diff -u --recursive --new-file v2.3.99-pre3/linux/CREDITS linux/CREDITS
--- v2.3.99-pre3/linux/CREDITS	Mon Mar 27 08:08:20 2000
+++ linux/CREDITS	Sun Apr  9 08:12:56 2000
@@ -1381,7 +1381,7 @@
 S: Czech Republic
 
 N: Bas Laarhoven
-E: bas@vimec.nl
+E: sjml@xs4all.nl
 D: Loadable modules and ftape driver
 S: J. Obrechtstr 23
 S: NL-5216 GP 's-Hertogenbosch
@@ -1526,9 +1526,10 @@
 D: Initial implementation of VC's, pty's and select()
 
 N: Pavel Machek
-E: pavel@atrey.karlin.mff.cuni.cz
-D: Softcursor for vga, hypertech cdrom support, vcsa bugfix
-D: Network block device, sun4/330 port 
+E: pavel@ucw.cz
+E: pavel@suse.cz
+D: Softcursor for vga, hypertech cdrom support, vcsa bugfix, nbd
+D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB
 S: Volkova 1131
 S: 198 00 Praha 9
 S: Czech Republic
@@ -1569,6 +1570,15 @@
 S: Santa Clara, CA 95052
 S: USA
 
+N: Petko Manolov
+E: petkan@spct.net
+D: USB ethernet (pegasus) driver
+D: optimizing i[45]86 string routines
+D: i386 task swithing hacks
+S: 5, Vrah Mancho str.
+S: 1324 Sofia
+S: Bulgaria
+
 N: Martin Mares
 E: mj@suse.cz
 E: mj@ucw.cz
@@ -2113,6 +2123,15 @@
 S: 301/222 City Walk
 S: Canberra ACT 2601
 S: Australia
+
+N: Bill Ryder
+E: bryder@sgi.com
+D: FTDI_SIO usb/serial converter driver
+W: http://reality.sgi.com/bryder_wellington/ftdi_sio
+S: I/3 Walter St
+S: Wellington
+S: New Zealand
+
 
 N: Sampo Saaristo
 E: sambo@cs.tut.fi
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.99-pre3/linux/Documentation/Configure.help	Mon Mar 27 08:08:20 2000
+++ linux/Documentation/Configure.help	Mon Apr 10 23:02:59 2000
@@ -59,7 +59,7 @@
 # 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-1999 by Axel Boldt and many others and are governed by the GNU
+# 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
@@ -112,18 +112,23 @@
   Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
   Management" code will be disabled if you say Y here.
 
-  See also: Documentation/SMP.txt, Documentation/smp.tex,
-  Documentation/smp.txt, and Documentation/IO-APIC.txt.  Also see the
+  See also the files Documentation/smp.tex, Documentation/smp.txt,
+  Documentation/IO-APIC.txt, Documentation/nmi_watchdog.txt and the 
   SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ .
   
   If you don't know what to do here, say N.
   
 APIC and IO-APIC Support on Uniprocessors
 CONFIG_X86_UP_IOAPIC
-  This option enables uniprocessor-kernels to switch into IO-APIC mode
-  if there is an IO-APIC in the system. Such a kernel will still boot
-  on IO-APIC-less systems with no slowdown at all. SMP kernels include
-  IO-APIC support unconditionally.
+  APIC (Advanced Programmable Interrupt Controller) is a scheme for
+  delivering hardware interrupt requests to the CPU. It is commonly
+  used on systems with several CPU's. If you have a single-CPU system
+  which uses APIC, you can say Y here to use it. If you say Y here
+  even though your machine doesn't have APIC, then the kernel will
+  still run with now slowdown at all.
+
+  If you have system with several CPU's, you do not need to say Y
+  here: APIC will be used automatically.
 
 Kernel math emulation
 CONFIG_MATH_EMULATION
@@ -140,10 +145,8 @@
   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. The lilo procedure is also explained in the SCSI-HOWTO,
-  available from http://www.linuxdoc.org/docs.html#howto .) This
-  means that it is a good idea to say Y here if you intend to use this
-  kernel on different machines.
+  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 arch/i386/math-emu/README.
@@ -187,9 +190,9 @@
   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).  This will result in the old "3GB/1GB"
-  virtual/physical memory split. 3BG are mapped so as each processus
+  virtual/physical memory split. 3GB are mapped so as each processus
   sees a 3GB virtual memory space.
-  The remaining part of the 4G virtual memory space is used by the
+  The remaining part of the 4GB virtual memory space is used by the
   kernel to 'permanently map' as much physical memory as possible.
   Certain types of applications perform better if there is more
   'permanently mapped' kernel memory.
@@ -277,7 +280,10 @@
 
   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.
+  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
@@ -289,13 +295,13 @@
   ftp://verden.pvv.org/pub/linux/kerneli/v2.1/ , 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
+  Note that alternative ways to use encrypted file systems are
+  provided by the cfs package, which can be gotten from
   ftp://ftp.replay.com/pub/crypto/disk/ , 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.
+  saying Y to "NFS file system support" below while using tcfs
+  requires applying a kernel patch.
 
   To use the loop device, you need the losetup utility and a recent
   version of the mount program, both contained in the util-linux
@@ -341,35 +347,39 @@
 
 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.
+  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 CDROM drives.
 
-  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 IDE interface.  State of the art disks use SCSI
-  interface.
+  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 Atachment (ATA) is a subset of the IDE specifications.
+  AT Attachment (ATA) is a subset 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/Ouput) from
-  previous ATA/IDE standards by means of fast DMA controlers.
-
-  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and CDROM
-  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
-  faillure conditions (heat, access time, and the like...). Disks builded 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.
+  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
+  CDROM 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),
@@ -385,15 +395,15 @@
   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. People with SCSI-only systems
-  can say N or M here.
+  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 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 .
+  detected, sound card ATA/IDE ports, module support, and other
+  topics, is contained in 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
@@ -403,7 +413,7 @@
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt and
   Documentation/ide.txt. The module will be called ide-mod.o. Do not
-  compile this driver as a module if your root filesystem (the one
+  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
@@ -428,8 +438,6 @@
   Disk-HOWTO, available from
   http://www.linuxdoc.org/docs.html#howto .
 
-  People with SCSI-only systems can say N here.
-
 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
@@ -446,9 +454,6 @@
   Normally, just say N here; you will then use the new driver for all
   4 interfaces.
 
-  People with SCSI-only systems don't need this and can say N here as
-  well.
-
 Include IDE/ATA-2 DISK support
 CONFIG_BLK_DEV_IDEDISK
   This will include enhanced support for MFM/RLL/IDE hard disks. If
@@ -505,8 +510,8 @@
   to the SCSI protocol. If you have an SCSI tape drive however, you
   can say N here.
 
-  This now includes the OnStream DI-30 tape drive support.
-  Will not work with SCSI protocol, until there is support for the
+  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
@@ -547,14 +552,17 @@
   and will allow you to use a SCSI device driver instead of a native
   ATAPI driver.
 
-  Must pass "hdx=scsi" per devices if you want the native EIDE sub-drivers
-  to skip over the native support.  This is required for use of CD-RW's.
-
   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.
+  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.
@@ -562,12 +570,10 @@
   If both this SCSI emulation and native ATAPI support are compiled
   into the kernel, the native support will be used.
 
-  People with SCSI-only systems can say N here. If unsure, say N.
-
 ISA-PNP EIDE support
 CONFIG_BLK_DEV_ISAPNP
-  If you have an ISA EIDE card that is PnP and requires setup first
-  before scanning for devices, say Y here.
+  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.
 
@@ -587,16 +593,12 @@
   (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 lilo procedure is also explained in
-  the SCSI-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto .)
+  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 Documentation/ide.txt. 
 
-  People with SCSI-only systems should say N here. If unsure, say Y.
-
 CMD640 enhanced support
 CONFIG_BLK_DEV_CMD640_ENHANCED
   This option includes support for setting/autotuning PIO modes and
@@ -615,16 +617,12 @@
   Linux. This may slow disk throughput by a few percent, but at least
   things will operate 100% reliably. 
 
-  People with SCSI-only systems should say N here. If unsure, say Y.
-
 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.
   
-  People with SCSI-only systems should say N here; if unsure say Y.
-
 Support for sharing PCI IDE interrupts
 CONFIG_IDEPCI_SHARE_IRQ
   Some ATA/IDE chipsets have hardware support which allows for
@@ -646,8 +644,8 @@
   the latest version of the hdparm utility from
   ftp://metalab.unc.edu/pub/Linux/system/hardware/ .
 
-  Read the comments at the beginning of drivers/ide/ide-dma.c and the
-  file Documentation/ide.txt for more information. 
+  Read the comments at the beginning of drivers/ide/ide-dma.c and
+  the file Documentation/ide.txt for more information.
 
   It is safe to say Y to this question.
 
@@ -671,16 +669,14 @@
   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
+  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. The lilo procedure is also
-  explained in the SCSI-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto .)
+  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.
@@ -693,7 +689,7 @@
   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 behavior, say Y to this question.
+  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!
@@ -703,8 +699,9 @@
 
 Various ATA, Work(s) In Progress (EXPERIMENTAL)
 CONFIG_IDEDMA_PCI_WIP
-  If you enable this you will be capable of using and testing
-  highly developmental projects.
+  If you enable this you will be able to use and test highly
+  developmental projects. If you say N, this configure script will
+  simply skip those options.
 
   It is SAFEST to say N to this question.
 
@@ -726,8 +723,9 @@
   should say Y here, and preferably also to "Use DMA by default when
   available".
 
-  Please read the comments at the top of drivers/ide/aec6210.c
-  If you say Y here, then say Y to "Use DMA by default when available" as well.
+  Please read the comments at the top of drivers/ide/aec6210.c If
+  you say Y here, then say Y to "Use DMA by default when available" as
+  well.
 
 AEC6210 Tuning support (WIP)
 CONFIG_AEC6210_TUNING
@@ -736,33 +734,37 @@
 
 ALI M15x3 chipset support
 CONFIG_BLK_DEV_ALI15X3
-  This driver ensures (U)DMA support for ALI 1543 and 1543C,
-  1535, 1535D onboard chipsets.  It also tests for Simplex mode and
-  enables normal dual channel support.
+  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 drivers/ide/alim15x3.c
-  If you say Y here, then say Y to "Use DMA by default when available" as well.
 
   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 CORUPTION, IF YOU ENABLE THIS!
-  No one will listen, just laugh for ignoring this SERIOUS WARNING.
+  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.
+  Using this option can allow WDC drives to run at ATA-4/5 transfer
+  rates with only an ATA-2 support structure.
 
   SAY NO!
 
 AMD7409 chipset support (EXPERIMENTAL)
 CONFIG_BLK_DEV_AMD7409
-  This driver ensures (U)DMA support for AMD756 Viper chipset.
+  This driver ensures (U)DMA support for the AMD756 Viper chipset.
 
+  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 drivers/ide/amd7409.c
-  If you say Y here, then say Y to "Use DMA by default when available" as well.
+
   If unsure, say N.
 
 AMD Viper ATA-66 Override support (WIP)
@@ -773,8 +775,8 @@
 
 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.
+  Say Y here if you have an IDE controller which uses any of these
+  chipsets: CMD643, CMD646, or CMD648.
 
 CMD64X chipset RAID support (WIP)
 CONFIG_CMD64X_RAID
@@ -786,7 +788,8 @@
   This driver adds detection and support for the CY82C693 chipset
   used on Digital's PC-Alpha 164SX boards.
 
-  If you say Y here, then say Y to "Use DMA by default when available" as well.
+  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
@@ -795,6 +798,8 @@
 
   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
@@ -806,38 +811,39 @@
 
 HPT34X AUTODMA support (WIP)
 CONFIG_HPT34X_AUTODMA
-  This is a dangerous thing to attempt currently!
-  Please read the comments at the top of drivers/ide/hpt34x.c
-  If you say Y here, then say Y to "Use DMA by default when available" as well.
+  This is a dangerous thing to attempt currently! Please read the
+  comments at the top of 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
-  This is an Ultra DMA chipset for ATA-66.
+  HPT366 is an Ultra DMA chipset for ATA-66.
   
   This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. The HPT366 chipset in its current form is a non-bootable,
-  without special LILO commands for redirecting the reference to device 0x80.
-  The other solution is to include "CONFIG_BLK_DEV_OFFBOARD" unless your
-  mainboard has the chipset native mounted.  Regardless one should use the
-  fore mentioned option and call at LILO or include in your append-line:
-  "ide=reverse".  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.
+  interrupt. 
 
-  Please read the comments at the top of drivers/ide/hpt366.c
-  If you say Y here, then say Y to "Use DMA by default when available" as well.
+  The HPT366 chipset in its current form is non-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.
 
 HPT366 Fast Interrupts (WIP)
 CONFIG_HPT366_FIP
-
   If unsure, say N.
 
-HPT366 mode three unsupported (WIP)
+HPT366 mode three unsupported (EXPERIMENTAL) (WIP)
 CONFIG_HPT366_MODE3
-  This is an undocumented mode that the HA366 can default to in many cases.
-  If unsure, say N.
+  This is an undocumented mode that the HA366 can default to in many
+  cases. If unsure, say N.
 
 NS87415 support (EXPERIMENTAL)
 CONFIG_BLK_DEV_NS87415
@@ -858,12 +864,14 @@
   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 drivers/ide/piix.c
+  Please read the comments at the top of drivers/ide/piix.c.
 
-  Should also include "PIIXn Tuning support" CONFIG_PIIX_TUNING
-  If unsure, say Y.
+  If you say Y here, you should also say Y to "PIIXn Tuning support",
+  below.
+
+  If unsure, say N.
 
-PIIXn Tuning support
+PIIXn Tuning support (EXPERIMENTAL)
 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
@@ -873,7 +881,7 @@
   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 Y.
+  If unsure, say N.
 
 PROMISE PDC20246/PDC20262 support
 CONFIG_BLK_DEV_PDC202XX
@@ -883,10 +891,10 @@
   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 (EXPERIMENTAL)".
+  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 (EXPERIMENTAL)".
 
   Promise Ultra66 or PDC20262
 
@@ -896,12 +904,14 @@
   boot-time for max-speed. Note tested limits are UDMA-2. Ultra66 BIOS
   1.11 or newer required.
 
-  If you say Y here, then say Y to "Use DMA by default when available" as well.
+  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 drivers/ide/pdc202xx.c
 
   If unsure, say N.
 
-Special UDMA Feature
+Special UDMA Feature (EXPERIMENTAL)
 CONFIG_PDC202XX_BURST
   For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally
   for PDC20246/Ultra33 that has BIOS setup failures when using 3 or
@@ -918,6 +928,17 @@
 
   Say N. 
 
+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 drivers/ide/sis5513.c
+ 
 Winbond SL82c105 support
 CONFIG_BLK_DEV_SL82C105
   If you have a Winbond SL82c105 IDE controller, say Y here to enable
@@ -933,16 +954,18 @@
 
 VIA82CXXX chipset support (EXPERIMENTAL)
 CONFIG_BLK_DEV_VIA82CXXX
-   This allows you to to configure your chipset for a better use while
-   running (U)DMA: it will allow you to enable efficiently the second
-   channel dma usage, as it is may not be set by BIOS. It allows you to
-   run a kernel command line at boot time in order to set fifo config.
-   If no command line is provided, it will try to set fifo configuration
-   at its best. It will allow you to get a proc/ide/via display
-  (while running a "cat") provided you enabled "proc" support.
+  This allows you to to configure your chipset for a better use while
+  running (U)DMA: it will allow you to enable efficiently the second
+  channel dma usage, as it may not be set by BIOS. It allows you to
+  pass a kernel command line at boot time in order to set fifo
+  config. If no command line is provided, 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" support.
+
   Please read the comments at the top of drivers/ide/via82cxxx.c
 
-  If you say Y here, then say Y to "Use DMA by default when available" as well.
+  If you say Y here, then say Y to "Use DMA by default when available"
+  as well.
 
   If unsure, say N.
 
@@ -1045,7 +1068,7 @@
 
 Amiga IDE Doubler support (EXPERIMENTAL)
 CONFIG_BLK_DEV_IDEDOUBLER
-  This driver provides support for the so called `IDE doublers' (made
+  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
@@ -1087,11 +1110,6 @@
   devices (hard disks, CD-ROM drives, etc.) that are connected to the
   builtin IDE interface.
 
-IDE card support
-CONFIG_BLK_DEV_IDE_CARDS
-  On Acorn systems, say Y here if you wish to use an IDE interface
-  expansion card. If you do not or are unsure, say N to this.
-
 ICS IDE interface support
 CONFIG_BLK_DEV_IDE_ICSIDE
   On Acorn systems, say Y here if you wish to use the ICS IDE
@@ -1100,7 +1118,8 @@
 
 ICS DMA support
 CONFIG_BLK_DEV_IDEDMA_ICS
-  No help for 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
@@ -1113,10 +1132,6 @@
   If you suspect your hardware is at all flakey, say N here.
   Do NOT email the IDE kernel people regarding this issue!
 
-RapIDE interface support
-CONFIG_BLK_DEV_IDE_RAPIDE
-  No help for CONFIG_BLK_DEV_IDE_RAPIDE
-
 XT hard disk support
 CONFIG_BLK_DEV_XD
   Very old 8 bit hard disk controllers used in the IBM XT computer
@@ -1133,7 +1148,7 @@
 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 Documentation/modules.txt. The module will be
@@ -1157,7 +1172,7 @@
   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 linux/Documentation/paride.txt for more information.
+  Read 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
@@ -1199,8 +1214,8 @@
   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 CDROM file system support" below, because that's the file system
-  used on CDROMs.
+  9660 CDROM file system support" below, because that's the file
+  system used on CDROMs.
 
 Parallel port ATAPI disks
 CONFIG_PARIDE_PF
@@ -1241,7 +1256,7 @@
   your system.
 
   This driver implements an API loosely related to the generic SCSI
-  driver. See /usr/include/linux/pg.h for details.
+  driver. See include/linux/pg.h for details.
 
   You can obtain the most recent version of cdrecord from
   ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ . Versions 1.6.1a3 and
@@ -1401,9 +1416,13 @@
   to new capacity needs.  Logical volumes are accessed as block
   devices named /dev/VolumeGroupName/LogicalVolumeName.
 
-  For details see /usr/src/linux/Documentaion/LVM-HOWTO.
+  For details see Documentation/LVM-HOWTO. You will need supporting
+  user space software from http://linux.msede.com/lvm .
 
-  To get the newest software see <http://linux.msede.com/lvm>.
+  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 Documentation/modules.txt. The module
+  will be called lvm-mod.o.
 
 Logical Volume Manager /proc file system information
 CONFIG_LVM_PROC_FS
@@ -1517,37 +1536,30 @@
   answer Y here. For lilo and loadlin options see the file
   Documentation/md.txt.
 
-Support for Deskstation RPC44 
-CONFIG_DESKSTATION_RPC44
-  This is a machine with a R4400 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 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.
+  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.
+  this board see http://www.algor.co.uk .
 
 Support for BAGET MIPS series
 CONFIG_BAGET_MIPS
   This enables support for the Baget, a Russian embedded system.  For 
   more details about the Baget see the Linux/MIPS FAQ on 
-  http://oss.sgi.com/mips.
+  http://oss.sgi.com/mips .
 
 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. the 
-  DECstation porting pages on http://decstation.unix-ag.org.
+  see the Linux/MIPS FAQ on http://oss.sgi.com/mips and the 
+  DECstation porting pages on http://decstation.unix-ag.org .
 
   If you have one of the following DECstation Models you definitely
   want to choose R4xx0 for the CPU Type:
@@ -1561,26 +1573,8 @@
 
 Support for NEC DDB Vrc-5074
 CONFIG_DDB5074
-  This enables support for the VR5000-based NEC DDB Vrc-5074 evaluation
-  board.
-
-IDE card support
-CONFIG_BLK_DEV_IDE_CARDS
-  On Acorn systems, say Y here if you wish to use an IDE interface
-  expansion card. If you do not or are unsure, say N to this.
-
-ICS IDE interface
-CONFIG_BLK_DEV_IDE_ICS
-  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.
-
-ADFS partition support
-CONFIG_BLK_DEV_PART
-  This allows Linux on Acorn systems to determine its partitions in
-  the 'non-ADFS' partition area of the hard disk - usually located
-  after the ADFS partition.  You are probably using this system, so
-  you should say Y it.
+  This enables support for the VR5000-based NEC DDB Vrc-5074
+  evaluation board.
 
 Support for Mips Magnum 4000
 CONFIG_MIPS_MAGNUM_4000
@@ -1598,9 +1592,9 @@
 
 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.
+  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
   This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics
@@ -1611,7 +1605,7 @@
 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 more memory.  Your system is most probly
+  which allows for more more memory.  Your system is most probably
   running in M-Mode, so you should say N here.
 
 MIPS JAZZ onboard SONIC Ethernet support
@@ -1621,26 +1615,26 @@
 
 MIPS JAZZ FAS216 SCSI support
 CONFIG_JAZZ_ESP
-  This is the driver for the onboard SCSI hostadapter of MIPS Magnum 4000,
-  Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
+  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.
 
 CPU type
 CONFIG_CPU_R3000
-  Please make shure to pick the right CPU type. Linux/MIPS is not
+  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 the supported Machines have an R4000 (or similar)
-  CPU R4xx0 might be a safe bet.
+  However, since most the supported Machines have an R4000 (or 
+  similar) CPU, R4xx0 might be a safe bet.
   If the resulting Kernel does not work try to recompile with R3000.
 
 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 did only support 40 bit / 1TB.  If
-  you need processes of more than 1TB virtual address space activate this.
-  Activating CONFIG_MIPS_INSANE_LARGE results in additional memory usage,
-  so only activate this if you really need.  Very few people will need
-  this.
+  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
@@ -1648,11 +1642,6 @@
   byte order. These modes require different kernels. Say Y if your
   machine is little endian, N if it's a big endian machine.
 
-Kernel support for IRIX binaries
-CONFIG_BINFMT_IRIX
-  If you say Y here, the kernel will support running of IRIX binaries.
-  You will need IRIX libraries for this to work.
-
 Networking support
 CONFIG_NET
   Unless you really know what you are doing, you should say Y here.
@@ -1675,7 +1664,7 @@
   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 linux/Documentation/networking/filter.txt for more information.
+  file Documentation/networking/filter.txt for more information.
   If unsure, say N.
 
 Network packet filtering
@@ -1710,7 +1699,7 @@
   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 port-forwarding. Masquerading is also often
+  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
@@ -1720,7 +1709,7 @@
 
   Various modules exist for netfilter which replace the previous
   masquerading (ipmasqadm), packet filtering (ipchains), transparent
-  proxying, and port-forwarding mechanisms. More information is
+  proxying, and portforwarding mechanisms. More information is
   available from http://netfilter.kernelnotes.org .
  
   Make sure to say N to "Fast switching" below if you intend to say Y
@@ -1729,6 +1718,11 @@
   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. 
+
 IP: connection tracking (required for masq/NAT)
 CONFIG_IP_NF_CONNTRACK
   Connection tracking keeps a record of what packets have passed
@@ -1773,7 +1767,8 @@
 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.
+  matched: mainly useful in combination with the LOG target ("LOG
+  target support", below).
 
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
@@ -1831,7 +1826,6 @@
 
 Owner match support (EXPERIMENTAL)
 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.
 
@@ -1889,7 +1883,7 @@
   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 tranparent proxies.
+  useful for transparent proxies.
 
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
@@ -1914,11 +1908,12 @@
 
 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 packet prior to routing.  This can change
-  the routing method (see `IP: use netfilter MARK value as routing key')
-  and can also be used by other subsystems to change their behavior.
+  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 `IP: 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
   Documentation/modules.txt.  If unsure, say `N'.
@@ -1989,11 +1984,6 @@
   
   If unsure, say Y.
 
-Sun floppy controller support
-CONFIG_BLK_DEV_SUNFD
-  This is support for floppy drives on Sun SPARC workstations. Say Y
-  if you have a floppy drive, otherwise N. Easy.
-
 Alpha system type
 CONFIG_ALPHA_GENERIC
   This is the system type of your hardware.  A "generic" kernel will
@@ -2060,12 +2050,6 @@
 
   If unsure, say N.
 
-Use SRM PCI setup
-CONFIG_ALPHA_SRM_SETUP
-  This option controls whether or not the PCI configuration set up by
-  SRM is modified.  If you say Y, the existing PCI configuration will
-  be left intact.
-
 Non-standard serial port support
 CONFIG_SERIAL_NONSTANDARD
   Say Y here if you have any non-standard serial boards -- boards
@@ -2128,7 +2112,7 @@
 
 SGI PROM Console Support
 CONFIG_SGI_PROM_CONSOLE
-  Enable this if you want to use the PROMs for console I/O.
+  Say Y here if you want to use the PROMs for console I/O.
 
 SGI Zilog85C30 serial support
 CONFIG_SGI_SERIAL
@@ -2144,7 +2128,7 @@
 
 SGI Newport Console support
 CONFIG_SGI_NEWPORT_CONSOLE
-  Enable this if you want the console on the Newport aka XL graphics
+  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
@@ -2152,51 +2136,131 @@
   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 
+  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.
 
-SGI Vino Video For Linux (EXPERIMENTAL)
-CONFIG_SGI_VIDEO_VINO
-  Support for the SGI Vino Video hardware which is part of the Newport
-  aka XL graphics card.  Most people will say N here.
-
 Support the Bell Technologies HUB6 card
 CONFIG_HUB6
   Say Y here to enable support in the dumb serial driver to support
   the HUB6 card.
 
-Support for hot-pluggable devices
-CONFIG_HOTPLUG
-  Say Y here to enable support for hot plugin of certain hardware such as
-  PCMCIA cards and the like.
-
-  At this moment, few drivers support it, but as they get converted to use the
-  new ressource allocator/manager, their number will increase.
-
 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
-  multifunction ethernet/modem cards.
+  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 Documentation/modules.txt. If unsure,
+  The module will be called serial_cs.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
 CardBus serial device support
 CONFIG_PCMCIA_SERIAL_CB
   Say Y here to enable support for CardBus serial devices, including
-  the modem functions of multifunction ethernet/modem devices.
+  serial port cards, modems, and the modem functions of multi-function
+  ethernet/modem devices. (CardBus cards are the newer and better 
+  version of PCMCIA- or PC-cards: 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_cb.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt. If unsure,
+  The module will be called serial_cb.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
+/dev/agpgart (AGP Support) (EXPERIMENTAL)
+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. The glx
+  module will then be able to program the GART (graphics aperture
+  relocation table) registers with appropriate values to transfer
+  commands to the card.
+
+  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.
+
+  For the moment, you should probably say N, unless you want to test
+  the GLX component for XFree86 3.3.6, which can be downloaded from
+  http://utah-glx.sourceforge.net/ , or need to use the 810 Xserver in
+  XFree 3.3.6.
+
+  This driver is available as a module. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. The module
+  will be called agpgart.o.
+
+Intel 440LX/BX/GX support
+CONFIG_AGP_INTEL
+  This option gives you AGP support for the GLX component of the
+  "soon to be released" XFree86 4.x on Intel 440LX/BX/GX chipsets.
+
+  For the moment, you should probably say N, unless you want to test
+  the GLX component for XFree86 3.3.6, which can be downloaded from
+  http://utah-glx.sourceforge.net/ .
+
+Intel I810/I810 DC100/I810e support
+CONFIG_AGP_I810
+  This option gives you AGP support for the Xserver for the Intel
+  810 chipset boards. This is required to do any useful video
+  modes.
+
+VIA chipset support
+CONFIG_AGP_VIA
+  This option gives you AGP support for the GLX component of the
+  "soon to be released" XFree86 4.x on VIA MPV3/Apollo Pro chipsets.
+
+  For the moment, you should probably say N, unless you want to test
+  the GLX component for XFree86 3.3.6, which can be downloaded from
+  http://utah-glx.sourceforge.net/ .
+
+AMD Irongate support
+CONFIG_AGP_AMD
+  This option gives you AGP support for the GLX component of the
+  "soon to be released" XFree86 4.x on Intel AMD Irongate chipset.
+
+  For the moment, you should probably say N, unless you want to test
+  the GLX component for XFree86 3.3.6, which can be downloaded from
+  http://utah-glx.sourceforge.net/ .
+
+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.
+
+  For the moment, you should probably say N, unless you want to test
+  the GLX component for XFree86 3.3.6, which can be downloaded from
+  http://utah-glx.sourceforge.net/ .
+
+ALI M1541 support
+CONFIG_AGP_ALI
+  This option gives you AGP support for the GLX component of the
+  "soon to be released" XFree86 4.x on the ALi M1541 chipset.
+
+  This 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.
+
+  For the moment, you should probably say N, unless you want to test
+  the GLX component for XFree86 3.3.6, which can be downloaded from
+  http://utah-glx.sourceforge.net/ .
+
 PCI support
 CONFIG_PCI
   Find out whether you have a PCI motherboard. PCI is the name of a
@@ -2221,16 +2285,17 @@
   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.
+  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
+  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.
 
@@ -2343,8 +2408,9 @@
 
   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 configure your PnP devices using the
-  user space utilities contained in the isapnptools package.
+  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).
@@ -2354,7 +2420,8 @@
 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 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
@@ -2362,13 +2429,27 @@
 
   If unsure, say Y.
 
-PCMCIA/CardBus support
+Support for hot-pluggable devices
+CONFIG_HOTPLUG
+  Say Y here if you want to attach devices to your computer that can
+  be attached and detached while the system is running. The most
+  prominent example of this are 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.
+
+PCMCIA/Cardbus support
 CONFIG_PCMCIA
-  Include kernel support for PCMCIA and CardBus devices.  Because
-  PCMCIA support requires additional components that are not part of
-  the kernel (i.e., the pcmcia-cs package), building PCMCIA into the
-  kernel is generally not recommended unless you have a specific
-  need.  If unsure, say N.
+  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 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).
@@ -2376,27 +2457,32 @@
   and ds.o.  If you want to compile it as a module, say M here and
   read Documentation/modules.txt.
 
-  You will also need David Hinds' pcmcia-cs package (see the file
-  Documentation/Changes for location).  For more information, see the
-  PCMCIA-HOWTO.
-
 CardBus support
 CONFIG_CARDBUS
-  There are two types of PCMCIA devices: 16-bit PC Cards, and higher
-  performance 32-bit CardBus devices.  Use this option to include
-  support for CardBus devices.  If unsure, say Y.
+  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.
+
+  To use your PC-cards, you will need supporting software from David 
+  Hinds' pcmcia-cs package (see the file Documentation/Changes for 
+  location).
+
+  If unsure, say Y.
 
 i82365/Yenta compatible bridge support
 CONFIG_I82365
-  Include support for PCMCIA and CardBus host bridges that are
-  register compatible with the Intel i82365 and/or the Yenta
+  Say Y here to include support for PCMCIA and CardBus host bridges
+  that are register compatible with the Intel i82365 and/or the Yenta
   specification: this includes virtually all modern PCMCIA bridges.
-  If unsure, say Y.
+  "Bridge" is the name used for the hardware inside your computer that
+  PCMCIA cards are plugged into. If unsure, say Y.
 
 Databook TCIC host bridge support
 CONFIG_TCIC
-  Include support for the Databook TCIC family of PCMCIA host bridges.
-  These are only found on a handful of old systems.  If unsure, say N.
+  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
@@ -2414,9 +2500,9 @@
   http://www.linuxdoc.org/docs.html#guide .
 
   Shared memory is now implemented using a new (minimal) virtual file
-  system, which you need to mount before programs can use shared memory. 
-  To do this automatically at system startup just add the following line 
-  to your /etc/fstab:
+  system, which you need to mount before programs can use shared
+  memory. To do this automatically at system startup just add the
+  following line to your /etc/fstab:
 
   none	/var/shm	shm	defaults	0 0
 
@@ -2451,21 +2537,24 @@
 
 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:
+  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
 
-  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
+  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 "-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.
-  
+  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.
+
 Kernel support for ELF binaries
 CONFIG_BINFMT_ELF
   ELF (Executable and Linkable Format) is a format for libraries and
@@ -2569,10 +2658,10 @@
   all x86 CPU types (albeit not optimally fast), you can specify
   "386" here.
 
-  If you specify one of "486" or "586" or "Pentium" or "PPro", then
-  the kernel will not necessarily run on earlier architectures (e.g. a
-  Pentium optimized kernel will run on a PPro, but not necessarily on
-  a i486).
+  If you specify one of "486" or "586" or "Pentium" or "PPro" or
+  "Athlon", then the kernel will not necessarily run on earlier
+  architectures (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
@@ -2583,11 +2672,11 @@
      UMC U5D or U5S.
    - "586" for generic Pentium CPUs, possibly lacking the TSC 
      (time stamp counter) register.
-   - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5.
+   - "Pentium" for the Intel Pentium/Pentium MMX, and AMD K5.
    - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and
-     Intel Pentium II/Pentium Pro.
+     Intel Pentium Pro/Celeron/Pentium II/Pentium III.
    - "K6/II/III" for the AMD K6, K6-II and K6-III (aka K6-3D).
-   - "Athlon" for the AMD Athlon (aka K7)
+   - "Athlon" for the AMD Athlon (K7).
 
   If you don't know what to do, choose "386".
 
@@ -2612,9 +2701,7 @@
   "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. The lilo procedure is also
-  explained in the SCSI-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto .)
+  how to pass options to the kernel.)
 
   Read the file Documentation/svga.txt for more information about the
   Video mode selection support. If unsure, say N.
@@ -2658,11 +2745,6 @@
   hardware found in Acorn RISC PCs and other ARM-based machines.  If
   unsure, say N.
 
-Apollo frame buffer device
-CONFIG_FB_APOLLO
-  This is the frame buffer device driver for the monochrome graphics
-  hardware found in some Apollo workstations.
-
 Amiga native chipset support
 CONFIG_FB_AMIGA
   This is the frame buffer device driver for the builtin graphics
@@ -2769,8 +2851,8 @@
 
 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)
 CONFIG_FB_3DFX
-  This driver supports graphics boards with the 3Dfx Banshee/Voodoo3 chips.
-  Say Y if you have such a graphics board.
+  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
@@ -2797,17 +2879,18 @@
   inserted and removed from the running kernel whenever you want). The
   module will be called atyfb.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
-
+  
 ATI Rage128 display support (EXPERIMENTAL)
 CONFIG_FB_ATY128
   This driver supports graphics boards with the ATI Rage128 chips.
-  Say Y if you have such a graphics board.
+  Say Y if you have such a graphics board and read
+  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 Documentation/modules.txt.
-  
+
 PowerMac "control" frame buffer device support
 CONFIG_FB_CONTROL
   This driver supports a frame buffer for the graphics adapter in the
@@ -2828,16 +2911,6 @@
   This is the frame buffer device driver for the Chips & Technologies
   65550 graphics chip in PowerBooks.
 
-Mac frame buffer device
-CONFIG_FB_MAC
-  This is the frame buffer device driver for the graphics hardware in
-  m68k Macintoshes.
-
-HP300 frame buffer device
-CONFIG_FB_HP300
-  This is the frame buffer device driver for the Topcat graphics
-  hardware found in HP300 workstations.
-
 TGA frame buffer support
 CONFIG_FB_TGA
   This is the frame buffer device driver for generic TGA graphic
@@ -2853,10 +2926,11 @@
 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 plans.
-  Only answer Y here if you have an (very old) VGA card that isn't
-  VESA 2 compatible.
+  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
@@ -2870,12 +2944,12 @@
 
 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.
+  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 this configure script to skip all the questions
-  about foreign fonts.
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause this configure script to skip all
+  the questions about foreign fonts.
 
   If unsure, say N (the default choices are safe).
 
@@ -2895,22 +2969,21 @@
 
 Sparc console 8x16 font
 CONFIG_FONT_SUN8x16
-  This is the high resolution console font for Sun machines.
-
-  Say Y.
+  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.
+  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 this is a poor quality font. The VGA 8x16 font is quite a lot
-  more readable.
+  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.
@@ -2923,7 +2996,6 @@
   (XF68_FBDev).
 
 HGA monochrome support (EXPERIMENTAL)
-Hercules mono graphics console (EXPERIMENTAL)
 CONFIG_FBCON_HGA
   Say Y here if you have a Hercules mono graphics card.
 
@@ -2932,11 +3004,12 @@
   The module will be called hgafb.o. If you want to compile it as
   a module, say M here and read Documentation/modules.txt.
 
-  As this card technology is 15 years old, most people will answer N here.
+  As this card technology is 15 years old, most people will answer N
+  here.
 
 Matrox unified accelerated driver (EXPERIMENTAL)
 CONFIG_FB_MATROX
-  Say Y here if you have Matrox Millennium, Matrox Millennium II,
+  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 or
   Matrox G400 card in your box. At this time, support for the G100,
@@ -2976,49 +3049,51 @@
   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 enable
-  I2C support and I2C bit-banging support in character devices section,
-  and then Matrox I2C support and G400 secondary head support here
-  in framebuffer section.
+
+  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
-  DDC (I2C) bus present on all Matroxes, I2C bus which interconnects
-  Matrox optional devices, like MGA-TVO on G200 and G400, and
-  secondary head DDC bus, present on G400 only.
+  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 module named i2c-matroxfb.o.
+  If you compile it as module, it will create a module named
+  i2c-matroxfb.o.
   
 Matrox G400 second head support
 CONFIG_FB_MATROX_MAVEN
-  Say Y or M here if you want to use secondary head 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 fbdev driver on first head and 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.
-  
-  Driver starts in monitor mode and you must use 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 good idea to compile them into kernel too. You can
-  use only some font widths, as driver uses generic painting procedures
-  (secondary head does not use acceleration engine).
+  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).
   
   There is no need for enabling 'Matrox multihead support' if you have
   only one Matrox card in the box.
@@ -3026,16 +3101,17 @@
 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. 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). 
+  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.
-  This is slightly faster but uses 40 KB of kernel memory per Matrox
-  card. You do this by inserting 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.
+  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.
 
 MDA text console (dual-headed)
 CONFIG_MDA_CONSOLE
@@ -3188,12 +3264,6 @@
   bits per pixel packed pixels on Mac. It supports variable font
   widths for low resolution screens.
   
-#VGA 16-color planar support
-#CONFIG_FBCON_VGA_PLANES
-###
-###What is this?
-###
-
 VGA characters/attributes support
 CONFIG_FBCON_VGA
   This is the low level frame buffer console driver for VGA text mode;
@@ -3266,17 +3336,11 @@
   other non-standard types of parallel ports. This causes a
   performance loss, so most people say N.
 
-Sun Ultra/AX-style hardware
-CONFIG_PARPORT_AX
-  Say Y here if you need support for the parallel port hardware on Sun
-  Ultra/AX machines. This code is also available as a module (say M),
-  called parport_ax.o. If in doubt, saying N is the safe plan.
-
 Support IEEE1284 status readback
 CONFIG_PRINTER_READBACK
-  If you have a device on your parallel port that support this protocol,
-  this option'll enable it to report its status.
-  It is safe to say Y.
+  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.
 
 IEEE1284 transfer modes
 CONFIG_PARPORT_1284
@@ -3366,9 +3430,9 @@
   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
+  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
   Documentation/Networking/ip-sysctl.txt.
 
@@ -3377,7 +3441,7 @@
 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
+  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
@@ -3502,8 +3566,8 @@
 
     echo "1" > /proc/sys/net/ipv4/ip_forward
 
-  at boot time after the /proc file system has been mounted. You can do
-  that even if you say N here.
+  at boot time after the /proc file system has been mounted. You can
+  do that even if you say N here.
 
   If unsure, say N here.
 
@@ -3511,7 +3575,7 @@
 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 at the kernel command line or by BOOTP or RARP protocols.
+  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
@@ -3633,16 +3697,7 @@
   saying Y here. Everyone else says N. 
 
   People having problems with NCSA telnet should see the file
-  linux/Documentation/networking/ncsa-telnet.
-
-Assume subnets are local
-CONFIG_INET_SNARL
-  Say Y if you are on a subnetted network with all machines connected
-  by Ethernet segments only, as this option optimizes network access
-  for this special case. If there are other connections, e.g. SLIP
-  links, between machines of your IP network, say N. If in doubt,
-  answer N. The PATH mtu discovery facility will cover most cases
-  anyway.
+  Documentation/networking/ncsa-telnet.
 
 Path MTU Discovery (normally enabled)
 CONFIG_PATH_MTU_DISCOVERY
@@ -3751,6 +3806,20 @@
   say Y to "Kernel/User network link driver" and to "Routing
   messages" instead.
   
+Kernel httpd acceleration (EXPERIMENTAL)
+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. 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.
+
 IPX networking
 CONFIG_IPX
   This is support for the Novell networking protocol, IPX, commonly
@@ -3760,7 +3829,7 @@
   ftp://metalab.unc.edu/pub/Linux/system/filesystems/ ) 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 systems support",
+  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,
@@ -3819,7 +3888,7 @@
 
   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 systems support" below for the client side, and the user
+  ("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
@@ -3844,7 +3913,7 @@
   More detailed documentation is available in the
   Documentation/networking/decnet.txt file.
 
-  Be sure to say Y to "/proc file systems support" and "Sysctl support"
+  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.
 
@@ -3865,22 +3934,28 @@
 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
-   turn it on, then make sure that you also say Y to "Kernel/User
-   network link driver", "Routing messages" and "Network packet 
+   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.inr.ac.ru). The "Network packet filtering" option will
-   be required for the forthcoming routing daemon to work.
+   from ftp://ftp.inr.ac.ru). The "Network packet filtering" option
+   will be required for the forthcoming routing daemon to work.
 
    See Documentation/networking/decnet.txt for more information.
 
+DECnet: use FWMARK value as 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 DDP
+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
@@ -3894,7 +3969,7 @@
   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
+  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.
@@ -4401,17 +4476,23 @@
   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.1d spanning tree protocol.
-  As this is a standard, Linux bridges will interwork properly with
+  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 available from ftp://openrock.net/bridge. 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 .
+  configuration tools; see 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 Documentation/modules.txt. The module will be
+  called bridge.o.
 
   If unsure, say N.
 
@@ -4491,16 +4572,17 @@
 Classical IP over ATM
 CONFIG_ATM_CLIP
   Classical IP over ATM for PVCs and SVCs, supporting InARP and
-  ATMARP. Typically you will either use LAN Emulation (LANE) or
-  Classical IP to communicate with other IP hosts on your ATM network.
+  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 neighbor
+Do NOT send ICMP if no neighbour
 CONFIG_ATM_CLIP_NO_ICMP
-  Normally, an "ICMP host unreachable" message is sent if a neighbor
+  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 neighbors are silently discarded instead.
+  such neighbours are silently discarded instead.
 
 LAN Emulation (LANE) support
 CONFIG_ATM_LANE
@@ -4524,12 +4606,16 @@
 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
+  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 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
@@ -4610,6 +4696,10 @@
   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 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
@@ -4632,7 +4722,11 @@
 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.
+  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 Documentation/modules.txt. The
+  module will be called nicstar.o.
 
 ForeRunner LE155 PHYsical layer
 CONFIG_ATM_NICSTAR_USE_SUNI
@@ -4717,6 +4811,35 @@
   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 Documentation/modules.txt. The
+  module will be called phonedev.o.
+
+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 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
   This is a driver for the FORE Systems 200E-series ATM adapter
@@ -4729,14 +4852,14 @@
  
 Enable PCA-200E card support on PCI-based hosts
 CONFIG_ATM_FORE200E_PCA
-  Enable this if you want your PCA-200E cards to be probed.
+  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
-  this feature is normally enabled.
+  they should say Y here.
  
 Pathname of user-supplied binary firmware
 CONFIG_ATM_FORE200E_PCA_FW
@@ -4744,20 +4867,20 @@
   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 enable the use
-  of the default firmware instead.
+  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
-  Enable this if you want your SBA-200E cards to be probed.
+  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
-  this feature is normally enabled.
+  they should say Y here.
  
 Pathname of user-supplied binary firmware
 CONFIG_ATM_FORE200E_SBA_FW
@@ -4765,9 +4888,9 @@
   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 enable the use
-  of the default firmware instead.
+  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
@@ -4815,8 +4938,8 @@
   The module will be called scsi_mod.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt and
   Documentation/scsi.txt. However, do not compile this as a module if
-  your root file systems (the one containing the directory /) is located
-  on a SCSI device.
+  your root file system (the one containing the directory /) is
+  located on a SCSI device.
 
 SCSI disk support
 CONFIG_BLK_DEV_SD
@@ -4831,15 +4954,15 @@
   The module will be called sd_mod.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt and
   Documentation/scsi.txt. Do not compile this driver as a module if
-  your root file systems (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.
+  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.
 
 Extra SCSI Disks
 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 this
+  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.
 
@@ -4847,6 +4970,8 @@
   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
@@ -4866,7 +4991,7 @@
   If you want to use a SCSI CDROM under Linux, say Y and read the
   SCSI-HOWTO and the CDROM-HOWTO at
   http://www.linuxdoc.org/docs.html#howto . Also make sure to say Y
-  or M to "ISO 9660 CDROM file systems support" later.
+  or M to "ISO 9660 CDROM 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).
@@ -4877,15 +5002,17 @@
 Extra SCSI CDROMs
 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 this value
-  is the number of additional CDROMs that can be loaded after the first
-  host driver is loaded.
+  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 CDROMs 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 CDROM)
 CONFIG_BLK_DEV_SR_VENDOR
   This enables the usage of vendor specific SCSI commands. This is
@@ -4899,14 +5026,15 @@
   about anything having "SCSI" in its name other than hard disks,
   CDROMs 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 CD-writers, you
-  would need the program cdwrite, available from
-  ftp://metalab.unc.edu/pub/Linux/utils/disk-management ; for other
-  devices, it's possible that you'll have to write the driver software
-  yourself, so have a look at the SCSI-HOWTO and at the
-  SCSI-Programming-HOWTO, both available from
-  http://www.linuxdoc.org/docs.html#howto . Please read the file
-  Documentation/scsi-generic.txt for more information.
+  talk to these devices using the SCSI protocol. For scanners, look at
+  SANE (www.mostang.com/sane). For CD writer software look at cdrecord
+  (www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private
+  /cdrecord.html) and for burning a "disk at once": cdrdao
+  (www.ping.de/sites/daneb/cdrdao.html). Cdparanoia is a high quality
+  digital reader of audio CDs (www.xiph.org/paranoia).
+  For other devices, it's possible that you'll have to write the driver
+  software yourself. Please read the 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),
@@ -4916,13 +5044,14 @@
 
 Debug new queueing code for SCSI
 CONFIG_SCSI_DEBUG_QUEUES
-  This option turns on a lot of additional consistency checking for the new
-  queueing code.   This will adversely affect performance, but it is likely
-  that bugs will be caught sooner if this is turned on.   This will typically
-  cause the kernel to panic if an error is detected, but it would have probably
-  crashed if the panic weren't there.   Comments/questions/problems to
-  linux-scsi mailing list please.  See http://www.andante.org/scsi_queue.html
-  for more uptodate information.
+  This option turns on a lot of additional consistency checking for
+  the new queueing code. This will adversely affect performance, but
+  it is likely that bugs will be caught sooner if this is turned on.
+  This will typically cause the kernel to panic if an error is
+  detected, but it would have probably crashed if the panic weren't
+  there. Comments/questions/problems to linux-scsi mailing list
+  please. See http://www.andante.org/scsi_queue.html for more
+  up-to-date information.
 
 Probe all LUNs on each SCSI device
 CONFIG_SCSI_MULTI_LUN
@@ -4946,12 +5075,12 @@
   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 systems support" and
+  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 systems has been mounted.
+  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: drivers/scsi/scsi.c), and this allows you
@@ -4982,7 +5111,7 @@
 
   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 comments at the top of drivers/scsi/aha152x.c.
+  read the 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).
@@ -5129,18 +5258,22 @@
   after a bus reset to be ready for the next command, but most hard
   drives and CD-ROM devices are ready in only a few seconds. This
   option has a maximum upper limit of 20 seconds to avoid bad
-  interactions between the aic7xxx driver and the rest of the linux
+  interactions between the aic7xxx driver and the rest of the Linux
   kernel. The default value has been reduced to 5 seconds. If this
   doesn't work with your hardware, try increasing this value.
 
 IBM ServeRAID Support
 CONFIG_SCSI_IPS
   This is support for the IBM ServeRAID hardware RAID controllers.
-  Consult the SCSI-HOWTO, available via anonymous FTP from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, and the file
-  README.ips in drivers/scsi for more information.  If this driver
-  does not work correctly without modification please contact the
-  author by email at ipslinux@us.ibm.com.
+  
+  Please consult the SCSI-HOWTO, available from
+  http://www.linuxdoc.org/docs.html#howto . 
+
+  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 Documentation/modules.txt. The
+  module will be called ips.o.
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
@@ -5165,6 +5298,15 @@
   substantial, so users of MultiMaster Host Adapters may wish to omit
   it.
 
+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 Documentation/modules.txt.
+
 DTC3180/3280 SCSI support
 CONFIG_SCSI_DTC3280
   This is support for DTC 3180/3280 SCSI Host Adapters. Please read
@@ -5528,9 +5670,7 @@
   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. The lilo procedure is also explained in
-  the SCSI-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto .
+  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),
@@ -5857,13 +5997,32 @@
   read 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
+  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 Documentation/modules.txt. The module will be
+  called sim710.o.
+
 Tekram DC390(T) and Am53/79C974 (PCscsi) 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 linux/drivers/scsi/README.tmscsim.
+  Documentation can be found in 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.
@@ -5881,7 +6040,7 @@
   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 linux/drivers/scsi/README.tmscsim.
+  configuration see 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
@@ -6015,21 +6174,28 @@
   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 support
+Fibre Channel support and FC4 SCSI support
 CONFIG_FC4
-  This is an experimental support for storage arrays connected to
-  the system using Fibre Optic and the "X3.269-199X Fibre Channel
-  Protocol for SCSI" specification. You'll also need the generic SCSI
-  support, as well as 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.
+  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
 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.
+  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
@@ -6038,11 +6204,11 @@
 
 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.
+  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
@@ -6060,9 +6226,9 @@
 
 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
+  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
@@ -6123,55 +6289,125 @@
   This enables support for the Powertec SCSI card on Acorn systems. If
   you have one of these, say Y. If unsure, say 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 ).
+IEEE 1394 (aka 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.
 
-  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).
+  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.
 
-  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 ftp://metalab.unc.edu/pub/Linux/docs/LDP . 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 Documentation/modules.txt. The module will be
+  called ieee1394.o.
 
-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.
+TI PCILynx IEEE 1394 support
+CONFIG_IEEE1394_PCILYNX
+  Say Y here if you have a 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 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.
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called 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.
 
-  This is similar to the EQL driver, but it merge ethernet segments instead
-  of serial lines.
+  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 Documentation/modules.txt. The module will be
-  called bonding.o.
+  called aic5800.o.
+
+OHCI (Open Host Controller Interface) support
+CONFIG_IEEE1394_OHCI1394
+  Say Y here if you have a IEEE 1394 controller based on OHCI.
+  The current driver was only tested with OHCI chipsets made
+  by Texas Instruments. However, most third-party vendors use
+  TI chips.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called ohci1394.o.
+
+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 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
@@ -6183,7 +6419,7 @@
   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://metalab.unc.edu/mdw/linux.html#guide .
+  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),
@@ -6192,6 +6428,26 @@
   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 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
@@ -6231,11 +6487,11 @@
   on both ends. Ask your access provider if you are not sure and
   answer Y, just in case. You will still be able to use plain SLIP. If
   you plan to use SLiRP, the SLIP emulator (available from
-  ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which allows
-  you to use SLIP over a regular dial up shell connection, you
+  ftp://metalab.unc.edu/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.
+  http://www.linuxdoc.org/docs.html#howto , explains how to configure
+  CSLIP. This won't enlarge your kernel.
 
 Keepalive and linefill
 CONFIG_SLIP_SMART
@@ -6296,6 +6552,7 @@
   into and removed from the running kernel).  If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+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
@@ -6338,10 +6595,20 @@
 Wireless LAN (non-hamradio)
 CONFIG_NET_RADIO
   Support for wireless LANs and everything having to do with radio,
-  but not with amateur radio. Note that the answer to this question
-  won't directly affect the kernel: saying N will just cause this
-  configure script to skip all the questions about radio
-  interfaces. 
+  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
@@ -6388,8 +6655,8 @@
   in the source code drivers/net/wavelan.p.h.
 
   You will also need the wireless tools package available from
-  ftp://hyper.stanford.edu/pub/pcmcia/contrib/ . Please read the man
-  pages contained therein.
+  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).
@@ -6402,95 +6669,109 @@
   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 latest information.
+  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.
+  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).
-  Work sponsored by www.spectrumwireless.net and www.vendomar.ee
-  This configuration option enables common code for all devices (PCI, ISA,
-  PCMCIA)
-  module is aironet4500_core
+
+  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 
+  Documentation/modules.txt as well as
+  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 
+	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
-  all other parameters can be set via /proc interface
-  These parameters belong to .._card module, but alas, they are here
-  if you have problems with screwing up card, both_bap_lock=1 is conservative
-  value (performance hit 15%)
-  for any other configuration options look at ..._proc module
+  
+  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
-  This is module aironet4500_card, which includes _possibility_ to
-  support for following
-  PCI device
-  ISA device in ISA mode(does not work currently)
-  ISA device in PNP mode
-  PCMCIA device _without_ cardservices, direct 365 chip INIT, 
-	does not work currently
-  PCMCIA _with_ CardServices(normal way) is at another module 
-  radio parameters are currently configurable at ..._core module
+  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 
+  Documentation/modules.txt
 
 Aironet 4500/4800 PNP support
 CONFIG_AIRONET4500_PNP
-	This option should be enabled for ISA cards, remember to enable
-	PNP jumper on board. 
-	module aironet4500_card
+  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
-	This option should be enabled for PCI cards
-	module aironet4500_card
+  If you have an PCI Aironet 4500/4800 card, say Y here.
 
 Aironet 4500/4800 ISA broken support (EXPERIMENTAL)
 CONFIG_AIRONET4500_ISA
-	This option enables support for ISA cards in non-PNP mode. 
-	Does not operate correctly by now.
-	module aironet4500_card
+  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 (EXPERIMENTAL)
 CONFIG_AIRONET4500_I365
-	This option enables support for PCMCIA cards on i365 controller 
-	_without_ cardservices. Doesn't have much sense and is not working
-	properly. Comes from times where there was no PCMCIA support in
-	kernel main source tree
+  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
-	This option enables support for PCMCIA cards to be used with
-	CardServices. 
-	This is not for ISA and PCI adapters.
-	module aironet4500_cs.o
-	The same option is both on:
-		1. PCMCIA netdevices configuring panel
-		2. Wireless netdevices configuring panel
-	Possibility to change this option depends on options set in 2.
+  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 
+  Documentation/modules.txt.
 	
 Aironet 4500/4800 PROC interface
 CONFIG_AIRONET4500_PROC
-	This option enables /proc/sys/aironet4500 interface for 
-	configuring the device.
-	NOTE: it takes lot of memory. Compile it as module and remove
-	after configuration
-	module: aironet4500_proc
-	additional info: look into drivers/net/aironet4500_rids.c
-	this is quite human-readable(no need to know C)
+  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 drivers/net/aironet4500_rids.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 
+  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
@@ -6520,8 +6801,18 @@
 
 PCMCIA network device support
 CONFIG_NET_PCMCIA
-  Say Y if you would like to include support for any PCMCIA network
-  adapters.  If unsure, say N.
+  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 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
@@ -6552,8 +6843,8 @@
 
   This driver is also 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 Documentation/modules.txt. If unsure,
+  The module will be called fmvj18x_cs.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
 NE2000 compatible PCMCIA support
@@ -6574,8 +6865,8 @@
 
   This driver is also 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 Documentation/modules.txt. If unsure,
+  The module will be called nmclan_cs.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
 SMC 91Cxx PCMCIA support
@@ -6585,9 +6876,9 @@
 
   This driver is also 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 Documentation/modules.txt. If unsure,
-  say N.
+  The module will be called smc91c92_cs.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
 
 Xircom 16-bit PCMCIA support
 CONFIG_PCMCIA_XIRC2PS
@@ -6596,10 +6887,21 @@
 
   This driver is also 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 Documentation/modules.txt. If unsure,
+  The module will be called xirc2ps_cs.o. If you want to compile it as
+  a module, say M here and read 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 Documentation/modules.txt. If
+  unsure, say N.
+
 3Com 3c575 CardBus support
 CONFIG_PCMCIA_3C575
   This driver supports the 3Com 3c575 series of CardBus Fast Ethernet
@@ -6610,20 +6912,36 @@
   The module will be called 3c575_cb.o. If you want to do that, say M
   here and read Documentation/modules.txt.  If unsure, say N.
 
-SMC EPIC CardBus support
-CONFIG_PCMCIA_EPIC100
-  This driver supports CardBus Fast Ethernet adapters based on the SMC
-  EPIC chipset.
+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 can only be compiled as a module ( = code which can be
+  This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  The module will be called epic100_cb.o. If you want to do that, say
-  M here and read Documentation/modules.txt.  If unsure, say N.
+  The module will be called xircom_tulip_cb.o. If you want to compile
+  it as a module, say M here and read 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 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 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).
@@ -6633,13 +6951,13 @@
 
 Xircom Netwave AirSurfer wireless support
 CONFIG_PCMCIA_NETWAVE
-  Say Y here if you intend to attach a Xircom Netwave AirSurfer PCMCIA
-  (PC-card) wireless Ethernet networking card to your computer.
+  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 Documentation/modules.txt. If unsure,
+  The module will be called netwave_cs.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
 AT&T/Lucent Wavelan wireless support
@@ -6650,8 +6968,8 @@
 
   This driver is also 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 Documentation/modules.txt. If unsure,
+  The module will be called wavelan_cs.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
 PLIP (parallel port) support
@@ -6814,17 +7132,6 @@
   Say Y here if you have a native Econet network card installed in
   your computer.
 
-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.
-
-  Say Y here if you want to use such interconnections.
-
-  It is safe to say N. Most people won't need it.
-
 WAN Router
 CONFIG_WAN_ROUTER
   Wide Area Networks (WANs), such as X.25, frame relay and leased
@@ -6850,18 +7157,6 @@
 
   If unsure, say N.
 
-WAN router drivers
-CONFIG_WAN_ROUTER_DRIVERS
-  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.
-
-  Say Y here will enable the kernel to a??? as a WAN router betwenn LAN by
-  means of WAN adapters.
-
 Fast switching (read help!)
 CONFIG_NET_FASTROUTE
   Saying Y here enables direct NIC-to-NIC (NIC = Network Interface
@@ -6917,9 +7212,15 @@
   That package also contains some documentation; for more, check out
   http://snafu.freedom.org/linux2.2/iproute-notes.html .
 
-  If you say Y here and to "/proc file system support" below, you will
-  be able to read status information about packet schedulers from the
-  file /proc/net/psched.
+  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://icawwww1.ipfl.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.
@@ -7030,12 +7331,23 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
+### Add these
+#+tristate '  GRED queue' CONFIG_NET_SCH_GRED
+#+tristate '  Diffserv field marker' CONFIG_NET_SCH_DSMARK
+#+tristate '  Ingress Qdisc' CONFIG_NET_SCH_INGRESS
+
 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://icawwww1.ipfl.ch/linux/diffserv/ .
+
   Note that the answer to this question won't directly affect the
   kernel: saying N will just cause this configure script to skip all
   the questions about QoS support.
@@ -7054,8 +7366,16 @@
   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://icawwww1.ipfl.ch/linux/diffserv/ .
+
+### Add
+#tristate '    TC index classifier' CONFIG_NET_CLS_TCINDEX
+
 Routing tables based classifier
-CONFIG_NET_CLS_ROUTE
+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.
 
@@ -7114,7 +7434,7 @@
   here and read Documentation/modules.txt
 
 #
-# Ingres traffic policing
+# Traffic policing (needed for in/egress)
 # CONFIG_NET_CLS_POLICE
 ###
 ### Some expert please fill these in
@@ -7127,6 +7447,22 @@
   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
@@ -7158,16 +7494,24 @@
 
 Fibre Channel driver support
 CONFIG_NET_FC
-  Say Y here provide support for storage arrays connected to
-  the system using Fibre Optic and the "X3.269-199X Fibre Channel
-  Protocol for SCSI" specification. You'll also need the generic SCSI
-  support, as well as 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.
-
-# Interphase 5526 Tachyon chipset based adaptor support
-# CONFIG_IPHASE5526
+  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 Documentation/modules.txt.
+  
 Red Creek Hardware VPN (EXPERIMENTAL)
 CONFIG_RCPCI
   This is a driver for hardware which provides a Virtual Private
@@ -7178,43 +7522,46 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
   
-SBNI Leased Line Adapters
+SBNI12-xx support
 CONFIG_SBNI
-  This is a driver for ISA SBNI12-xx cards that is a low cost
-  alternative to leased line modems. Say Y if you want to insert
-  driver into kernel or say M to compile driver as a module. 
+  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 mail to sbni@granch.ru.
+  utilities at http://www.granch.ru . If you have any question you
+  can send email to sbni@granch.ru.
   
   Say N if unsure.
-  
-WAN Drivers
-CONFIG_WAN_DRIVERS
-  Say Y to this option if your Linux box contains a WAN card and you
-  are planning to use the box as a WAN ( = Wide Area Network) router 
-  ( = device used to interconnect local area networks over wide area
-  communication links, such as leased lines or public data networks,
-  e.g. X.25 or frame relay) and you will be offered a list of drivers
-  for WAN cards currently available. For more information, read
-  Documentation/networking/wan-router.txt.
+
+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 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 this configure script to skip all
-  the questions about WAN card drivers. If unsure, say N.
+  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 T1 (1.544 Mbps). They are also known as Synchronous Data
-  Link Adapters (SDLA) and designated S502E(A), S503 or S508. These
-  cards support the X.25, Frame Relay, and PPP protocols. If you have
-  one or more of these cards, say Y to this option; you may then also
-  want to read the file Documentation/networking/wanpipe.txt. The next
-  questions will ask you about the protocols you want the driver to
-  support.
+  WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com ) is
+  a family of intelligent multiprotocol WAN adapters with data
+  transfer rates up to T1 (1.544 Mbps). They are also known as
+  Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503
+  or S508. These cards support the X.25, Frame Relay, and PPP
+  protocols. If you have one or more of these cards, say Y to this
+  option; you may then also want to read the 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).
@@ -7229,6 +7576,13 @@
   re-compiling the driver, but remember that in this case you'll waste
   some kernel memory (about 1K per card).
 
+WANPIPE Cisco HDLC support
+CONFIG_WANPIPE_CHDLC
+  Say Y to this option if you are planning to connect a WANPIPE card
+  to a connection which uses the synchronous Cisco HDLC (High-level
+  Data Link Control) protocol. This protocol is often used on
+  high-speed leased lines like T1/E1.
+
 WANPIPE X.25 support
 CONFIG_WANPIPE_X25
   Say Y to this option if you are planning to connect a WANPIPE card
@@ -7255,13 +7609,13 @@
 
 MultiGate/COMX 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 linux/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>.
+  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 linux/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>.
 
   If you want to compile this as a module, say M and read
   Documentation/modules.txt. The module will be called comx.o.
@@ -7279,30 +7633,34 @@
 
 LoCOMX board support
 CONFIG_COMX_HW_LOCOMX
-  Hardware driver for the 'LoCOMX' board from the MultiGate family. Say Y
-  if you have a board like this. 
+  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
-  Documentation/modules.txt. The module will be called comx-hw-locomx.o.
+  Documentation/modules.txt. The module will be called
+  comx-hw-locomx.o.
 
 MixCOM board support
 CONFIG_COMX_HW_MIXCOM
-  Hardware driver for the 'MixCOM' board from the MultiGate family. Say Y
-  if you have a board like this.
+  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/.
+  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
-  Documentation/modules.txt. The module will be called comx-hw-mixcom.o.
+  Documentation/modules.txt. The module will be called
+  comx-hw-mixcom.o.
 
 MultiGate Cisco-HDLC and synchronous PPP protocol support
 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.
+  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
   Documentation/modules.txt. The module will be called 
@@ -7314,7 +7672,8 @@
   want to use this protocol on your MultiGate boards.
 
   If you want to compile this as a module, say M and read
-  Documentation/modules.txt. The module will be called comx-proto-lapb.o.
+  Documentation/modules.txt. The module will be called
+  comx-proto-lapb.o.
 
 MultiGate Frame Relay protocol support
 CONFIG_COMX_PROTO_FR
@@ -7322,7 +7681,8 @@
   want to use this protocol on your MultiGate boards.
 
   If you want to compile this as a module, say M and read
-  Documentation/modules.txt. The module will be called comx-proto-fr.o.
+  Documentation/modules.txt. The module will be called
+  comx-proto-fr.o.
 
 Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL)
 CONFIG_CYCLADES_SYNC
@@ -7343,7 +7703,7 @@
   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).
+  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).
@@ -7383,22 +7743,6 @@
   kernel: saying N will just cause this configure script to skip all
   the questions about Ethernet network cards. If unsure, say N.
 
-Sun LANCE Ethernet support
-CONFIG_SUN_LANCE
-  This is support for lance Ethernet cards on Sun workstations such as
-  the SPARCstation IPC (any SPARC with a network interface 'le0' under
-  SunOS basically). 
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called lance.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
-
-Sun Intel Ethernet support
-CONFIG_SUN_INTEL
-  This is support for the Intel Ethernet cards on some Sun
-  workstations (all those with a network interface 'ie0' under SunOS).
-
 Western Digital/SMC cards
 CONFIG_NET_VENDOR_SMC
   If you have a network (Ethernet) card belonging to this class, say Y
@@ -7494,19 +7838,6 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
-PCI DM9102(A)/DM9132/DM9801 support 
-CONFIG_DM9102
-  This driver is for DM9102 compatible PCI cards from Davicom 
-  (http://www.davicom.com.tw) including models DM9132 & DM9801.
-  If you have a PCI DM9102, DM9132 or DM9801 network (Ethernet)
-  card, 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 dmfe.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt as well as
-  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
@@ -7570,9 +7901,9 @@
 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 chip. If you have one of those, say Y and
-  read the Ethernet-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto .
+  the RTL8139 chips. If you have one of those, say Y and read
+  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),
@@ -7584,13 +7915,13 @@
   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 via FTP (user: anonymous) in   
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Please read 
-  Documentation/networking/sis900.txt and comments at the beginning
-  of drivers/net/sis900.c for more information.
+  read the Ethernet-HOWTO, available at
+  http://www.linuxdoc.org/docs.html#howto . Please read
+  Documentation/networking/sis900.txt and comments at the beginning of
+  drivers/net/sis900.c for more information.
 
-  This driver also supports AMD 79C901 HomePNA such that you can use
-  your phone line as network cable.
+  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),
@@ -7632,6 +7963,18 @@
 
   If you don't have this card, of course say N.
 
+Adaptec Starfire support (EXPERIMENTAL)
+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 Documentation/modules.txt. This is recommended.
+  The module will be called starfile.o.
+  
 Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
 CONFIG_ACENIC
   Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear
@@ -7682,6 +8025,11 @@
 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 Documentation/modules.txt. This is recommended.
+  The module will be called myri_sbus.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
@@ -7694,6 +8042,12 @@
   say M here and read 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 .
+
 3COM cards
 CONFIG_NET_VENDOR_3COM
   If you have a network (Ethernet) card belonging to this class, say Y
@@ -7797,6 +8151,18 @@
   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 Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt. The module will be called
+  3c515.o.
+
 3c590 series (592/595/597) "Vortex" support
 CONFIG_VORTEX
   If you have a 3Com "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597)
@@ -7858,7 +8224,7 @@
   ARCnet documentation in Documentation/networking/arcnet.txt for more
   information about using arc0e and arc0s.
 
-Enable arc0s (ARCnet RFC1051 packet format)
+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
@@ -8178,7 +8544,7 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
-Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)
+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
@@ -8263,10 +8629,10 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
-EtherExpress PRO/100 support
-CONFIG_EEPRO100_PM (EXPERIMENTAL)
+Enable Power Management (EXPERIMENTAL)
+CONFIG_EEPRO100_PM
   If you want to play around with power management code
-  that has reported to lock up some machines, say Y here.
+  that has been reported to lock up some machines, say Y here.
 
 ICL EtherTeam 16i/32 support (EXPERIMENTAL)
 CONFIG_ETH16I
@@ -8297,7 +8663,7 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
-  Please email feedback to torben.mathiasen@compaq.com.
+  Please email feedback to  torben.mathiasen@compaq.com.
 
 VIA Rhine support
 CONFIG_VIA_RHINE
@@ -8310,6 +8676,19 @@
   a module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
+PCI DM9102(A)/DM9132/DM9801 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 
+  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 Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
+
 Racal-Interlan EISA ES3210 support (EXPERIMENTAL)
 CONFIG_ES3210
   If you have a network (Ethernet) card of this type, say Y and read
@@ -8347,18 +8726,6 @@
   by this driver. Read the Ethernet-HOWTO, available from
   http://www.linuxdoc.org/docs.html#howto .
 
-Adaptec Starfire support
-CONFIG_ADAPTEC_STARFIRE
-  If you have an Ethernet network card like this, 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 starfire.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt.
-
 Pocket and portable adapters
 CONFIG_NET_POCKET
   Cute little network (Ethernet) devices which attach to the parallel
@@ -8386,9 +8753,14 @@
   port. Read 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
+  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 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
@@ -8459,22 +8831,22 @@
   The module will will be called olympic.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt.
 
-  Also read the file Documentation/networking/olympic.txt or check the 
+  Also read the file Documentation/networking/olympic.txt or check the
   Linux Token Ring Project site for the latest information at
-  http://www.linuxtr.net
+  http://www.linuxtr.net .
 
 IBM Lanstreamer chipset PCI adapter support
 CONFIG_IBMLS
   This is support for IBM Lanstreamer PCI Token Ring Cards.
 
-  If you have such an adapter, say Y and read the Token-Ring mini-HOWTO
-  available via FTP (user:anonymous) from
+  If you have such an adapter, say Y and read the Token-Ring
+  mini-HOWTO available via FTP (user:anonymous) from
   ftp://metalab.unc/edu/pub/Linux/docs/HOWTO.
 
   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 Documentation/modules.txt.
+  The modules will be called lanstreamer.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 Generic TMS380 Token Ring ISA/PCI/MCA/EISA adapter support
 CONFIG_TMS380TR
@@ -8483,16 +8855,21 @@
   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 selected, you will be asked to select
+  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 or M and
+  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 linux/Documentation/networking/tms380tr.txt or check
-  http://www.auk.cx/tms380tr/
+  Also read the 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 will be called tms380tr.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 Generic TMS380 PCI support
 CONFIG_TMSPCI
@@ -8504,30 +8881,53 @@
      - 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 will be called tmspci.o. If you want to compile it
+  as a module, say M here and read 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 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 will be called abyss.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 Madge Smart 16/4 Ringode MicroChannel 
 CONFIG_MADGEMC
   This tms380 module supports the Madge Smart 16/4 MC16 and MC32
-  MicroChannel adapters
+  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 will be called madgemc.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 SMC ISA TokenRing 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.
+  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 .
+  http://www.linuxdoc.org/docs.html#howto and the 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 will be called smctr.o. If you want to compile it
+  as a module, say M here and read 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 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
@@ -8539,8 +8939,8 @@
   This driver supports the "le" interface present on all 32-bit Sparc
   systems, on some older Ultra systems and as an Sbus option.
 
-  This support is also available as a module called sunlance.o ( = code
-  which can be inserted in and removed from the running kernel
+  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 Documentation/modules.txt.
 
@@ -8620,8 +9020,10 @@
   - Netelligent 100 FDDI DAS UTP
   - Netelligent 100 FDDI SAS UTP
   - Netelligent 100 FDDI SAS Fibre MIC
+  
   Read Documentation/networking/skfp.txt for information about
   the driver.
+
   WARNING: this driver does currently not support 64 bit systems!
   Questions concerning this driver can be addressed to:
     linux@syskonnect.de
@@ -8631,14 +9033,6 @@
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called skfp.o.
 
-Linux telephony support
-CONFIG_PHONE
-  This option enable the kernel to manage telephony cards.
-
-  There are very few supported cards at this moment.
-
-  If unsure, say N.
-
 HIgh Performance Parallel Interface support (EXPERIMENTAL)
 CONFIG_HIPPI
   HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
@@ -8712,7 +9106,7 @@
   read Documentation/modules.txt. 
 
   If you want to use any of these CDROM drivers, you also have to
-  answer Y or M to "ISO 9660 CDROM file systems support" below (this
+  answer Y or M to "ISO 9660 CDROM file system support" below (this
   answer will get "defaulted" for you if you enable any of the Linux
   CDROM drivers).
 
@@ -8725,11 +9119,10 @@
   time as described in Documentation/cdrom/cdu31a or fill in your
   parameters into 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. The lilo procedure is also
-  explained in the SCSI-HOWTO. 
+  how to pass options to the kernel.
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  file systems support" below, because that's the file systems used on
+  file system support" below, because that's the file system used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -8751,7 +9144,7 @@
   this. If you want that one, say N here.
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  file systems support" below, because that's the file systems used on
+  file system support" below, because that's the file system used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -8784,7 +9177,7 @@
   Documentation/cdrom/mcdx.
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  file systems support" below, because that's the file systems used on
+  file system support" below, because that's the file system used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -8822,7 +9215,7 @@
   usable.
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  file systems support" below, because that's the file systems used on
+  file system support" below, because that's the file system used on
   CDROMs. 
 
   This driver is also available as a module ( = code which can be
@@ -8835,7 +9228,7 @@
   Say Y here only if you have two CDROM 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
-  linux/include/linux/sbpcd.h before compiling the new kernel. Read
+  include/linux/sbpcd.h before compiling the new kernel. Read
   the file Documentation/cdrom/sbpcd.
 
 Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support
@@ -8847,7 +9240,7 @@
   CDA269-031SE. Please read the file Documentation/cdrom/aztcd. 
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
-  file systems support" below, because that's the file systems used on
+  file system support" below, because that's the file system used on
   CDROMs.
 
   This driver is also available as a module ( = code which can be
@@ -8872,8 +9265,8 @@
 Goldstar R420 CDROM support
 CONFIG_GSCD
   If this is your CDROM drive, say Y here. As described in the file
-  linux/Documentation/cdrom/gscd, you might have to change a setting
-  in the file linux/drivers/cdrom/gscd.h before compiling the
+  Documentation/cdrom/gscd, you might have to change a setting
+  in the file drivers/cdrom/gscd.h before compiling the
   kernel. Please read the file Documentation/cdrom/gscd. 
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
@@ -8929,17 +9322,6 @@
   The module will be called sjcd.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-Soft configurable cdrom interface card support
-CONFIG_CDI_INIT
-  If you want to include boot-time initialization of any cdrom
-  interface card that is software configurable, say Y here. Currently
-  only the ISP16/MAD16/Mozart sound cards with built-in cdrom
-  interfaces are supported. 
-
-  Note that the answer to this question doesn't directly affect the
-  kernel: saying N will just cause this configure script to skip all
-  the questions about these CDROM drives.
-
 ISP16/MAD16/Mozart soft configurable cdrom interface support
 CONFIG_ISP16_CDI
   These are sound cards with built-in cdrom interfaces using the OPTi
@@ -8969,8 +9351,8 @@
   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 PCs have USB
+  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.
@@ -8986,6 +9368,12 @@
   The module will be called usbcore.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+USB verbose debug messages
+CONFIG_USB_DEBUG
+  Say Y here if you want the USB core 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.
+
 UHCI (intel PIIX4, VIA, ...) support?
 CONFIG_USB_UHCI
   The Universal Host Controller Interface is a standard by Intel for
@@ -9061,17 +9449,37 @@
   USB keyboard and prefer to use the keyboard in its limited Boot
   Protocol mode. 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 Documentation/modules.txt.
+
+  If unsure, say N.
+
 USB HIDBP Mouse 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. 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 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 you select Mouse and Event
-  support as well.
+  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 "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 Documentation/modules.txt.
 
 Logitech WingMan Force joystick support
 CONFIG_USB_WMFORCE
@@ -9079,42 +9487,65 @@
   on the USB port. No force-feedback support yet, but other than that,
   it should work like a normal 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 wmforce.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
 Keyboard support
 CONFIG_INPUT_KEYBDEV
   Say Y here if you want your USB HID keyboard 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 Documentation/modules.txt.
+
 Mouse support
 CONFIG_INPUT_MOUSEDEV
   Say Y here if you want your USB HID mouse to be accessible as
-  misc devices 32+ under /dev/, as an emulated PS/2 mouse.
+  misc devices 32+ under /dev/, as an emulated PS/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 Documentation/modules.txt.
 
 Mix all mice into one device
 CONFIG_INPUT_MOUSEDEV_MIX
   Say Y here if you want input from all your USB HID mice to be mixed
   into one misc device. If you say N, you'll have a separate
-  device for each your USB mouse.
+  device for each USB mouse.
 
 Support for digitizers
 CONFIG_INPUT_MOUSEDEV_DIGITIZER
-  Use this if you have a digitizer that doesn't emulate a mouse
+  Say Y here if you have a digitizer that doesn't emulate a mouse
   itself, and want to use it as a mouse.
 
 Horizontal screen resolution
 CONFIG_INPUT_MOUSEDEV_SCREEN_X
-  For the mouse emulation to be correct, the mousedev driver needs
-  to know the screen resolution you are using (in X). 
+  For the mouse emulation to be correct, the mousedev driver needs to
+  know the screen resolution you are using (in the X window system).
 
 Vertical screen resolution
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y
-  For the mouse emulation to be correct, the mousedev driver needs
-  to know the screen resolution you are using (in X). 
+  For the mouse emulation to be correct, the mousedev driver needs to
+  know the screen resolution you are using (in the X window system).
 
 Joystick support
 CONFIG_INPUT_JOYDEV
   Say Y here if you want your USB HID joystick or gamepad to be
-  accessible as /dev/js device. You can't use a normal joystick
-  if you select this.
+  accessible as a /dev/js device. You can't use a normal (non-USB)
+  joystick if you 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 joydev.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Event interface support
 CONFIG_INPUT_EVDEV
@@ -9124,18 +9555,18 @@
 
 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 Documentation/usb/scanner.txt
-  and Documentation/usb/scanner-hp-sane.txt for more information.
+  Say Y here if you want to connect a USB scanner to your computer's
+  USB port. Please read Documentation/usb/scanner.txt and
+  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 hp_scanner.o. If you want to compile it as
+  The module will be called scanner.o. If you want to compile it as
   a module, say M here and read Documentation/modules.txt.
 
 USB Audio support
 CONFIG_USB_AUDIO
-  Say Y here if you want to connect USB audio equipment such as
+  Say Y here if you want to connect UAB audio equipment such as
   speakers to your computer's USB port.
 
   This code is also available as a module ( = code which can be
@@ -9155,11 +9586,16 @@
 
 USB Serial converter support
 CONFIG_USB_SERIAL
-  Say Y here if you want to connect a Connect Tech WhiteHEAT 
-  multi-port USB to serial converter; a FTDI or Keyspan single port 
-  USB to serial converter; or a Handspring Visor. Please read 
-  Documentation/usb/usb-serial.txt for more information.
+  Say Y here if you have a USB device that provides normal serial
+  ports, and you want to connect it to your USB bus. Supported devices
+  are the Tech WhiteHEAT multi-port USB to serial converter, and the
+  FTDI or Keyspan single port USB to serial converter Handspring
+  Visor. In addition to saying Y here, you need to say Y to the driver
+  for your specific hardware below. Some other devices may also be
+  used if you say Y to "USB Generic Serial Driver", below.
 
+  Please read 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 usb-serial.o. If you want to compile it 
@@ -9167,10 +9603,11 @@
 
 USB Generic Serial Driver
 CONFIG_USB_SERIAL_GENERIC
-  Say Y here if you want to use the generic USB serial driver.
-  Please read Documentation/usb/usb-serial.txt for more information
-  on using this driver. It is recommended that the USB Serial
-  Driver be compiled as a module for this driver to be used properly.
+  Say Y here if you want to use the generic USB serial driver. Please
+  read 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
@@ -9186,7 +9623,10 @@
 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.
+  converter device. The implementation I have is called the USC-1000
+
+  See http://reality.sgi.com/bryder_wellington/ftdi_sio for more information 
+   on this driver and the device
 
 USB FTDI Single Port Serial Driver
 CONFIG_USB_SERIAL_KEYSPAN_PDA
@@ -9203,26 +9643,11 @@
   The module will be called printer.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-USB CPiA Camera support
-CONFIG_USB_CPIA
-  Say Y here if you want to connect this type of camera to your
-  computer's USB port.
-
-  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 cpia.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
-
 USB IBM (Xirlink) C-It Camera support
 CONFIG_USB_IBMCAM
-  Say Y here if you want to connect this type of camera to your
-  computer's USB port.
+  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 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)
@@ -9243,11 +9668,10 @@
   computer's USB port. See Documentation/usb/ov511.txt for more
   information and for a list of supported cameras.
   
-  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 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).
@@ -9256,11 +9680,18 @@
 
 USB ADMtek Pegasus-based ethernet device support
 CONFIG_USB_PEGASUS
-  Say Y if you want to use your USB ethernet device. Note that
-  the code is still experimental. If you have devices with vendor
-  IDs other than ADMtek's, you should change/add them in the
-  driver code and send a message to me (petkan@spct.net) for 
-  update.
+  Say Y if you want to use your USB ethernet device. Supported
+  cards until now are:
+    Accton 10/100
+    Billington USB-100
+    Corega FEter USB-TX
+    MELCO/BUFFALO LUA-TX
+    D-Link DSB-650TX, DSB-650TX-PNA
+    Linksys USB100TX
+    SNC 202
+  If you have devices with vendor IDs other than noted above
+  you should add them in the driver code and send a message
+  to me (petkan@spct.net) for update.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -9285,7 +9716,7 @@
   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 www.gphoto.org).
-  To use it create a devicenode with mknod /dev/mustek c 10 171 and
+  To use it create a devicenode 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
@@ -9293,7 +9724,6 @@
   The module will be called mdc800.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-
 USB Mass Storage support
 CONFIG_USB_STORAGE
   Say Y here if you want to connect USB mass storage devices to your
@@ -9312,8 +9742,9 @@
 USS720 parport driver
 CONFIG_USB_USS720
   This driver is for USB parallel port adapters that use the Lucent
-  Technologies USS-720 chip. These adapters provide USB compatibility
-  to peripherals designed with parallel port interfaces.
+  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
@@ -9338,38 +9769,53 @@
   
 USB device file system
 CONFIG_USB_DEVICEFS
-  This file system implements a "devices" file, that lists
-  the currently connected to your USB busses, a "drivers" file
-  that lists the USB kernel client drivers currently loaded,
-  and for every connected device a file named "xxx/yyy", where
-  xxx is the bus number and yyy the device number, that can be used
-  by userspace drivers to talk to the device.
+  If you say Y here (and to "/proc file system support" below), you
+  will get a file /proc/usb/devices which lists the devices currently
+  connected to your USB busses, a file /proc/usb/drivers file which
+  lists the USB kernel client drivers currently loaded, and for every
+  connected device a file named "/proc/usb/xxx/yyy", where xxx is the
+  bus number and yyy the device number; the latter files can be used
+  by userspace drivers to talk to the device. These files are
+  "virtual", meaning they are generated on the fly and not stored on
+  the hard drive.
+  
+  For the format of the /proc/usb/ files, please read
+  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.
 
 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.
+  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
+  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 Documentation/modules.txt.
- 
+
 PLUSB driver
 CONFIG_USB_PLUSB
-  A driver for the Prolific PL-2302 USB-to-USB network device. This 'USB
-  cable' connects two hosts via a point-to-point network with bandwidth of
-  5 Mbit/s.  Configure this driver after connecting the USB cable via
-  ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 
-  (and vice versa on the other host).
+  A driver for the Prolific PL-2302 USB-to-USB network device. This
+  'USB cable' connects two hosts via a point-to-point network with
+  bandwidth of 5 Mbit/s. Configure this driver after connecting the
+  USB cable via ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 (and
+  vice versa on the other host).
+
+  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 plusb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 USB Diamond Rio500 support
 CONFIG_USB_RIO500
-  Say Y here if you want to connect a USB rio500 to your
+  Say Y here if you want to connect a USB Rio500 mp3 player to your
   computer's USB port. Please read Documentation/usb/rio.txt
   for more information.
 
@@ -9378,7 +9824,7 @@
   The module will be called rio500.o. If you want to compile it as
   a module, say M here and read Documentation/modules.txt.
 
-D-Link DSB-R100 FM radio upport
+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
@@ -9396,28 +9842,22 @@
   The module will be called dsbr100.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-ACPI support
-CONFIG_ACPI
-  Advanced Configuration and Power Interface (ACPI) is an interface
-  specification to support power management of peripherals. If your
-  system supports it, say Y here.
-
 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.
+  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 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.
+  called minix.o. Note that the file system of your root partition
+  (the one containing the directory /) cannot be compiled as a module.
 
 Second extended fs support
 CONFIG_EXT2_FS
@@ -9425,11 +9865,11 @@
   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
+  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
+  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*
@@ -9437,7 +9877,7 @@
   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.
+  by about 44 KB.
 
   The Ext2fs-Undeletion mini-HOWTO, available from
   http://www.linuxdoc.org/docs.html#howto , gives information about
@@ -9451,9 +9891,10 @@
   command line tool package (available via FTP (user: anonymous) from
   ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2 ) and from
   within Windows NT using the ext2nt command line tool package from
-  ftp://metalab.unc.edu/pub/Linux/utils/dos . Explore2fs is a graphical
-  explorer for ext2fs partitions which runs on Windows 95 and Windows
-  NT and includes experimental write support; it is available from
+  ftp://metalab.unc.edu/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
@@ -9467,31 +9908,50 @@
 BFS file system support (EXPERIMENTAL)
 CONFIG_BFS_FS
   Boot File System (BFS) is a file system used under SCO UnixWare to
-  allow bootloader access 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. This is useful if you want to access files on your /stand
-  slice from Linux. More information on this file system can be found in
-  Documentation/filesystems/bfs.txt file. If you do not know what it is, 
-  say N.
+  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 
+  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 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 Documentation/filesystems/cramfs.txt and 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 Documentation/modules.txt. The module will be
+  called cramfs.o.
+   
 ISO 9660 CDROM file system support
 CONFIG_ISO9660_FS
   This is the standard file system used on CDROMs. 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 CDROM drive and want to do more with it than just
-  listen to audio CDs and watch its LEDs, say Y (and read
+  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 CDROM drive and want to do more with it than
+  just listen to audio CDs and watch its LEDs, say Y (and read
   Documentation/filesystems/isofs.txt and the CDROM-HOWTO, available
-  from http://www.linuxdoc.org/docs.html#howto ), thereby
-  enlarging your kernel by about 27 KB; otherwise say N.
+  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),
@@ -9507,17 +9967,21 @@
   http://www.unicode.org for more information). Say Y here if you want
   to be able to read Joliet CDROMs under Linux.
 
-UDF file system support (read only)
+UDF File System support (read only)
 CONFIG_UDF_FS
-  This is the new file system used by some CDROMS and DVD drivers. 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. Please
-  read Documentation/filesystems/udf.txt.
+  This is the new file system used on some CDROMs 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
+  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 Documentation/modules.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
+  Documentation/modules.txt.
 
   If unsure, say N.
 
@@ -9525,7 +9989,7 @@
 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.
+  is only supported for hard discs, DVD-RAM, and loopback files.
 
 DOS FAT fs support
 CONFIG_FAT_FS
@@ -9537,18 +10001,24 @@
   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.
+  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. This doesn't require the FAT
-  file system support.
+  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 Documentation/filesystems/fat_cvf.txt for details.
+  file systems; read Documentation/filesystems/fat_cvf.txt for
+  details.
   
   The FAT support will enlarge your kernel by about 37 KB. If unsure,
   say Y.
@@ -9557,11 +10027,11 @@
   be inserted in and removed from the running kernel whenever you
   want), say M here and read Documentation/modules.txt. The module
   will be called 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.
+  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
@@ -9576,36 +10046,37 @@
   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 DOS,
-  which allows you to run Linux from within a DOS partition without
-  repartitioning, you'll have to say Y or M here. 
+  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
+  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 "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 Documentation/modules.txt. The module
-  will be called msdos.o.
+  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 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 mtools. 
+  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
-  "umsdos: Unix like fs on top of std MSDOS fs", below).
+  "UMSDOS: 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 "fat fs support" above. Please read the
-  file Documentation/filesystems/vfat.txt for details. If unsure, 
+  works if you said Y to the "DOS FAT fs support" above. Please read
+  the file Documentation/filesystems/vfat.txt for details. If unsure,
   say Y.
 
   If you want to compile this as a module ( = code which can be
@@ -9613,23 +10084,6 @@
   say M here and read Documentation/modules.txt. The module will be
   called vfat.o.
 
-Compressed ROM file system support
-CONFIG_CRAMFS
-  This option provides 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), don't
-  support neither 16/32 bits uid/gid nor hard links. Neither are timestamps.
-  It isn't endian aware.
-  
-  See Documentation/filesystems/cramfs.txt and 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 Documentation/modules.txt. The module will be
-  called cramfs.o.
-
 UMSDOS: 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
@@ -9642,20 +10096,20 @@
   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 Documentation/filesystems/umsdos.txt. 
+  make use of UMSDOS; read Documentation/filesystems/umsdos.txt. 
 
   To get utilities for initializing/checking UMSDOS file system, or
-  latest patches and/or information, visit UMSDOS homepage at
+  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 "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 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.
+  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 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
@@ -9674,30 +10128,35 @@
 
   The /proc file system is explained in the file
   Documentation/filesystems/proc.txt and on the proc(5) manpage ("man
-  5 proc").
+  5 proc"). You can also use the program procinfo to display some
+  information about your system gathered from the /proc file system.
 
   This option will enlarge your kernel by about 67 KB. Several
   programs depend on this, so everyone should say Y here.
 
 /dev file system support (EXPERIMENTAL)
 CONFIG_DEVFS_FS
-  This is another 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 appear automagically. Without
-  devfs you need to populate /dev with hundreds, even thousands of
-  inodes.
+  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 anymore.
+
   This is work in progress. If you want to use this you *must* read
-  Documentation/filesystems/devfs/README
-  In particular, make sure you install devfsd. If you don't, expect to
-  spend time patching broken code and updating configuration files.
+  the material in Documentation/filesystems/devfs/, especially the
+  file README there.
+
+  If unsure, say N.
 
 Debug devfs
 CONFIG_DEVFS_DEBUG
-  This option appears if you have CONFIG_DEVFS_FS enabled. Setting
-  this to 'Y' enables devfs debugging output. See the file
+  If you say Y here, then the /dev file system code will generate
+  debugging messages. See the file
   Documentation/filesystems/devfs/boot-options for more details.
-  The default is 'N'.
+  
+  If unsure, say N.
 
 NFS file system support
 CONFIG_NFS_FS
@@ -9710,7 +10169,7 @@
   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://metalab.unc.edu/mdw/linux.html#guide , on its man page: "man
+  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
@@ -9761,35 +10220,34 @@
   section.
 
   Please read the NFS-HOWTO, available from
-  http://www.linuxdoc.org/HOWTO/NFS-HOWTO.html .
-
+  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 Documentation/modules.txt. If unsure, say N.
 
-Provide NFSv3 server support (EXPERIMENTAL)
+Provide NFSv3 server support
 CONFIG_NFSD_V3
-  If you would like to include the NFSv3 server was well as the NFSv2
-  server, say Y here.  File locking, via the NLMv4 protocol, is also
-  supported. If unsure, say N.
+  If you would like to include the NFSv3 server as well as the NFSv2
+  server, say Y here.  In unsure, say Y.
 
 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 an OS/2
-  HPFS partition of 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 Documentation/filesystems/hpfs.txt. 
+  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
+  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 Documentation/modules.txt. If unsure, say N.
 
-NTFS file system support (read only)
+NTFS 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.
@@ -9804,11 +10262,13 @@
 
 NTFS write support (DANGEROUS)
 CONFIG_NTFS_RW
-  If you say Y here, you will (hopefully) 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
+  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
   enable this, back up your NTFS volume first since it may get
-  damaged.
+  damaged. Also, make sure to run chkdsk from within Microsoft
+  Windows NT after having performed any writes to a NTFS partition
+  from Linux to detect any problems as early as possible.
 
   If unsure, say N.
 
@@ -9816,7 +10276,8 @@
 CONFIG_SYSV_FS
   SCO, Xenix and Coherent are commercial Unix systems for Intel
   machines. Saying Y here would allow you to read from their floppies
-  and hard disk partitions.
+  and hard disk partitions. If you also want to write to these media,
+  say Y to "SYSV file system write support" below.
 
   If you have floppies or hard disk partitions like that, it is likely
   that they contain binaries from those other Unix systems; in order
@@ -9837,7 +10298,7 @@
   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 Documentation/filesystems/sysv-fs.txt.
-  Saying Y here will enlarge your kernel by about 27 kB.
+  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),
@@ -9848,12 +10309,12 @@
 
 SYSV file system write support (DANGEROUS)
 CONFIG_SYSV_FS_WRITE
-  If you say Y here, you will (hopefully) be able to write to System V
-  and Coherent file systems as well as read from them. The read-write
-  support in SYSV is not well tested yet. If you enable this, back up
-  your SYSV/Coherent volumes first since they may get damaged.
+  If you say Y here, you will be able to write to hard drive
+  partitions and floppy disks which carry a SYSV file system used the
+  commercial Unixes SCO, Xenix and Coherent. 
 
-  If unsure, say N.
+  This support is experimental and you may destroy your data. If
+  unsure, say N.
 
 Amiga FFS file system support
 CONFIG_AFFS_FS
@@ -9883,10 +10344,11 @@
   Please read 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 Documentation/modules.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 hfs.o. If you want to
+  compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 ROM file system support
 CONFIG_ROMFS_FS
@@ -9895,10 +10357,11 @@
   other read-only media as well. Read
   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 Documentation/modules.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 romfs.o. If you want to
+  compile it as a module, say M here and read
+  Documentation/modules.txt.
 
   If you don't know whether you need it, then you don't need it:
   answer N.
@@ -9907,13 +10370,14 @@
 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 write support" below, you will only be able to read
+  "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 Documentation/modules.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 qnx4.o. If you want to
+  compile it as a module, say M here and read
+  Documentation/modules.txt.
 
   If you don't know whether you need it, then you don't need it:
   answer N.
@@ -9933,6 +10397,10 @@
   ftp://ftp.kernel.org/pub/linux/daemons/autofs ; 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 Documentation/modules.txt. The module will be
@@ -9941,10 +10409,7 @@
   If you are not a part of a fairly large, distributed network, you
   probably do not need an automounter, and can say N here.
 
-  If you want to use the newer version of autofs with more features,
-  say N here and select automounter v4.
-
-Kernel automounter version 4 support (also supports v3)
+Kernel automounter v4 support
 CONFIG_AUTOFS4_FS
   The automounter is a tool to automatically mount remote file systems
   on demand. This implementation is partially kernel-based to reduce
@@ -9961,15 +10426,16 @@
   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.
+  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) (EXPERIMENTAL)
+EFS file system support (read-only) (EXPERIMENTAL)
 CONFIG_EFS_FS
-  EFS is an older file system used for non-ISO9660 CDROMs 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).
+  EFS is an older file system used for non-ISO9660 CDROMs 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
@@ -9980,12 +10446,7 @@
   whenever you want), say M here and read Documentation/modules.txt.
   The module will be called efs.o. 
 
-SGI disklabel support
-CONFIG_SGI_DISKLABEL
-  Say Y to this only if you plan on mounting disks with SGI
-  disklabels. This is not required to mount EFS-format CDROMs.
-
-UFS file system support (read only)
+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
@@ -10028,7 +10489,7 @@
 
   Note that the answer to this question won't directly affect the
   kernel: saying N will just cause this configure script to skip all
-  the questions about foreign partitioning schemes.
+  the questions about foreign partitioning schemes. 
 
   If unsure, say N.
 
@@ -10084,13 +10545,14 @@
   Say Y here if you would like to be able to read the hard disk
   partition table format used by SGI machines.
 
-ADFS file system support (read only) (EXPERIMENTAL)
+ADFS file system support (EXPERIMENTAL)
 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.
+  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
@@ -10103,6 +10565,12 @@
 
   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.
@@ -10119,7 +10587,8 @@
   mode of operation; you also need client programs that use the Unix98
   API.
 
-  Note that CONFIG_DEVFS_FS is a more general facility.
+  Note that the experimental "/dev file system support"
+  (CONFIG_DEVFS_FS)  is a more general facility.
 
 UnixWare slices support (EXPERIMENTAL)
 CONFIG_UNIXWARE_DISKLABEL
@@ -10127,9 +10596,8 @@
   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", "System
-  V and Coherent file system support" or "BFS file system support",
-  above.
+  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
@@ -10178,9 +10646,9 @@
 
   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. need no kernel
-  support. Please read Documentation/filesystems/coda.txt and check
-  out the Coda home page http://www.coda.cs.cmu.edu .
+  and server. Servers are currently user level, i.e. they need no
+  kernel support. Please read 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
@@ -10266,7 +10734,7 @@
 
   To utilize this feature you must use ncpfs-2.0.12 or newer.
 
-NDS interserver authentication domains
+NDS authentication support
 CONFIG_NCPFS_NDS_DOMAINS
   This allows storing NDS private keys in kernel space where they
   can be used to authenticate another server as interserver NDS
@@ -10295,7 +10763,7 @@
 
 nls codepage 437
 CONFIG_NLS_CODEPAGE_437
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10306,7 +10774,7 @@
 
 nls codepage 737
 CONFIG_NLS_CODEPAGE_737
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10317,7 +10785,7 @@
 
 nls codepage 775
 CONFIG_NLS_CODEPAGE_775
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10328,7 +10796,7 @@
 
 nls codepage 850
 CONFIG_NLS_CODEPAGE_850
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10343,7 +10811,7 @@
 
 nls codepage 852
 CONFIG_NLS_CODEPAGE_852
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10357,7 +10825,7 @@
 
 nls codepage 855
 CONFIG_NLS_CODEPAGE_855
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10367,7 +10835,7 @@
 
 nls codepage 857
 CONFIG_NLS_CODEPAGE_857
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10377,7 +10845,7 @@
 
 nls codepage 860
 CONFIG_NLS_CODEPAGE_860
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10387,7 +10855,7 @@
 
 nls codepage 861
 CONFIG_NLS_CODEPAGE_861
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10397,7 +10865,7 @@
 
 nls codepage 862
 CONFIG_NLS_CODEPAGE_862
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10407,7 +10875,7 @@
 
 nls codepage 863
 CONFIG_NLS_CODEPAGE_863
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10418,7 +10886,7 @@
 
 nls codepage 864
 CONFIG_NLS_CODEPAGE_864
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10428,7 +10896,7 @@
 
 nls codepage 865
 CONFIG_NLS_CODEPAGE_865
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10439,7 +10907,7 @@
 
 nls codepage 866
 CONFIG_NLS_CODEPAGE_866
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10450,20 +10918,17 @@
 
 nls codepage 869
 CONFIG_NLS_CODEPAGE_869
-  The Microsoft fat file system family can deal with filenames in
+  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.
-###
-### Why do we have two codepages for Greek and Cyrillic?
-###
 
 nls codepage 874
 CONFIG_NLS_CODEPAGE_874
-  The Microsoft fat file system family can deal with filenames in
+  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
@@ -10474,7 +10939,7 @@
 nls iso8859-1
 CONFIG_NLS_ISO8859_1
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   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,
@@ -10485,7 +10950,7 @@
 nls iso8859-2
 CONFIG_NLS_ISO8859_2
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   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
@@ -10495,7 +10960,7 @@
 nls iso8859-3
 CONFIG_NLS_ISO8859_3
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   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,
@@ -10504,7 +10969,7 @@
 nls iso8859-4
 CONFIG_NLS_ISO8859_4
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   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
@@ -10513,7 +10978,7 @@
 nls iso8859-5
 CONFIG_NLS_ISO8859_5
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   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, Byelorussian,
@@ -10523,7 +10988,7 @@
 nls iso8859-6
 CONFIG_NLS_ISO8859_6
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for ISO8859-6, the Arabic
   character set.
@@ -10531,7 +10996,7 @@
 nls iso8859-7
 CONFIG_NLS_ISO8859_7
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   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.
@@ -10539,7 +11004,7 @@
 nls iso8859-8
 CONFIG_NLS_ISO8859_8
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for ISO8859-8, the Hebrew
   character set.
@@ -10547,7 +11012,7 @@
 nls iso8859-9
 CONFIG_NLS_ISO8859_9
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   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
@@ -10556,7 +11021,7 @@
 nls iso8859-10
 CONFIG_NLS_ISO8859_10
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   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)
@@ -10566,7 +11031,7 @@
 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 CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   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)
@@ -10576,7 +11041,7 @@
 nls iso8859-15
 CONFIG_NLS_ISO8859_15
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   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,
@@ -10591,7 +11056,7 @@
 nls koi8-r
 CONFIG_NLS_KOI8_R
   If you want to display filenames with native language characters
-  from the Microsoft fat file system family or from JOLIET CDROMs
+  from the Microsoft FAT file system family or from JOLIET CDROMs
   correctly on the screen, you need to include the appropriate
   input/output character sets. Say Y here for the preferred Russian
   character set.
@@ -10608,7 +11073,12 @@
   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) of a virtual terminal.
+  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
@@ -10634,20 +11104,10 @@
   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. The
-  lilo procedure is also explained in the SCSI-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto .)
+  loadlin) about how to pass options to the kernel at boot time.)
 
   If unsure, say Y.
 
-Software generated cursor
-CONFIG_SOFTCURSOR
-  If you say Y here, you'll be able to do lots of nice things with the
-  cursors of your virtual consoles -- for example turn them into
-  non-blinking block cursors which are more visible on laptop screens,
-  or change their colors depending on the virtual console they're on.
-  See Documentation/VGA-softcursor.txt for more information.
-
 Support for PowerMac keyboard
 CONFIG_MAC_KEYBOARD
   This option allows you to use an ADB keyboard attached to your
@@ -10698,9 +11158,7 @@
   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. The lilo procedure is also explained in the
-  SCSI-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto .)
+  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
@@ -10766,11 +11224,11 @@
 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. It
-  does not support 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
+  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 Documentation/computone.txt.
 
   If you want to compile this as a module ( = code which can be
@@ -10818,13 +11276,13 @@
 
 Cyclades-Z interrupt mode operation (EXPERIMENTAL)
 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.
+  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
@@ -10899,6 +11357,24 @@
   and read 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 (EXPERIMENTAL)
 CONFIG_ISI
   This is a driver for the Multi-Tech cards which provide several
@@ -10964,10 +11440,8 @@
   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 lilo procedure
-  is also explained in the SCSI-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto .) The syntax of the "lp"
-  command line option can be found in drivers/char/lp.c.
+  how to pass options to the kernel at boot time.) The syntax of the
+  "lp" command line option can be found in drivers/char/lp.c.
 
   If you have more than 3 printers, you need to increase the LP_NO
   variable in lp.c.
@@ -10980,11 +11454,118 @@
   option "console=lp" to the kernel at boot time.
 
   Note that kernel messages can get lost if the printer is out of
-  paper (or off, or unplugged, or too busy..), but this behavior
+  paper (or off, or unplugged, or too busy..), but this behaviour
   can be changed. See drivers/char/lp.c (do this at your own risk).
 
   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 Documentation/modules.txt. The
+  module will be called ppdev.o.
+
+  If unsure, say N.
+
+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 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 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
+  Documentation/modules.txt. The module will be called i2c-core.o.
+
+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 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 Documentation/modules.txt. The
+  module will be called i2c-philips-par.o.
+
+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 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 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 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 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 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 Documentation/modules.txt. The
+  module will be called i2c-dev.o.
+
 Bus Mouse Support
 CONFIG_BUSMOUSE
   Say Y here if your machine has a bus mouse as opposed to a serial
@@ -11069,7 +11650,7 @@
 
 PC110 digitizer pad support
 CONFIG_PC110_PAD
-  This drives the digitizer pad on the IBM PC110 palmtop. It can turn 
+  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.
 
@@ -11258,11 +11839,10 @@
   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.
+  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.
 
 Controlling the amount of debugging output of ftape
 CONFIG_FT_NORMAL_DEBUG
@@ -11434,50 +12014,52 @@
 Direct Rendering Manager (XFree86 DRI support)
 CONFIG_DRM
   Kernel-level support for the Direct Rendering Infrastructure (DRI)
-  introduced in XFree86 4.x. These modules provide support for
-  synchronization, security, and DMA transfers. Select the module that
-  provides support for your graphics card.
+  introduced in XFree86 4.x. 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 read drivers/char/drm/README.drm for more 
+  details. 
 
-tdfx Direct Rendering Manager (XFree86 DRI support)
+3dfx Banshee/Voodoo3
 CONFIG_DRM_TDFX
   Choose M here if you have a 3dfx Banshee/Voodoo3 graphics card.
+  The module will be called tdfx.o.
 
 3dlabs GMX 2000 Direct Rendering Driver (XFree86 DRI support)
 CONFIG_DRM_GAMMA
   Choose M here if you have a 3dlabs GMX 2000 graphics card.
+  The module will be called gamma.o.
 
 MTRR control and configuration
 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 when you have
+  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. This option creates a
-  /proc/mtrr file which may be used to manipulate your
-  MTRRs. Typically the X server should use this. This should have a
-  reasonably generic interface so that similar control registers on
-  other processors can be easily supported.
+  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, which means that it
-  makes sense to say Y here for these processors as well.
-
+  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.
-
-  The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
-  are supported.
+  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 the secondary CPUs. This can
-  lead to all sorts of problems.
+  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 9K to your kernel.
+  just add about 9 KB to your kernel.
 
   See Documentation/mtrr.txt for more information.
 
@@ -11487,11 +12069,6 @@
   determined automatically, so you need to specify it here ONLY if
   running a DEC Alpha, otherwise this setting has no effect.
 
-Zilog serial support
-CONFIG_SUN_ZS
-  This driver does not exist at this point, so you might as well 
-  say N.
-
 Double Talk PC internal speech card support
 CONFIG_DTLK
   This driver is for the DoubleTalk PC, a speech synthesizer
@@ -11531,26 +12108,54 @@
 
 Power Management support
 CONFIG_PM
-  This enable the kernel to lower the requested computer power by making some
-  devices enter in lower power levels (standy, sleep, ... modes).
-  Basically, this let you save power.
-
-  Two majors interfaces exist between the hardware and the OS, the older
-  Advanced Power Management (APM) and the newer Advanced Configuration and
-  Power Interface (ACPI).
-
-  Both are supported by the Linux Kernel.
-
-  Note that on some architectures (such as ia32), the idle task perform hlt
-  instructions which makes the CPU enter a low power mode. This can be seen as
-  the first kernel PM level.
+  "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
+  The Advanced Configuration and Power Interface is a standard
+  designed to allow the operating system more control over power
+  management issues, such as suspending a computer in a low power
+  consumption state after a certain time of inaction. It aims to be
+  an improved version of APM (see below). ACPI has to be
+  supported by the motherboard. You can read more about the standard
+  at http://www.teleport.com/~acpi/ . 
+
+  If your computer supports ACPI and you want to use it, say Y here.
+  You will then need supporting software; for location and more
+  information, please read Documentation/pm.txt and the Battery
+  Powered Linux mini-HOWTO, available from
+  http://www.linuxdoc.org/docs.html#howto .
+
+  If you say Y here and also to "Advanced Power Management" (APM)
+  below, then ACPI has precedence in the sense that, if your hardware
+  supports ACPI, it will be used and APM won't.
+
+  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. The module will be called 
+  acpi.o.
 
 Enter S1 for sleep (EXPERIMENTAL)
 CONFIG_ACPI_S1_SLEEP
-  This enable ACPI compliant devices to enter level 1 of ACPI saving
-  power levels. Basically, this will let them entering in sleep mode.
+  If you say Y here, ACPI compliant devices can enter level 1 of ACPI
+  saving power levels. Basically, this will let them enter sleep mode.
 
-Advanced Power Management
+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
@@ -11565,8 +12170,9 @@
   Note that the APM support is almost completely disabled for
   machines with more than one CPU.
 
-  Supporting software is available; for more information, read the
-  Battery Powered Linux mini-HOWTO, available from
+  In order to use APM, you will need supporting software. For location
+  and more information, read 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)
@@ -11578,10 +12184,6 @@
   desktop machines also don't have compliant BIOSes, and this driver
   may cause those machines to panic during the boot phase.
 
-  If you are running Linux on a laptop, you may also want to read the
-  Linux Laptop home page on the WWW at
-  http://www.cs.utexas.edu/users/kharker/linux-laptop/ .
-
   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
@@ -11689,7 +12291,7 @@
   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
+  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.
 
@@ -11724,7 +12326,7 @@
 
 Disable watchdog shutdown on close
 CONFIG_WATCHDOG_NOWAYOUT
-  The default watchdog behavior (which you get if you say N here) is
+  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
@@ -11797,34 +12399,47 @@
   module, say M here and read Documentation/modules.txt. Most people
   will say N.
 
-Intel P6 CPU Microcode Update Support
+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 Documentation/modules.txt. Most people
+  will say N.
+
+/dev/cpu/microcode - Intel P6 CPU microcode support
 CONFIG_MICROCODE
-  If you say Y here you will be able to update microcode on 
-  Intel processors in P6 family, e.g.  Pentium Pro, Pentium II, 
+  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 P6 family, e.g. Pentium Pro, Pentium II,
   Pentium III, Xeon etc. You will obviously need the actual microcode
-  binary data itself which is not shipped with the Linux kernel. 
-  You also need to say Y to "/dev file system support" in 'File systems'
-  section of the kernel configuration menu.
+  binary data itself which is not shipped with the Linux kernel.
 
-  You need to be superuser to do that. For latest news and information
-  on obtaining all the required ingredients for this driver, check:
-
-     http://www.ocston.org/~tigran/patches/microcode
+  For latest news and information on obtaining all the required
+  ingredients for this driver, check:
+  http://www.ocston.org/~tigran/patches/microcode .
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  The module will be called microcode.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  The module will be called microcode.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
 
 Enhanced Real Time Clock Support
 CONFIG_RTC
   If you say Y here and create a character special file /dev/rtc with
   major number 10 and minor number 135 using mknod ("man mknod"), you
-  will get access to the real time clock built into your computer.
+  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 behavior is set by various ioctls on
+  /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
@@ -11835,6 +12450,15 @@
   sampling), then say Y here, and read 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 Documentation/modules.txt. 
+
+### Add
+#EFI Real Time Clock Services
+#CONFIG_EFI_RTC
+
 Tadpole ANA H8 Support
 CONFIG_H8
   The Hitachi H8/337 is a microcontroller used to deal with the power
@@ -11878,6 +12502,11 @@
   the file Documentation/joystick.txt which contains more information
   and the location of the joystick package that you'll need.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called joystick.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
 Classic PC analog
 CONFIG_JOY_ANALOG
   Say Y here if you have a controller that connects to the PC
@@ -11887,30 +12516,55 @@
   ThrustMaster FCS or 6 and 8 button gamepads. For more information on
   how to use the driver please read Documentation/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-analog.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 FPGaming and MadCatz A3D
 CONFIG_JOY_ASSASSIN
   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 Documentation/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-assasin.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 Gravis GrIP
 CONFIG_JOY_GRAVIS
   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 Documentation/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-gravis.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 Logitech ADI
 CONFIG_JOY_LOGITECH
   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 Documentation/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-logitech.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 Microsoft SideWinder
 CONFIG_JOY_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 Documentation/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-sidewinder.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 ThrustMaster DirectConnect
 CONFIG_JOY_THRUSTMASTER
   Say Y here if you have a ThrustMaster controller using the
@@ -11918,18 +12572,44 @@
   information on how to use the driver please read
   Documentation/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-thrustmaster.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 Creative Labs Blaster
 CONFIG_JOY_CREATIVE
   Say Y here if you have a Creative Labs controller using the
   Blaster protocol over the PC gameport. For more information on how
   to use the driver please read Documentation/joystick.txt
 
-PDPI Lightning 4 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 joy-creative.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
+PDPI Lightning 4 cards
 CONFIG_JOY_LIGHTNING
   Say Y here if you have a PDPI Lightning 4 gamecard and an analog
   joystick or gamepad connected to it. For more information on how to
   use the driver please read Documentation/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-lightning.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
+Logitech WingMan Warrior
+CONFIG_JOY_WARRIOR
+  Say Y here if you have a Logitech WingMan Warrior controller
+  connected to your computer's serial port.  For more information on
+  how to use the driver please read Documentation/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-warrior.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 Trident 4DWave and Aureal Vortex gameport
 CONFIG_JOY_PCI
   Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2
@@ -11937,12 +12617,22 @@
   with and ordinary analog joystick. For more information on how to
   use the driver please read Documentation/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-pci.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 Magellan and Space Mouse
 CONFIG_JOY_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 Documentation/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-magellan.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 SpaceTec SpaceOrb 360 and SpaceBall Avenger
 CONFIG_JOY_SPACEORB
   Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
@@ -11950,6 +12640,11 @@
   information on how to use the driver please read
   Documentation/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-spaceorb.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+ 
 SpaceTec SpaceBall 4000 FLX
 CONFIG_JOY_SPACEBALL
   Say Y here if you have a SpaceTec SpaceBall 4000 FLX
@@ -11957,12 +12652,11 @@
   information on how to use the driver please read
   Documentation/joystick.txt
 
-Logitech WingMan Warrior
-CONFIG_JOY_WARRIOR
-  Say Y here if you have a Logitech WingMan Warrior controller
-  connected to your computer's serial port.  For more information on
-  how to use the driver please read Documentation/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-spaceball.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+ 
 NES, SNES, N64, PSX, Multi
 CONFIG_JOY_CONSOLE
   Say Y here if you have a Nintendo Entertainment System gamepad,
@@ -11972,15 +12666,25 @@
   For more information on how to use the driver please read
   Documentation/joystick.txt and Documentation/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 joy-console.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 Sega, Multi
 CONFIG_JOY_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
-  Documentation/joystick.txt and Documentation/joystick-parport.txt
+  Commodore, Amstrad CPC joystick connected to your parallel port. 
+  For more information on how to use the driver please read 
+  Documentation/joystick.txt and Documentation/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 joy-db9.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
 
-TurboGraFX interface
+TurboGraFX Multisystem interface
 CONFIG_JOY_TURBOGRAFX
   Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
   and want to use it with Multiststem -- Atari, Amiga, Commodore,
@@ -11988,12 +12692,22 @@
   please read Documentation/joystick.txt and
   Documentation/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 joy-turbografx.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 Amiga joysticks
 CONFIG_JOY_AMIGA
   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
   Documentation/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 Documentation/modules.txt.
+
 Atomwide Serial Support
 CONFIG_ATOMWIDE_SERIAL
   If you have an Atomwide Serial card for an Acorn system, say Y to
@@ -12017,7 +12731,7 @@
   row.
 
   Do not hold the button down for too long, as the driver does not
-  alter the behavior of the hardware reset circuitry attached to the
+  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.
 
@@ -12066,7 +12780,7 @@
   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/.
+  package, available at ftp://ftp.infradead.org/pub/pcsp/ .
 
 OSS sound modules
 CONFIG_SOUND_OSS
@@ -12096,24 +12810,25 @@
   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.
+  "sgalaxy=<io>,<irq>,<dma>,<dma2>,<sgbase>" to the kernel command
+  line.
 
 Support for AD1816(A) based cards (EXPERIMENTAL)
 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.
 
-  NOTE: This driver is still EXPERIMENTAL. 
-        See Documentation/sound/AD1816 for further information.
-
 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 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.
@@ -12124,6 +12839,7 @@
   16 or Logitech SoundMan 16 sound card. Don't answer Y if you have
   some other card made by Media Vision or Logitech since they are not
   PAS16 compatible.
+
   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.
@@ -12138,14 +12854,16 @@
   Please read the file Documentation/sound/Soundblaster.
 
   You should also say Y here for cards based on the Avance Logic
-  ALS-007 chip (read Documentation/sound/ALS007) and for cards based
+  ALS-007 chip (read Documentation/sound/ALS) and for cards based
   on ESS chips (read Documentation/sound/ESS1868 and
   Documentation/sound/ESS). If you have an SB AWE 32 or SB AWE 64, say
   Y here and also to "Additional lowlevel drivers" and to "SB32/AWE
   support" below and read Documentation/sound/INSTALL.awe. If you have
   an IBM Mwave card, say Y here and read 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.
+
+  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.
@@ -12161,6 +12879,7 @@
   Say Y here for any type of Gravis Ultrasound card, including
   the GUS or GUS MAX. See also 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.
 
@@ -12174,6 +12893,7 @@
   was in the list of supported cards, look at the card specific
   instructions in the drivers/sound/Readme.cards file. It's 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.
 
@@ -12182,14 +12902,10 @@
   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.
 
-VIDC Sound
-CONFIG_VIDC_SOUND
-  Say Y here for ARM systems with the VIDC video controller and 16-bit
-  Linear sound DACs. If unsure, say N.
-
 PSS (AD1848, ADSP-2115, ESC614) support
 CONFIG_SOUND_PSS
   Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven
@@ -12197,6 +12913,7 @@
   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
   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.
@@ -12223,16 +12940,6 @@
   Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file,
   starting from /.
 
-16 bit sampling option of GUS (_NOT_ GUS MAX)
-CONFIG_SOUND_GUS16
-  Answer Y if you have installed the 16 bit sampling daughtercard on
-  your GUS. Answer N if you have a GUS MAX, since saying Y here
-  disables GUS MAX support.
-
-GUS MAX support
-CONFIG_SOUND_GUSMAX
-  Answer Y only if you have a Gravis Ultrasound MAX.
-
 Microsoft Sound System support
 CONFIG_SOUND_MSS
   Again think carefully before answering Y to this question. It's safe
@@ -12258,8 +12965,10 @@
   specific instructions in drivers/sound/Readme.cards. 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.
+  "ad1848=<io>,<irq>,<dma>,<dma2>[,<type>]" to the kernel command
+  line.
 
 SGI Visual Workstation on-board audio
 CONFIG_SOUND_VWSND
@@ -12272,16 +12981,15 @@
   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.
+  "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.
-  If you compile the driver into the kernel, you have to add
-  "trix=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<mpuio>,<mpuirq>"
-  to the kernel command line.
 
 Have TRXPRO.HEX firmware file
 CONFIG_TRIX_HAVE_BOOT
@@ -12306,6 +13014,7 @@
   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.
@@ -12329,6 +13038,7 @@
 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.
@@ -12341,6 +13051,7 @@
   Say Y or M if you have a card based on one of these Yamaha
   sound chipsets. Read Documentation/sound/OPL3-SA2 for more
   information on configuring these cards.
+
   If you compile the driver into the kernel, you have to add
   "opl3sa2=<io>,<irq>,<dma>,<dma2>,<mssio>,<mpuio>" to the kernel
   command line.
@@ -12349,6 +13060,7 @@
 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.
 
@@ -12447,15 +13159,11 @@
   cards, however).
   Please read the 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.
- 
-Sun Audio support
-CONFIG_SUN_AUDIO
-  This is support for the sound cards on Sun workstations. The code
-  does not exist yet, so you might as well say N here.
 
 ACI mixer (miroPCM12/PCM20)
 CONFIG_SOUND_ACI_MIXER
@@ -12502,6 +13210,7 @@
   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.
@@ -12590,7 +13299,7 @@
   for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018.
 
   This driver differs slightly from OSS/Free, so PLEASE READ the
-  comments at of driver/sound/trident.c
+  comments at the top of driver/sound/trident.c
 
 Rockwell WaveArtist
 CONFIG_SOUND_WAVEARTIST
@@ -12599,18 +13308,18 @@
 
 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 SoundBlaster or Adlib with this driver, unless you have
-  a SoundBlaster or Adlib card in addition to your VIA audio chip.
+  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.
 
 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.
+  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 Documentation/sound/NM256 for further information.
 
@@ -12627,9 +13336,9 @@
 
 Kernel support for Linux/MIPS 32-bit binary compatibility
 CONFIG_MIPS32_COMPAT
-  Select this option this option if you want Linux/MIPS 32-bit binary
-  compatibility.  Since all software available available for Linux/MIPS
-  is currently 32-bit you should say Y here.
+  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
@@ -12717,7 +13426,7 @@
 
 X.25 PLP on top of ISDN
 CONFIG_ISDN_X25
-  This feature provides the X.25 protocol over ISDN connections.
+  This feature provides the X.25 protocol over ISDN connections. 
   See Documentation/isdn/README.x25 for more information
   if you are thinking about using this.
 
@@ -12782,11 +13491,21 @@
 
 HiSax Support for EURO/DSS1
 CONFIG_HISAX_EURO
-  Enable this if you have a EURO ISDN line.
+  Say Y or N according to the D-channel protocol which your local
+  telephone service company provides.
 
-Support for german chargeinfo
+  NOTE: If you say Y here and you have only one ISDN card installed,
+  you cannot say Y to "HiSax Support for German 1TR6", below. And vice
+  versa.
+
+Support for german charge info
 CONFIG_DE_AOC
-  If you have german AOC, you can enable this to get the charginfo.
+  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
@@ -12800,12 +13519,17 @@
 
 Disable keypad protocol option
 CONFIG_HISAX_NO_KEYPAD
-  If you like to send special dialstrings including * or # without
+  If you like to send special dial strings including * or # without
   using the keypad protocol, select this option.
 
-HiSax Support for german 1TR6
+HiSax Support for German 1TR6
 CONFIG_HISAX_1TR6
-  Enable this if you have a old german 1TR6 line.
+  Say Y or N according to the D-channel protocol which your local
+  telephone service company provides.
+
+  NOTE: If you say Y here and you have only one ISDN card installed,
+  you cannot say Y to "HiSax Support for EURO/DSS1", above. And vice
+  versa.
 
 Teles 16.0/8.0
 CONFIG_HISAX_16_0
@@ -12829,7 +13553,7 @@
 CONFIG_HISAX_TELESPCI
   This enables HiSax support for the Teles PCI.
   See Documentation/isdn/README.HiSax on how to configure it.
-
+ 
 Teles S0Box
 CONFIG_HISAX_S0BOX
   This enables HiSax support for the Teles/Creatix parallel port
@@ -12992,8 +13716,8 @@
 
 HFC-S+, HFC-SP, HFC-PCMCIA cards (EXPERIMENTAL)
 CONFIG_HISAX_HFC_SX
-  This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA cards.
-  This code is not finished yet.
+  This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA
+  cards. This code is not finished yet.
 
 Am7930 (EXPERIMENTAL)
 CONFIG_HISAX_AMD7930
@@ -13049,10 +13773,16 @@
 
 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 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
+  Documentation/modules.txt.
 
 AVM B1 ISA support
 CONFIG_ISDN_DRV_AVMB1_B1ISA
@@ -13091,7 +13821,6 @@
   disconnecting. This will increase the size of the kernel by 7 KB. If
   unsure, say Y.
 
-
 IBM Active 2000 support (EXPERIMENTAL)
 CONFIG_ISDN_DRV_ACT2000
   Say Y here if you have an IBM Active 2000 ISDN card. In order to use
@@ -13100,12 +13829,12 @@
   isdn4k-utils package. Please read the file
   Documentation/isdn/README.act2000 for more information.
 
-Support for AP1000 multicomputer
-CONFIG_AP1000
-  This enables support for a SPARC based parallel multi-computer
-  called AP1000+. For details on our efforts to port Linux to this
-  machine see http://cap.anu.edu.au/cap/projects/linux or mail to
-  hackers@cafe.anu.edu.au
+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 Documentation/isdn/README.hysdn for more
+  information.
 
 Support for Sun4 architecture
 CONFIG_SUN4
@@ -13127,11 +13856,11 @@
 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.
+  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
+  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 Documentation/modules.txt.
 
@@ -13147,14 +13876,14 @@
 
 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 Documentation/modules.txt. The module
-  will be called openpromfs.o. If unsure, say M.
+  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 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
@@ -13195,8 +13924,8 @@
 
 JavaStation OS Flash SIMM (EXPERIMENTAL)
 CONFIG_SUN_JSFLASH
-  This option enables a driver for JavaStation OS Flash driver.
-  Say N unless you want to boot from your Flash SIMM.
+  If you say Y here, you will be able to boot from your JavaStation's
+  Flash memory.
 
 Siemens SAB82532 serial support
 CONFIG_SAB82532
@@ -13212,8 +13941,9 @@
 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.
+  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
@@ -13227,108 +13957,20 @@
 
 DBRI Lowlevel Driver
 CONFIG_SPARCAUDIO_DBRI
-  This driver supports the DBRI audio interface found on the SS10, SS20,
-  Sparcbook 3, and Voyager systems.
+  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.
+  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 (EXPERIMENTAL)
 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.
-
-IEEE 1394 (aka 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).
-
-  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 Documentation/modules.txt. The module will be
-  called ieee1394.o.
-
-  FireWire is a trademark by Apple Inc. and i.Link is a trademark by 
-  Sony.
-
-TI PCILynx IEEE 1394 support
-CONFIG_IEEE1394_PCILYNX
-  Say Y here if you have a 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 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 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.
-  
-  Unless you are absolutely sure that you have 64kB of local RAM and
-  that you want to use it or if you don't know what this is all about,
-  say N here.
-
-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 Documentation/modules.txt. The module will be
-  called aic5800.o.
-
-OHCI (Open Host Controller Interface) support
-CONFIG_IEEE1394_OHCI1394
-  Say Y here if you have a IEEE 1394 controller based on OHCI.
-  The current driver was only tested with OHCI chipsets made
-  by Texas Instruments. However, most third-party vendors use
-  TI chips.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called ohci1394.o.
-
-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 to the IEEE 1394 bus.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called 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.
+  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.
 
 #
 # m68k-specific kernel options
@@ -13370,23 +14012,12 @@
 
 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.
+  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.
 
   If you don't want to compile a kernel for a Sun 3x, say N.
 
-Sun 3 support
-CONFIG_SUN3
-  This option enables support for the Sun 3 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.
-  Currently, it is not possible to build a kernel with support for the
-  Sun 3 and something else, so make sure you have said N to all the
-  other machines. This option does not support the sun3x series of
-  machines (the Sun 3/80 and 3/460). If you don't want to compile a
-  kernel for a Sun 3, say N.
-
 68020 support
 CONFIG_M68020
   If you anticipate running this kernel on a computer with a MC68020
@@ -13444,7 +14075,13 @@
   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. Most users should say N to this question.
+  you are doing. 
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause this configure script to skip all
+  the questions about these options.
+
+  Most users should say N to this question.
 
 Use read-modify-write instructions
 CONFIG_RMW_INSNS
@@ -13465,8 +14102,9 @@
   cards that obey the AutoConfig(tm) specification.
   Say Y if you want your expansion cards to be identified on bootup;
   it will enlarge your kernel by about 10 KB. The identification
-  information is also available through /proc/zorro (say Y to
-  "/proc file system support"!).
+  information is then also available through /proc/zorro (say Y to
+  "/proc file system support"!). Read Documentation/zorro.txt for more
+  information. 
 
   Note that even if you say N here, you can still use your expansion
   cards. If in doubt, say Y.
@@ -13476,23 +14114,6 @@
   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.
 
-Amiga GSP (TMS340x0) support
-CONFIG_AMIGA_GSP
-  Include support for Amiga graphics cards that use the Texas
-  Instruments TMS340x0 GSP (Graphics Signal Processor) chips. Say Y
-  if you want to use a DMI Resolver or Commodore A2410 (Lowell)
-  graphics card on an Amiga; otherwise, say N.
-
-DMI Resolver support
-CONFIG_GSP_RESOLVER
-  Include support in the kernel for the DMI Resolver graphics card. If
-  you have one, say Y; otherwise, say N.
-
-A2410 support
-CONFIG_GSP_A2410
-  Include support in the kernel for the Commodore/University of Lowell
-  A2410 graphics card. If you have one, say Y; otherwise, say N.
-
 Amiga Zorro II ramdisk support
 CONFIG_AMIGA_Z2RAM
   This enables support for using Chip RAM and Zorro II RAM as a
@@ -13591,7 +14212,7 @@
   and the optional Cyberstorm SCSI controller, say Y. Otherwise,
   answer N.
 
-Blizzard 2060 SCSI support
+Blizzard 2060 SCSI support (EXPERIMENTAL)
 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,
@@ -13603,7 +14224,7 @@
   1260 accelerator, and the optional SCSI module, say Y. Otherwise,
   say N.
 
-Blizzard PowerUP 603e+ SCSI support (EXPERIMENTAL)
+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.
@@ -13706,16 +14327,6 @@
   ACSI port ("ACSI node"). The driver works (has to work...) with a
   polled I/O scheme, so it's rather slow :-(
 
-Multiface Card III parallel support
-CONFIG_MULTIFACE_III_LP
-  If you have a Multiface III card for your Amiga, and want to use its
-  parallel port in Linux, 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 lp_m68k.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
-
 Amiga mouse support
 CONFIG_AMIGAMOUSE
   If you want to be able to use an Amiga mouse in Linux, say Y. 
@@ -13725,13 +14336,6 @@
   The module is called amigamouse.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-Amiga Copper Console
-CONFIG_COPCON
-  This configures the console to use the Amiga's graphics coprocessor
-  for scrolling, instead of using the CPU. This option markedly
-  improves response times in the high color modes (5 bitplanes and
-  up). If you would like to use this, say Y; otherwise, say N.
-
 Atari mouse support
 CONFIG_ATARIMOUSE
   If you want to be able to use an Atari mouse in Linux, say Y. 
@@ -13821,12 +14425,44 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
-Amiga or Atari DMA sound support
-CONFIG_DMASOUND
-  If you want to use the internal audio of your Atari or 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.
+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
+  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
+  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
+  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
@@ -13843,11 +14479,6 @@
   If you want to use the builtin "LANCE" Ethernet controller on an
   HP300 machine, say Y here.
 
-Sun 3 onboard LANCE support
-CONFIG_SUN3LANCE
-  If you want to use the onboard AMD "LANCE" (le) Ethernet hardware
-  on a Sun 3, you will need to say Y here.
-
 DIO bus support
 CONFIG_DIO
   Say Y here to enable support for the "DIO" expansion bus used in
@@ -13857,10 +14488,10 @@
 Processor Type
 CONFIG_6xx
   There are three types of PowerPC chips supported. The more common
-  types (601, 603, 604, 740, 750), the Motorola embedded versions (821,
-  823, 850, 855, 860), and the IBM embedded versions (403 and 405).
-  Unless you are building a kernel for one of the embedded processor
-  systems, choose 6xx.
+  types (601, 603, 604, 740, 750), the Motorola embedded versions
+  (821, 823, 850, 855, 860), and the IBM embedded versions (403 and
+  405). Unless you are building a kernel for one of the embedded
+  processor systems, choose 6xx.
 
 Machine Type
 CONFIG_PMAC
@@ -13932,6 +14563,35 @@
   whenever you want). If you want to compile it as a module, say M
   here and read 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 Documentation/modules.txt.
+
+Symbios 53c885 (Synergy ethernet) support
+CONFIG_NCR885E
+  This is and Ethernet driver for the dual-function NCR 53C885
+  SCSI/Ethernet controller.
+
+  This driver is also available as a module called ncr885e.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 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 Documentation/modules.txt.
+
 Video For Linux
 CONFIG_VIDEO_DEV
   Support for audio/video capture and overlay devices and FM radio
@@ -14037,10 +14697,6 @@
   say M here and read Documentation/modules.txt. The module will be
   called radio-cadet.o.
 
-ADS Cadet AM/FM Radio Tuner Card I/O Port
-CONFIG_RADIO_CADET_PORT
-  Enter the I/O address of the card here (most commonly 330). 
-
 SF16FMI Radio
 CONFIG_RADIO_SF16FMI
   Choose Y here if you have one of these FM radio cards, and then fill
@@ -14160,7 +14816,9 @@
 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.
+  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.
 
 PlanB Video-In for PowerMacs
 CONFIG_VIDEO_PLANB
@@ -14179,34 +14837,56 @@
   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,
+  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; to browse the WWW,
-  you need to have access to a machine on the Internet that has a
-  program like lynx or netscape.
+  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 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.
+
+### Add these
 # Zoran ZR36057/36060 support
 # CONFIG_VIDEO_ZORAN
 
 # Include support for Iomega Buz
 # CONFIG_VIDEO_BUZ
 
+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 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
   Documentation/video4linux/bttv for more information.
 
-  This driver is also available as a module called bttv.o ( = code
+  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 Documentation/modules.txt.
@@ -14245,11 +14925,12 @@
 
 Colour QuickCam Video For Linux
 CONFIG_VIDEO_CQCAM
-  This is the video4linux driver for the color version of the
+  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).
+  as a module (c-qcam.o). Read Documentation/video4linux/CQcam.txt for
+  more information.
 
 Mediavision Pro Movie Studio Video For Linux
 CONFIG_VIDEO_PMS
@@ -14266,114 +14947,9 @@
    boards supported by this driver, and for further information 
    on the use of this driver. 
 
-QuickNet Internet LineJack/PhoneJack support
-CONFIG_PHONE_IXJ
-  Say M if you have a telephony card manufactured by Quicknet
-  Technologies, Inc.  These include the Internet PhoneJACK and
-  Internet LineJACK Telephony Cards.
-
-  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:
-
-  /usr/src/linux/Documentation/telephony/ixj.txt.
-
-  For more information on these cards, see Quicknet's website at:
-  http://www.quicknet.net/
-
-  If you do not have any Quicknet telephony cards, you can safely
-  ignore this option.
-
-/dev/agpgart (AGP Support) (EXPERIMENTAL)
-CONFIG_AGP
-  The agpgart kernel module is necessary to use the AGP features
-  of your 3D rendering video card.  It acts as a sort of "AGP
-  driver" for the motherboard's chipset.
-  Loading this module into the kernel will allow the glx module to
-  program the GART (graphics aperture relocation table) registers
-  with appropriate values to transfer commands to the card. 
-
-  If you need more texture memory than you can get with the AGP GART
-  (theoretically up to 256 megs, but in practice usually 64 or 128
-  megs 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 mean to have get XFree4/GLX use
-  write-combining with MTRR support on AGP bus. Without, OpenGL
-  direct rendering will be a lot slower but still faster than PIO.
-
-  For the moment, most people should say no, unless you want to
-  test the GLX component which can be downloaded from
-       http://glx.on.openprojects.net/
-
-  or need to use the 810 Xserver in XFree 3.3.6
-
-Intel 440LX/BX/GX support
-CONFIG_AGP_INTEL
-  This option give you AGP support for the GLX component of the
-  "soon to be released" XFree86-4 on Intel 440LX/BX/GX chipsets.
-
-  For the moment, most people should say no, unless you want to
-  test the GLX component which can be downloaded from
-       http://glx.on.openprojects.net/
-
-Intel I810/I810 DC100/I810e support
-CONFIG_AGP_I810
-  This option give you AGP support for the Xserver for the intel
-  810 chipset boards. This is required to do any useful video
-  modes.
-
-VIA VP3/MVP3/Apollo Pro support
-CONFIG_AGP_VIA
-  This option give you AGP support for the GLX component of the
-  "soon to be released" XFree86-4 on VIA MPV3/Apollo Pro chipsets.
-
-  For the moment, most people should say no, unless you want to
-  test the GLX component which can be downloaded from
-       http://glx.on.openprojects.net/
-
-AMD Irongate support
-CONFIG_AGP_AMD
-  This option give you AGP support for the GLX component of the
-  "soon to be released" XFree86-4 on Intel AMD Irongate chipset.
-
-  For the moment, most people should say no, unless you want to
-  test the GLX component which can be downloaded from
-       http://glx.on.openprojects.net/
-
-Generic SiS support
-CONFIG_AGP_SIS
-  This option give you AGP support for the GLX component of the
-  "soon to be released" XFree86-4 on Silicon Integrated Systems [SiS]
-  chipsets.
-
-  Note than 5591/5592 AGP chipsets are NOT supported.
-
-  For the moment, most people should say no, unless you want to
-  test the GLX component which can be downloaded from
-       http://glx.on.openprojects.net/
-
-ALI M1541 support
-CONFIG_AGP_ALI
-  This option give you AGP support for the GLX component of the
-  "soon to be released" XFree86-4 on ALI M1541 chipset.
-
-  For the moment, most people should say no, unless you want to
-  test the GLX component which can be downloaded from
-       http://glx.on.openprojects.net/
-
 #
 # ARM options
 #
-CPU Optimization
-CONFIG_CPU_ARM2
-  This selects the processor type of your CPU. This is only used to
-  determine C compiler optimization options, and can affect the
-  compatibility of the kernel on other processors. If you specify
-  ARM6, the kernel should work on all 32-bit processors. If you
-  specify ARM2, ARM250 or ARM3, it should work on all 26-bit
-  processors. If you're not sure, set it to "None".
-
 ARM System type
 CONFIG_ARCH_ARC
   This selects what ARM system you wish to build the kernel for. It
@@ -14381,14 +14957,6 @@
   to set this option to, please consult any information supplied with
   your system.
 
-Include support for Chalice CATS boards
-CONFIG_CATS
-  Say Y here if you intend to run this kernel on a CATS system.
-
-Include support for Intel EBSA285
-CONFIG_ARCH_EBSA285
-  board.
-
 Include support for the NetWinder
 CONFIG_ARCH_NETWINDER
   Say Y here if you intend to run this kernel on the NetWinder.
@@ -14412,7 +14980,7 @@
   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 module.
+  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
@@ -14441,12 +15009,6 @@
   you are concerned with the code size or don't want to see these
   messages.
 
-Build Tools Selection
-CONFIG_BINUTILS_NEW
-  Say Y here if and only if you're using GCC 2.8.1/EGCS with a
-  binutils version >= 2.8.1 to compile the kernel (check with "gcc
-  --version" and "ld -v").
-
 Compile kernel with frame pointer
 CONFIG_FRAME_POINTER
   If you say Y here, the resulting kernel will be slightly larger and
@@ -14469,12 +15031,12 @@
   time and disk space needed for compilation of the kernel. If in
   doubt say N.
 
-Split initialization functions into discardable section
+Split initialisation functions into discardable section
 CONFIG_TEXT_SECTIONS
   If you say Y here, kernel code that is only used during
-  initialization is collected into a special area of the kernel so
+  initialisation is collected into a special area of the kernel so
   that it can be discarded and the memory reclaimed when
-  initialization is complete. In addition, if the kernel you wish to
+  initialisation is complete. In addition, if the kernel you wish to
   build is able to run on multiple architectures, it allows the unused
   code to be discarded. Some versions of binutils, however, have a bug
   that causes the kernel to crash during startup when this option is
@@ -14535,7 +15097,7 @@
 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 modules.
+  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.
 
@@ -14553,7 +15115,7 @@
   sometimes doesn't work and it also does some dodgy stuff which
   potentially might damage your drive.
 
-IrDA Protocols
+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
@@ -14565,8 +15127,9 @@
   Documentation/networking/irda.txt. You also want to read the
   IR-HOWTO, available at http://www.linuxdoc.org/docs.html#howto .
 
-  This support is also available as a module. If you want to compile
-  it as a module, say M here and read Documentation/modules.txt.
+  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
+  Documentation/modules.txt.
 
 IrDA Cache last LSAP
 CONFIG_IRDA_CACHE_LAST_LSAP
@@ -14623,7 +15186,7 @@
 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, say M here and read
+  you want to compile it as a module (irlan.o), say M here and read
   Documentation/modules.txt. IrLAN emulates an Ethernet and makes it
   possible to put up a wireless LAN using infrared beams.
 
@@ -14635,19 +15198,20 @@
 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, say M here and read
-  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.
+  you want to compile it as a module (you will get ircomm.o and
+  ircomm-tty.o), say M here and read 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, say M here and
-  read Documentation/modules.txt. IrTTY makes it possible to use
-  Linux's own serial driver for all IrDA ports that are 16550
+  discipline. If you want to compile it as a module (irtty.o), say M
+  here and read 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)
@@ -14657,50 +15221,62 @@
 IrPORT IrDA Device 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, say M here and
-  read 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.
+  driver. If you want to compile it as a module (irport.o), say M here
+  and read 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.
 
-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 drivers/block/sis5513.c
- 
 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. If you want to compile it as a module,
-  say M here and read Documentation/modules.txt. This driver should be
-  used for the IrDA chipset in the Corel NetWinder. The driver
-  supports SIR, MIR and FIR (4Mbps) speeds.
+  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
+  Documentation/modules.txt. The module will be called w83977af_ir.o.
 
 NSC PC87108 IrDA Device Driver
 CONFIG_NSC_FIR
   Say Y here if you want to build support for the NSC PC87108 and
-  PC87338 IrDA chipsets. If you want to compile it as a module, say M 
-  here and read Documentation/modules.txt. This driver supports SIR, 
-  MIR and FIR (4Mbps) speeds.
+  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
+  Documentation/modules.txt. The module will be called nsc-ircc.o.
 
 Toshiba Type-O IR Port Device Driver
 CONFIG_TOSHIBA_FIR
   Say Y here if you want to build support for the Toshiba Type-O IR
-  chipset. If you want to compile it as a module, say M here and
-  read Documentation/modules.txt. This chipset is used by the Toshiba
-  Libretto 100CT, and many more laptops.
+  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 Documentation/modules.txt. The module will be called
+  toshoboe.o.
+
+SMC IrCC (Experimental)
+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 Documentation/modules.txt. The module will be called
+  smc-ircc.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 this configure script to skip all
+  the questions about serial dongles.
 
 ESI JetEye PC Dongle
 CONFIG_ESI_DONGLE
@@ -14748,6 +15324,14 @@
   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 Documentation/modules.txt. The module will be called
+  old_belkin.o. Some information is contained in the comments at the
+  top of 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
@@ -14795,13 +15379,6 @@
   SCSI controller chip.  Almost everyone using one of these boards
   will want to say Y to this question.
 
-Simple 53c710 SCSI support (Compaq, NCR machines)
-CONFIG_SCSI_SIM710
-  This is a driver for the NCR53C710 chip commonly found in Compaq and
-  NCR machines.  If you are looking for 53C710 support for an Amiga or
-  some 680x0 based VME card then you probably want the other NCR53C710
-  driver.
-
 MVME16x Ethernet support
 CONFIG_MVME16x_NET
   This is the driver for the Ethernet interface on the Motorola
@@ -14916,6 +15493,31 @@
   files, usually found in the /dev directory on your system. They
   make it possible to have user-space programs use the I2C bus.
 
+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.
+  It 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).
+
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, 
@@ -14930,7 +15532,7 @@
 # LocalWords:  CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab
 # 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 CDROMs IDECD NEC MITSUMI XT XD PCI BIOS cezar ATEN
+# LocalWords:  HD CDROMs 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
@@ -14960,11 +15562,11 @@
 # 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:  smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI
+# 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 Deskstation DECstation SUNFD JENSEN Noname XXXM SLiRP
+# 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 mac netatalk macs cs Wolff
 # LocalWords:  dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
@@ -14977,12 +15579,13 @@
 # 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 oss sgi com azstarnet cdr fb MDA ps esdi
+# 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 behavior dialin isdn callback BTX Teles ICN EDSS Cisco
+# LocalWords:  NOWAYOUT behaviour dialin isdn callback BTX Teles  XXXX LVM lvm
+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
@@ -15052,12 +15655,12 @@
 # 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:  transname filespace adm Nodename hostname uname Kernelname bootp
+# LocalWords:  filespace adm Nodename hostname uname Kernelname bootp nmi DI OV
 # 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 HIGHMEM DAC IRQ's
-# LocalWords:  IDEPCI IDEDMA idedma PDC pdc TRM trm raidtools luthien nuclecu
+# 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
@@ -15073,7 +15676,7 @@
 # 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 Byelorussian KOI mt
-# LocalWords:  charset Inuit Greenlandic Sami Lappish koi SOFTCURSOR softcursor
+# 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
@@ -15087,7 +15690,7 @@
 # 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 color Connectix QuickClip prive mentre
+# 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
@@ -15103,8 +15706,8 @@
 # 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 SKTR SNA
-# LocalWords:  SysKonnect tms380tr sna etherboot ufs NetBEUI MultiSound MSNDCLAS GX
+# 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
@@ -15141,7 +15744,7 @@
 # LocalWords:  ACTiSYS Dongle 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:  QNX4FS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
+# 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
@@ -15151,7 +15754,7 @@
 # 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 initialisation discardable pgtable PGT mdw
-# LocalWords:  quicklist pagetable arthur StrongARM module modules Autodetect
+# 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
@@ -15173,9 +15776,56 @@
 # 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
+# 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
-# LocalWords:  LOGIBUSMOUSE OV511 ov511 Integraphics
+# LocalWords:  EXTRAPREC fpu mainboards KHTTPD kHTTPd khttpd Xcelerator SBNI tw
+# LocalWords:  LOGIBUSMOUSE Granch granch sbni Raylink NOHIGHMEM Athlon SIM sim
+# LocalWords:  hpl Tourrilhes DuraLAN starfile 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:  WMFORCE mousedev ConnectTech HandSpring Xirlink IBMCAM ibmcam SN
+# LocalWords:  DEVICEFS yyy userspace Cymraeg Dwave SIMM JSFLASH JavaStation's
+# 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
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile
--- v2.3.99-pre3/linux/Documentation/DocBook/Makefile	Mon Mar 27 08:08:20 2000
+++ linux/Documentation/DocBook/Makefile	Mon Apr  3 13:24:05 2000
@@ -1,7 +1,14 @@
-BOOKS	:= wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml kernel-api.sgml
-	
+BOOKS	:= wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml kernel-api.sgml parportbook.sgml
+
+PS	:=	$(patsubst %.sgml, %.ps, $(BOOKS))
+PDF	:=	$(patsubst %.sgml, %.pdf, $(BOOKS))
+
 books:	docproc $(BOOKS)
 
+ps:	$(PS)
+
+pdf:	$(PDF)
+
 docproc:
 	$(MAKE) -C $(TOPDIR)/scripts docproc
 
@@ -36,11 +43,32 @@
 		$(TOPDIR)/drivers/net/wan/syncppp.c \
 		$(TOPDIR)/drivers/net/wan/z85230.c \
 		$(TOPDIR)/kernel/pm.c \
+		$(TOPDIR)/kernel/ksyms.c \
+		$(TOPDIR)/net/netsyms.c \
 		<kernel-api.tmpl >kernel-api.sgml
 
+parportbook.sgml: parportbook.tmpl
+	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/parport/init.c \
+		<parportbook.tmpl >parportbook.sgml
+
+DVI	:=	$(patsubst %.sgml, %.dvi, $(BOOKS))
+AUX	:=	$(patsubst %.sgml, %.aux, $(BOOKS))
+TEX	:=	$(patsubst %.sgml, %.tex, $(BOOKS))
+LOG	:=	$(patsubst %.sgml, %.log, $(BOOKS))
+
 clean:
-	rm -f core *~
-	rm -f $(BOOKS)
+	$(RM) core *~
+	$(RM) $(BOOKS)
+	$(RM) $(DVI) $(AUX) $(TEX) $(LOG)
+
+mrproper: clean
+	$(RM) $(PS) $(PDF)
+
+%.ps : %.sgml
+	db2ps $<
+
+%.pdf : %.sgml
+	db2pdf $<
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl
--- v2.3.99-pre3/linux/Documentation/DocBook/kernel-api.tmpl	Mon Mar 27 08:08:20 2000
+++ linux/Documentation/DocBook/kernel-api.tmpl	Sun Apr  2 15:38:53 2000
@@ -34,13 +34,71 @@
  </bookinfo>
 
 <toc></toc>
-  <chapter id="intfuncs">
-     <title>Interrupt Handling</title>
-!Iarch/i386/kernel/irq.c
+  <chapter id="vfs">
+     <title>The Linux VFS</title>
+     <sect1><title>The Directory Cache</title>
+!Efs/dcache.c
+!Iinclude/linux/dcache.h
+     </sect1>
+     <sect1><title>Inode Handling</title>
+!Efs/inode.c
+!Efs/bad_inode.c
+     </sect1>
+     <sect1><title>Registration and Superblocks</title>
+!Efs/super.c
+     </sect1>
+  </chapter>
+
+  <chapter id="netcore">
+     <title>Linux Networking</title>
+     <sect1><title>Socket Buffer Functions</title>
+!Iinclude/linux/skbuff.h
+!Enet/core/skbuff.c
+     </sect1>
+     <sect1><title>Socket Filter</title>
+!Enet/core/filter.c
+     </sect1>
   </chapter>
-  <chapter id="mtrrfuncs">
-     <title>MTRR Handling</title>
+
+  <chapter id="netdev">
+     <title>Network device support</title>
+     <sect1><title>Driver Support</title>
+!Edrivers/net/net_init.c
+!Enet/core/dev.c
+     </sect1>
+     <sect1><title>8390 Based Network Cards</title>
+!Edrivers/net/8390.c
+     </sect1>
+     <sect1><title>Synchronous PPP</title>
+!Edrivers/net/wan/syncppp.c
+     </sect1>
+  </chapter>
+
+  <chapter id="modload">
+     <title>Module Loading</title>
+!Ekernel/kmod.c
+  </chapter>
+
+  <chapter id="hardware">
+     <title>Hardware Interfaces</title>
+     <sect1><title>Interrupt Handling</title>
+!Iarch/i386/kernel/irq.c
+     </sect1>
+
+     <sect1><title>MTRR Handling</title>
 !Earch/i386/kernel/mtrr.c
+     </sect1>
+     <sect1><title>PCI Support Library</title>
+!Edrivers/pci/pci.c
+     </sect1>
+     <sect1><title>MCA Architecture</title>
+	<sect2><title>MCA Device Functions</title>
+!Earch/i386/kernel/mca.c
+	</sect2>
+	<sect2><title>MCA Bus DMA</title>
+!Iinclude/asm-i386/mca_dma.h
+	</sect2>
+     </sect1>
   </chapter>
 
   <chapter id="pmfuncs">
@@ -58,34 +116,14 @@
 !Edrivers/char/videodev.c
   </chapter>
 
-  <chapter id="netdev">
-     <title>Network devices</title>
-!Idrivers/net/net_init.c
-!Edrivers/net/8390.c
-  </chapter>
-
   <chapter id="snddev">
      <title>Sound Devices</title>
 !Edrivers/sound/sound_core.c
 !Idrivers/sound/sound_firmware.c
   </chapter>
 
-  <chapter id="mcabus">
-     <title>MCA Architecture</title>
-	<sect1><title>MCA Device Functions</title>
-!Earch/i386/kernel/mca.c
-	</sect1>
-	<sect1><title>MCA Bus DMA</title>
-!Iinclude/asm-i386/mca_dma.h
-	</sect1>
-  </chapter>
-
-  <chapter id="syncppp">
-     <title>Synchronous PPP</title>
-!Edrivers/net/wan/syncppp.c
-  </chapter>
 
-  <chapter id="16x50">
+  <chapter id="uart16x50">
      <title>16x50 UART Driver</title>
 !Edrivers/char/serial.c
   </chapter>
@@ -95,9 +133,5 @@
 !Edrivers/net/wan/z85230.c
   </chapter>
 
-  <chapter id="pcilib">
-     <title>PCI Support Library</title>
-!Edrivers/pci/pci.c
-  </chapter>
 
 </book>
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/DocBook/parportbook.sgml linux/Documentation/DocBook/parportbook.sgml
--- v2.3.99-pre3/linux/Documentation/DocBook/parportbook.sgml	Tue Mar 14 19:10:38 2000
+++ linux/Documentation/DocBook/parportbook.sgml	Wed Dec 31 16:00:00 1969
@@ -1,1747 +0,0 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
-
-<book id="ParportGuide">
- <bookinfo>
-  <title>The Parallel Port Subsystem</title>
-
-  <authorgroup>
-   <author>
-    <firstname>Tim</firstname>
-    <surname>Waugh</surname>
-    <affiliation>
-     <address>
-      <email>twaugh@redhat.com</email>
-     </address>
-    </affiliation>
-   </author>
-  </authorgroup>
-
-  <copyright>
-   <year>1999-2000</year>
-   <holder>Tim Waugh</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>
-  </legalnotice>
- </bookinfo>
-
-<toc></toc>
-
-<chapter id="design">
-<title>Design goals</title>
-
-<sect1>
-<title>The problems</title>
-
-<!-- Short-comings -->
-<!-- How they are addressed -->
-
-<!-- Short-comings
-     - simplistic lp driver
-     - platform differences
-     - no support for Zip drive pass-through
-     - no support for readback? When did Carsten add it?
-     - more parallel port devices. Figures?
-     - IEEE 1284 transfer modes: no advanced modes
-  -->
-
-<para>The first parallel port support for Linux came with the line
-printer driver, <filename>lp</filename>.  The printer driver is a
-character special device, and (in Linux 2.0) had support for writing,
-via <function>write</function>, and configuration and statistics
-reporting via <function>ioctl</function>.</para>
-
-<para>The printer driver could be used on any computer that had an IBM
-PC-compatible parallel port.  Because some architectures have parallel
-ports that aren't really the same as PC-style ports, other variants of
-the printer driver were written in order to support Amiga and Atari
-parallel ports.</para>
-
-<para>When the Iomega Zip drive was released, and a driver written for
-it, a problem became apparent.  The Zip drive is a parallel port
-device that provides a parallel port of its own---it is designed to
-sit between a computer and an attached printer, with the printer
-plugged into the Zip drive, and the Zip drive plugged into the
-computer.</para>
-
-<para>The problem was that, although printers and Zip drives were both
-supported, for any given port only one could be used at a time.  Only
-one of the two drivers could be present in the kernel at once.  This
-was because of the fact that both drivers wanted to drive the same
-hardware---the parallel port.  When the printer driver initialised, it
-would call the <function>check_region</function> function to make sure
-that the IO region associated with the parallel port was free, and
-then it would call <function>request_region</function> to allocate it.
-The Zip drive used the same mechanism.  Whichever driver initialised
-first would gain exclusive control of the parallel port.</para>
-
-<para>The only way around this problem at the time was to make sure
-that both drivers were available as loadable kernel modules.  To use
-the printer, load the printer driver module; then for the Zip drive,
-unload the printer driver module and load the Zip driver
-module.</para>
-
-<para>The net effect was that printing a document that was stored on a Zip
-drive was a bit of an ordeal, at least if the Zip drive and printer
-shared a parallel port.  A better solution was needed.</para>
-
-<para>Zip drives are not the only devices that presented problems for
-Linux.  There are other devices with pass-through ports, for example
-parallel port CD-ROM drives.  There are also printers that report
-their status textually rather than using simple error pins: sending a
-command to the printer can cause it to report the number of pages that
-it has ever printed, or how much free memory it has, or whether it is
-running out of toner, and so on.  The printer driver didn't originally
-offer any facility for reading back this information (although Carsten
-Gross added nibble mode readback support for kernel 2.2).</para>
-
-<!-- IEEE 1284 transfer modes: no advanced modes --> 
-
-<para>The IEEE has issued a standards document called IEEE 1284, which
-documents existing practice for parallel port communications in a
-variety of modes.  Those modes are: <quote>compatibility</quote>,
-reverse nibble, reverse byte, ECP and EPP.  Newer devices often use
-the more advanced modes of transfer (ECP and EPP).  In Linux 2.0, the
-printer driver only supported <quote>compatibility mode</quote>
-(i.e. normal printer protocol) and reverse nibble mode.</para>
-
-</sect1>
-
-<sect1>
-<title>The solutions</title>
-
-<!-- How they are addressed
-     - sharing model
-     - overview of structure (i.e. port drivers) in 2.2 and 2.3.
-     - IEEE 1284 stuff
-     - whether or not 'platform independence' goal was met
-  -->
-
-<para>The <filename>parport</filename> code in Linux 2.2 was designed
-to meet these problems of architectural differences in parallel ports,
-of port-sharing between devices with pass-through ports, and of lack
-of support for IEEE 1284 transfer modes.</para>
-
-<!-- platform differences -->
-
-<para>There are two layers to the
-<filename>parport</filename> subsystem, only one of which deals
-directly with the hardware.  The other layer deals with sharing and
-IEEE 1284 transfer modes.  In this way, parallel support for a
-particular architecture comes in the form of a module which registers
-itself with the generic sharing layer.</para>
-
-<!-- sharing model -->
-
-<para>The sharing model provided by the <filename>parport</filename>
-subsystem is one of exclusive access.  A device driver, such as the
-printer driver, must ask the <filename>parport</filename> layer for
-access to the port, and can only use the port once access has been
-granted.  When it has finished a <quote>transaction</quote>, it can
-tell the <filename>parport</filename> layer that it may release the
-port for other device drivers to use.</para>
-
-<!-- talk a bit about how drivers can share devices on the same port -->
-
-<para>Devices with pass-through ports all manage to share a parallel
-port with other devices in generally the same way.  The device has a
-latch for each of the pins on its pass-through port.  The normal state
-of affairs is pass-through mode, with the device copying the signal
-lines between its host port and its pass-through port.  When the
-device sees a special signal from the host port, it latches the
-pass-through port so that devices further downstream don't get
-confused by the pass-through device's conversation with the host
-parallel port: the device connected to the pass-through port (and any
-devices connected in turn to it) are effectively cut off from the
-computer.  When the pass-through device has completed its transaction
-with the computer, it enables the pass-through port again.</para>
-
-<mediaobject>
-<imageobject>
-<imagedata Align=center scalefit=1 fileref="parport-share.eps">
-</imageobject>
-</mediaobject>
-
-<para>This technique relies on certain <quote>special signals</quote>
-being invisible to devices that aren't watching for them.  This tends
-to mean only changing the data signals and leaving the control signals
-alone.  IEEE 1284.3 documents a standard protocol for daisy-chaining
-devices together with parallel ports.</para>
-
-<!-- transfer modes -->
-
-<para>Support for standard transfer modes are provided as operations
-that can be performed on a port, along with operations for setting the
-data lines, or the control lines, or reading the status lines.  These
-operations appear to the device driver as function pointers; more
-later.</para>
-
-</sect1>
-
-</chapter>
-
-<chapter id="transfermodes">
-<title>Standard transfer modes</title>
-
-<!-- Defined by IEEE, but in common use (even though there are widely -->
-<!-- varying implementations). -->
-
-<para>The <quote>standard</quote> transfer modes in use over the
-parallel port are <quote>defined</quote> by a document called IEEE
-1284.  It really just codifies existing practice and documents
-protocols (and variations on protocols) that have been in common use
-for quite some time.</para>
-
-<para>The original definitions of which pin did what were set out by
-Centronics Data Computer Corporation, but only the printer-side
-interface signals were specified.</para>
-
-<para>By the early 1980s, IBM's host-side implementation had become
-the most widely used.  New printers emerged that claimed Centronics
-compatibility, but although compatible with Centronics they differed
-from one another in a number of ways.</para>
-
-<para>As a result of this, when IEEE 1284 was published in 1994, all
-that it could really do was document the various protocols that are
-used for printers (there are about six variations on a theme).</para>
-
-<para>In addition to the protocol used to talk to
-Centronics-compatible printers, IEEE 1284 defined other protocols that
-are used for unidirectional peripheral-to-host transfers (reverse
-nibble and reverse byte) and for fast bidirectional transfers (ECP and
-EPP).</para>
-
-</chapter>
-
-<chapter id="structure">
-<title>Structure</title>
-
-<!-- Main structure
-     - sharing core
-     - parports and their IEEE 1284 overrides
-       - IEEE 1284 transfer modes for generic ports
-       - maybe mention muxes here
-     - pardevices
-     - IEEE 1284.3 API
-  -->
-
-<!-- Diagram -->
-
-<mediaobject>
-<imageobject>
-<imagedata Align=Center ScaleFit=1 fileref="parport-structure.eps">
-</imageobject>
-</mediaobject>
-
-<sect1>
-<title>Sharing core</title>
-
-<!-- sharing core -->
-
-<para>At the core of the <filename>parport</filename> subsystem is the
-sharing mechanism (see <filename>drivers/parport/share.c</filename>).
-This module, <filename>parport</filename>, is responsible for
-keeping track of which ports there are in the system, which device
-drivers might be interested in new ports, and whether or not each port
-is available for use (or if not, which driver is currently using
-it).</para>
-
-</sect1>
-
-<sect1>
-<title>Parports and their overrides</title>
-<!-- parports and their overrides -->
-
-<para>The generic <filename>parport</filename> sharing code doesn't
-directly handle the parallel port hardware.  That is done instead by
-<quote>low-level</quote> <filename>parport</filename> drivers.  The
-function of a low-level <filename>parport</filename> driver is to
-detect parallel ports, register them with the sharing code, and
-provide a list of access functions for each port.</para>
-
-<para>The most basic access functions that must be provided are ones
-for examining the status lines, for setting the control lines, and for
-setting the data lines.  There are also access functions for setting
-the direction of the data lines; normally they are in the
-<quote>forward</quote> direction (that is, the computer drives them),
-but some ports allow switching to <quote>reverse</quote> mode (driven
-by the peripheral).  There is an access function for examining the
-data lines once in reverse mode.</para>
-
-</sect1>
-
-<sect1>
-<title>IEEE 1284 transfer modes</title>
-<!-- IEEE 1284 transfer modes -->
-
-<para>Stacked on top of the sharing mechanism, but still in the
-<filename>parport</filename> module, are functions for transferring
-data.  They are provided for the device drivers to use, and are very
-much like library routines.  Since these transfer functions are
-provided by the generic <filename>parport</filename> core they must
-use the <quote>lowest common denominator</quote> set of access
-functions: they can set the control lines, examine the status lines,
-and use the data lines.  With some parallel ports the data lines can
-only be set and not examined, and with other ports accessing the data
-register causes control line activity; with these types of situations,
-the IEEE 1284 transfer functions make a best effort attempt to do the
-right thing.  In some cases, it is not physically possible to use
-particular IEEE 1284 transfer modes.</para>
-
-<para>The low-level <filename>parport</filename> drivers also provide
-IEEE 1284 transfer functions, as names in the access function list.
-The low-level driver can just name the generic IEEE 1284 transfer
-functions for this.  Some parallel ports can do IEEE 1284 transfers in
-hardware; for those ports, the low-level driver can provide functions
-to utilise that feature.</para>
-
-</sect1>
-
-<!-- muxes? -->
-
-<!-- pardevices and pardrivers -->
-
-<sect1>
-<title>Pardevices and parport_drivers</title>
-
-<para>When a parallel port device driver (such as
-<filename>lp</filename>) initialises it tells the sharing layer about
-itself using <function>parport_register_driver</function>.  The
-information is put into a <structname>struct
-parport_driver</structname>, which is put into a linked list.  The
-information in a <structname>struct parport_driver</structname> really
-just amounts to some function pointers to callbacks in the parallel
-port device driver.</para>
-
-<para>During its initialisation, a low-level port driver tells the
-sharing layer about all the ports that it has found (using
-<function>parport_register_port</function>), and the sharing layer
-creates a <structname>struct parport</structname> for each of them.
-Each <structname>struct parport</structname> contains (among other
-things) a pointer to a <structname>struct
-parport_operations</structname>, which is a list of function pointers
-for the various operations that can be performed on a port.  You can
-think of a <structname>struct parport</structname> as a parallel port
-<quote>object</quote>, if <quote>object-orientated</quote> programming
-is your thing.  The <structname>parport</structname> structures are
-chained in a linked list, whose head is <varname>portlist</varname>
-(in <filename>drivers/parport/share.c</filename>).</para>
-
-<para>Once the port has been registered, the low-level port driver
-announces it.  The <function>parport_announce_port</function> function
-walks down the list of parallel port device drivers
-(<structname>struct parport_driver</structname>s) calling the
-<function>attach</function> function of each.</para>
-
-<para>Similarly, a low-level port driver can undo the effect of
-registering a port with the
-<function>parport_unregister_port</function> function, and device
-drivers are notified using the <function>detach</function>
-callback.</para>
-
-<para>Device drivers can undo the effect of registering themselves
-with the <function>parport_unregister_driver</function>
-function.</para>
-
-</sect1>
-
-<!-- IEEE 1284.3 API -->
-
-<sect1>
-<title>The IEEE 1284.3 API</title>
-
-<para>The ability to daisy-chain devices is very useful, but if every
-device does it in a different way it could lead to lots of
-complications for device driver writers.  Fortunately, the IEEE are
-standardising it in IEEE 1284.3, which covers daisy-chain devices and
-port multiplexors.</para>
-
-<para>At the time of writing, IEEE 1284.3 has not been published, but
-the draft specifies the on-the-wire protocol for daisy-chaining and
-multiplexing, and also suggests a programming interface for using it.
-That interface (or most of it) has been implemented in the
-<filename>parport</filename> code in Linux.</para>
-
-<para>At initialisation of the parallel port <quote>bus</quote>, daisy-chained
-devices are assigned addresses starting from zero.  There can only be
-four devices with daisy-chain addresses, plus one device on the end
-that doesn't know about daisy-chaining and thinks it's connected
-directly to a computer.</para>
-
-<para>Another way of connecting more parallel port devices is to use a
-multiplexor.  The idea is to have a device that is connected directly
-to a parallel port on a computer, but has a number of parallel ports
-on the other side for other peripherals to connect to (two or four
-ports are allowed).  The multiplexor switches control to different
-ports under software control---it is, in effect, a programmable
-printer switch.</para>
-
-<para>Combining the ability of daisy-chaining five devices together
-with the ability to multiplex one parallel port between four gives the
-potential to have twenty peripherals connected to the same parallel
-port!</para>
-
-<para>In addition, of course, a single computer can have multiple
-parallel ports.  So, each parallel port peripheral in the system can
-be identified with three numbers, or co-ordinates: the parallel port,
-the multiplexed port, and the daisy-chain address.</para>
-
-<mediaobject>
-<imageobject>
-<imagedata align=center scalefit=1 fileref="parport-multi.eps">
-</imageobject>
-</mediaobject>
-
-<!-- x parport_open -->
-<!-- x parport_close -->
-<!-- x parport_device_id -->
-<!-- x parport_device_num -->
-<!-- x parport_device_coords -->
-<!-- x parport_find_device -->
-<!-- x parport_find_class -->
-
-<para>Each device in the system is numbered at initialisation (by
-<function>parport_daisy_init</function>).  You can convert between
-this device number and its co-ordinates with
-<function>parport_device_num</function> and
-<function>parport_device_coords</function>.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_device_num</function></funcdef>
-  <paramdef>int <parameter>parport</parameter></paramdef>
-  <paramdef>int <parameter>mux</parameter></paramdef>
-  <paramdef>int <parameter>daisy</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_device_coords</function></funcdef>
-  <paramdef>int <parameter>devnum</parameter></paramdef>
-  <paramdef>int *<parameter>parport</parameter></paramdef>
-  <paramdef>int *<parameter>mux</parameter></paramdef>
-  <paramdef>int *<parameter>daisy</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>Any parallel port peripheral will be connected directly or
-indirectly to a parallel port on the system, but it won't have a
-daisy-chain address if it does not know about daisy-chaining, and it
-won't be connected through a multiplexor port if there is no
-multiplexor.  The special co-ordinate value <constant>-1</constant> is
-used to indicate these cases.</para>
-
-<para>Two functions are provided for finding devices based on their
-IEEE 1284 Device ID: <function>parport_find_device</function> and
-<function>parport_find_class</function>.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_find_device</function></funcdef>
-  <paramdef>const char *<parameter>mfg</parameter></paramdef>
-  <paramdef>const char *<parameter>mdl</parameter></paramdef>
-  <paramdef>int <parameter>from</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_find_class</function></funcdef>
-  <paramdef>parport_device_class <parameter>cls</parameter></paramdef>
-  <paramdef>int <parameter>from</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>These functions take a device number (in addition to some other
-things), and return another device number.  They walk through the list
-of detected devices until they find one that matches the requirements,
-and then return that device number (or <constant>-1</constant> if
-there are no more such devices).  They start their search at the
-device after the one in the list with the number given (at
-<parameter>from</parameter>+1, in other words).</para>
-
-</sect1>
-
-</chapter>
-
-<chapter id="drivers">
-<title>Device driver's view</title>
-
-<!-- Cover:
-     - sharing interface, preemption, interrupts, wakeups...
-     - IEEE 1284.3 interface
-     - port operations
-       - why can read data but ctr is faked, etc.
-  -->
-
-<!-- I should take a look at the kernel hackers' guide bit I wrote, -->
-<!-- as that deals with a lot of this.  The main complaint with it  -->
-<!-- was that there weren't enough examples, but 'The printer -->
-<!-- driver' should deal with that later; might be worth mentioning -->
-<!-- in the text. -->
-
-<para>This section is written from the point of view of the device
-driver programmer, who might be writing a driver for a printer or a
-scanner or else anything that plugs into the parallel port.  It
-explains how to use the <filename>parport</filename> interface to find
-parallel ports, use them, and share them with other device
-drivers.</para>
-
-<para>We'll start out with a description of the various functions that
-can be called, and then look at a reasonably simple example of their
-use: the printer driver.</para>
-
-<para>The interactions between the device driver and the
-<filename>parport</filename> layer are as follows.  First, the device
-driver registers its existence with <filename>parport</filename>, in
-order to get told about any parallel ports that have been (or will be)
-detected.  When it gets told about a parallel port, it then tells
-<filename>parport</filename> that it wants to drive a device on that
-port.  Thereafter it can claim exclusive access to the port in order
-to talk to its device.</para>
-
-<para>So, the first thing for the device driver to do is tell
-<filename>parport</filename> that it wants to know what parallel ports
-are on the system.  To do this, it uses the
-<function>parport_register_device</function> function:</para>
-
-<programlisting>
-<![CDATA[
-struct parport_driver {
-        const char *name;
-        void (*attach) (struct parport *);
-        void (*detach) (struct parport *);
-        struct parport_driver *next;
-};
-]]></programlisting>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_register_driver</function></funcdef>
-  <paramdef>struct parport_driver *<parameter>driver</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>In other words, the device driver passes pointers to a couple of
-functions to <filename>parport</filename>, and
-<filename>parport</filename> calls <function>attach</function> for
-each port that's detected (and <function>detach</function> for each
-port that disappears -- yes, this can happen).</para>
-
-<para>The next thing that happens is that the device driver tells
-<filename>parport</filename> that it thinks there's a device on the
-port that it can drive.  This typically will happen in the driver's
-<function>attach</function> function, and is done with
-<function>parport_register_device</function>:</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
-  <paramdef>struct parport *<parameter>port</parameter></paramdef>
-  <paramdef>const char *<parameter>name</parameter></paramdef>
-  <paramdef>int <parameter>(*pf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>void <parameter>(*kf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>void <parameter>(*irq_func)</parameter>
-    <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
-  <paramdef>int <parameter>flags</parameter></paramdef>
-  <paramdef>void *<parameter>handle</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>The <parameter>port</parameter> comes from the parameter supplied
-to the <function>attach</function> function when it is called, or
-alternatively can be found from the list of detected parallel ports
-directly with the (now deprecated)
-<function>parport_enumerate</function> function.</para>
-
-<para>The next three parameters, <parameter>pf</parameter>,
-<parameter>kf</parameter>, and <parameter>irq_func</parameter>, are
-more function pointers.  These callback functions get called under
-various circumstances, and are always given the
-<parameter>handle</parameter> as one of their parameters.</para>
-
-<para>The preemption callback, <parameter>pf</parameter>, is called
-when the driver has claimed access to the port but another device
-driver wants access.  If the driver is willing to let the port go, it
-should return zero and the port will be released on its behalf.  There
-is no need to call <function>parport_release</function>.  If
-<parameter>pf</parameter> gets called at a bad time for letting the
-port go, it should return non-zero and no action will be taken.  It is
-good manners for the driver to try to release the port at the earliest
-opportunity after its preemption callback is called.</para>
-
-<para>The <quote>kick</quote> callback, <parameter>kf</parameter>, is
-called when the port can be claimed for exclusive access; that is,
-<function>parport_claim</function> is guaranteed to succeed inside the
-<quote>kick</quote> callback.  If the driver wants to claim the port
-it should do so; otherwise, it need not take any action.</para>
-
-<para>The <parameter>irq_func</parameter> callback is called,
-predictably, when a parallel port interrupt is generated.  But it is
-not the only code that hooks on the interrupt.  The sequence is this:
-the lowlevel driver is the one that has done
-<function>request_irq</function>; it then does whatever
-hardware-specific things it needs to do to the parallel port hardware
-(for PC-style ports, there is nothing special to do); it then tells
-the IEEE 1284 code about the interrupt, which may involve reacting to
-an IEEE 1284 event, depending on the current IEEE 1284 phase; and
-finally the <parameter>irq_func</parameter> function is called.</para>
-
-<para>None of the callback functions are allowed to block.</para>
-
-<para>The <parameter>flags</parameter> are for telling
-<filename>parport</filename> any requirements or hints that are
-useful.  The only useful value here (other than
-<constant>0</constant>, which is the usual value) is
-<constant>PARPORT_DEV_EXCL</constant>.  The point of that flag is to
-request exclusive access at all times---once a driver has successfully
-called <function>parport_register_device</function> with that flag, no
-other device drivers will be able to register devices on that port
-(until the successful driver deregisters its device, of
-course).</para>
-
-<para>The <constant>PARPORT_DEV_EXCL</constant> flag is for preventing
-port sharing, and so should only be used when sharing the port with
-other device drivers is impossible and would lead to incorrect
-behaviour.  Use it sparingly!</para>
-
-<para>Devices can also be registered by device drivers based on their
-device numbers (the same device numbers as in the previous
-section).</para>
-
-<para>The <function>parport_open</function> function is similar to
-<function>parport_register_device</function>, and
-<function>parport_close</function> is the equivalent of
-<function>parport_unregister_device</function>.  The difference is
-that <function>parport_open</function> takes a device number rather
-than a pointer to a <structname>struct parport</structname>.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>struct pardevice *<function>parport_open</function></funcdef>
-  <paramdef>int <parameter>devnum</parameter></paramdef>
-  <paramdef>int <parameter>(*pf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>int <parameter>(*kf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>int <parameter>(*irqf)</parameter>
-    <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
-  <paramdef>int <parameter>flags</parameter></paramdef>
-  <paramdef>void *<parameter>handle</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>void <function>parport_close</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
-  <paramdef>struct parport *<parameter>port</parameter></paramdef>
-  <paramdef>const char *<parameter>name</parameter></paramdef>
-  <paramdef>int <parameter>(*pf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>int <parameter>(*kf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>int <parameter>(*irqf)</parameter>
-    <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
-  <paramdef>int <parameter>flags</parameter></paramdef>
-  <paramdef>void *<parameter>handle</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>void <function>parport_unregister_device</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>The intended use of these functions is during driver
-initialisation while the driver looks for devices that it supports, as
-demonstrated by the following code fragment:</para>
-
-<programlisting>
-<![CDATA[
-int devnum = -1;
-while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM,
-                                     devnum)) != -1) {
-    struct pardevice *dev = parport_open (devnum, ...);
-    ...
-}
-]]></programlisting>
-
-<para>Once your device driver has registered its device and been
-handed a pointer to a <structname>struct pardevice</structname>, the
-next thing you are likely to want to do is communicate with the device
-you think is there.  To do that you'll need to claim access to the
-port.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_claim</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_claim_or_block</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>void <function>parport_release</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>To claim access to the port, use
-<function>parport_claim</function> or
-<function>parport_claim_or_block</function>.  The first of these will
-not block, and so can be used from interrupt context.  If
-<function>parport_claim</function> succeeds it will return zero and
-the port is available to use.  It may fail (returning non-zero) if the
-port is in use by another driver and that driver is not willing to
-relinquish control of the port.</para>
-
-<para>The other function, <function>parport_claim_or_block</function>,
-will block if necessary to wait for the port to be free.  If it slept,
-it returns <constant>1</constant>; if it succeeded without needing to
-sleep it returns <constant>0</constant>.  If it fails it will return a
-negative error code.</para>
-
-<para>When you have finished communicating with the device, you can
-give up access to the port so that other drivers can communicate with
-their devices.  The <function>parport_release</function> function
-cannot fail, but it should not be called without the port claimed.
-Similarly, you should not try to claim the port if you already have it
-claimed.</para>
-
-<para>You may find that although there are convenient points for your
-driver to relinquish the parallel port and allow other drivers to talk
-to their devices, it would be preferable to keep hold of the port.
-The printer driver only needs the port when there is data to print,
-for example, but a network driver (such as PLIP) could be sent a
-remote packet at any time.  With PLIP, it is no huge catastrophe if a
-network packet is dropped, since it will likely be sent again, so it
-is possible for that kind of driver to share the port with other
-(pass-through) devices.</para>
-
-<para>The <function>parport_yield</function> and
-<function>parport_yield_blocking</function> functions are for marking
-points in the driver at which other drivers may claim the port and use
-their devices.  Yielding the port is similar to releasing it and
-reclaiming it, but it more efficient because nothing is done if there
-are no other devices needing the port.  In fact, nothing is done even
-if there are other devices waiting but the current device is still
-within its <quote>timeslice</quote>.  The default timeslice is half a
-second, but it can be adjusted via a <filename>/proc</filename>
-entry.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_yield</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_yield_blocking</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>The first of these, <function>parport_yield</function>, will not
-block but as a result may fail.  The return value for
-<function>parport_yield</function> is the same as for
-<function>parport_claim</function>.  The blocking version,
-<function>parport_yield_blocking</function>, has the same return code
-as <function>parport_claim_or_block</function>.</para>
-
-<para>Once the port has been claimed, the device driver can use the
-functions in the <structname>struct parport_operations</structname>
-pointer in the <structname>struct parport</structname> it has a
-pointer to.  For example:</para>
-
-<programlisting>
-<![CDATA[
-port->ops->write_data (port, d);
-]]></programlisting>
-
-<para>Some of these operations have <quote>shortcuts</quote>.  For
-instance, <function>parport_write_data</function> is equivalent to the
-above, but may be a little bit faster (it's a macro that in some cases
-can avoid needing to indirect through <varname>port</varname> and
-<varname>ops</varname>).</para>
-
-</chapter>
-
-<chapter id="portdrivers">
-<title>Port drivers</title>
-
-<!-- What port drivers are for (i.e. implementing parport objects). -->
-
-<para>To recap, then:</para>
-
-<itemizedlist spacing=compact>
-
-<listitem>
-<para>
-The device driver registers itself with <filename>parport</filename>.
-</para>
-</listitem>
-
-<listitem>
-<para>
-A low-level driver finds a parallel port and registers it with
-<filename>parport</filename> (these first two things can happen in
-either order).  This registration creates a <structname>struct
-parport</structname> which is linked onto a list of known ports.
-</para>
-</listitem>
-
-<listitem>
-<para>
-<filename>parport</filename> calls the <function>attach</function>
-function of each registered device driver, passing it the pointer to
-the new <structname>struct parport</structname>.
-</para>
-</listitem>
-
-<listitem>
-<para>
-The device driver gets a handle from <filename>parport</filename>, for
-use with
-<function>parport_claim</function>/<function>release</function>.  This
-handle takes the form of a pointer to a <structname>struct
-pardevice</structname>, representing a particular device on the
-parallel port, and is acquired using
-<function>parport_register_device</function>.
-</para>
-</listitem>
-
-<listitem>
-<para>
-The device driver claims the port using
-<function>parport_claim</function> (or
-<function>function_claim_or_block</function>).
-</para>
-</listitem>
-
-<listitem>
-<para>
-Then it goes ahead and uses the port.  When finished it releases the
-port.
-</para>
-</listitem>
-
-</itemizedlist>
-
-<para>The purpose of the low-level drivers, then, is to detect
-parallel ports and provide methods of accessing them
-(i.e. implementing the operations in <structname>struct
-parport_operations</structname>).</para>
-
-<!-- Interaction with sharing engine; port state -->
-<!-- What did I mean by that? -->
-
-<!-- Talk about parport_pc implementation, and contrast with e.g. amiga -->
-
-<para>A more complete description of which operation is supposed to do
-what is available in
-<filename>Documentation/parport-lowlevel.txt</filename>.</para>
-
-</chapter>
-
-<chapter id="lp">
-<title>The printer driver</title>
-
-<!-- Talk the reader through the printer driver. -->
-<!-- Could even talk about parallel port console here. -->
-
-<para>The printer driver, <filename>lp</filename> is a character
-special device driver and a <filename>parport</filename> client.  As a
-character special device driver it registers a <structname>struct
-file_operations</structname> using
-<function>register_chrdev</function>, with pointers filled in for
-<structfield>write</structfield>, <structfield>ioctl</structfield>,
-<structfield>open</structfield> and
-<structfield>release</structfield>.  As a client of
-<filename>parport</filename>, it registers a <structname>struct
-parport_driver</structname> using
-<function>parport_register_driver</function>, so that
-<filename>parport</filename> knows to call
-<function>lp_attach</function> when a new parallel port is discovered
-(and <function>lp_detach</function> when it goes away).</para>
-
-<para>The parallel port console functionality is also implemented in
-<filename>lp.c</filename>, but that won't be covered here (it's quite
-simple though).</para>
-
-<para>The initialisation of the driver is quite easy to understand
-(see <function>lp_init</function>).  The <varname>lp_table</varname>
-is an array of structures that contain information about a specific
-device (the <structname>struct pardevice</structname> associated with
-it, for example).  That array is initialised to sensible values first
-of all.</para>
-
-<para>Next, the printer driver calls
-<function>register_chrdev</function> passing it a pointer to
-<varname>lp_fops</varname>, which contains function pointers for the
-printer driver's implementation of <function>open</function>,
-<function>write</function>, and so on.  This part is the same as for
-any character special device driver.</para>
-
-<para>After successfully registering itself as a character special
-device driver, the printer driver registers itself as a
-<filename>parport</filename> client using
-<function>parport_register_driver</function>.  It passes a pointer to
-this structure:</para>
-
-<programlisting>
-<![CDATA[
-static struct parport_driver lp_driver = {
-        "lp",
-        lp_attach,
-        lp_detach,
-        NULL
-};
-]]></programlisting>
-
-<para>The <function>lp_detach</function> function is not very
-interesting (it does nothing); the interesting bit is
-<function>lp_attach</function>.  What goes on here depends on whether
-the user supplied any parameters.  The possibilities are: no
-parameters supplied, in which case the printer driver uses every port
-that is detected; the user supplied the parameter <quote>auto</quote>,
-in which case only ports on which the device ID string indicates a
-printer is present are used; or the user supplied a list of parallel
-port numbers to try, in which case only those are used.</para>
-
-<para>For each port that the printer driver wants to use (see
-<function>lp_register</function>), it calls
-<function>parport_register_device</function> and stores the resulting
-<structname>struct pardevice</structname> pointer in the
-<varname>lp_table</varname>.  If the user told it to do so, it then
-resets the printer.</para>
-
-<para>The other interesting piece of the printer driver, from the
-point of view of <filename>parport</filename>, is
-<function>lp_write</function>.  In this function, the user space
-process has data that it wants printed, and the printer driver hands
-it off to the <filename>parport</filename> code to deal with.</para>
-
-<para>The <filename>parport</filename> functions it uses that we have
-not seen yet are <function>parport_negotiate</function>,
-<function>parport_set_timeout</function>, and
-<function>parport_write</function>.  These functions are part of the
-IEEE 1284 implementation.</para>
-
-<para>The way the IEEE 1284 protocol works is that the host tells the
-peripheral what transfer mode it would like to use, and the peripheral
-either accepts that mode or rejects it; if the mode is rejected, the
-host can try again with a different mode.  This is the negotation
-phase.  Once the peripheral has accepted a particular transfer mode,
-data transfer can begin that mode.</para>
-
-<para>The particular transfer mode that the printer driver wants to
-use is named in IEEE 1284 as <quote>compatibility</quote> mode, and
-the function to request a particular mode is called
-<function>parport_negotiate</function>.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_negotiate</function></funcdef>
-  <paramdef>struct parport *<parameter>port</parameter></paramdef>
-  <paramdef>int <parameter>mode</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>The <parameter>modes</parameter> parameter is a symbolic
-constant representing an IEEE 1284 mode; in this instance, it is
-<constant>IEEE1284_MODE_COMPAT</constant>. (Compatibility mode is
-slightly different to the other modes---rather than being specifically
-requested, it is the default until another mode is selected.)</para>
-
-<para>Back to <function>lp_write</function> then.  First, access to
-the parallel port is secured with
-<function>parport_claim_or_block</function>.  At this point the driver
-might sleep, waiting for another driver (perhaps a Zip drive driver,
-for instance) to let the port go.  Next, it goes to compatibility mode
-using <function>parport_negotiate</function>.</para>
-
-<para>The main work is done in the write-loop.  In particular, the
-line that hands the data over to <filename>parport</filename>
-reads:</para>
-
-<programlisting>
-<![CDATA[
-        written = parport_write (port, kbuf, copy_size);
-]]></programlisting>
-
-<para>The <function>parport_write</function> function writes data to
-the peripheral using the currently selected transfer mode
-(compatibility mode, in this case).  It returns the number of bytes
-successfully written:</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>ssize_t <function>parport_write</function></funcdef>
-  <paramdef>struct parport *<parameter>port</parameter></paramdef>
-  <paramdef>const void *<parameter>buf</parameter></paramdef>
-  <paramdef>size_t <parameter>len</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>ssize_t <function>parport_read</function></funcdef>
-  <paramdef>struct parport *<parameter>port</parameter></paramdef>
-  <paramdef>void *<parameter>buf</parameter></paramdef>
-  <paramdef>size_t <parameter>len</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>(<function>parport_read</function> does what it sounds like, but
-only works for modes in which reverse transfer is possible.  Of
-course, <function>parport_write</function> only works in modes in
-which forward transfer is possible, too.)</para>
-
-<para>The <parameter>buf</parameter> pointer should be to kernel space
-memory, and obviously the <parameter>len</parameter> parameter
-specifies the amount of data to transfer.</para>
-
-<para>In fact what <function>parport_write</function> does is call the
-appropriate block transfer function from the <structname>struct
-parport_operations</structname>:</para>
-
-<programlisting>
-<![CDATA[
-struct parport_operations {
-        [...]
-
-        /* Block read/write */
-        size_t (*epp_write_data) (struct parport *port, const void *buf,
-                                  size_t len, int flags);
-        size_t (*epp_read_data) (struct parport *port, void *buf, size_t len,
-                                 int flags);
-        size_t (*epp_write_addr) (struct parport *port, const void *buf,
-                                  size_t len, int flags);
-        size_t (*epp_read_addr) (struct parport *port, void *buf, size_t len,
-                                 int flags);
-
-        size_t (*ecp_write_data) (struct parport *port, const void *buf,
-                                  size_t len, int flags);
-        size_t (*ecp_read_data) (struct parport *port, void *buf, size_t len,
-                                 int flags);
-        size_t (*ecp_write_addr) (struct parport *port, const void *buf,
-                                  size_t len, int flags);
-
-        size_t (*compat_write_data) (struct parport *port, const void *buf,
-                                     size_t len, int flags);
-        size_t (*nibble_read_data) (struct parport *port, void *buf,
-                                    size_t len, int flags);
-        size_t (*byte_read_data) (struct parport *port, void *buf,
-                                  size_t len, int flags);
-};
-]]></programlisting>
-
-<para>The transfer code in <filename>parport</filename> will tolerate
-a data transfer stall only for so long, and this timeout can be
-specified with <function>parport_set_timeout</function>, which returns
-the previous timeout:</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>long <function>parport_set_timeout</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-  <paramdef>long <parameter>inactivity</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>This timeout is specific to the device, and is restored on
-<function>parport_claim</function>.</para>
-
-</chapter>
-
-<chapter id="ppdev">
-<title>User-level device drivers</title>
-
-<!-- ppdev -->
-<sect1>
-<title>Introduction to ppdev</title>
-
-<para>The printer is accessible through <filename>/dev/lp0</filename>;
-in the same way, the parallel port itself is accessible through
-<filename>/dev/parport0</filename>.  The difference is in the level of
-control that you have over the wires in the parallel port
-cable.</para>
-
-<para>With the printer driver, a user-space program (such as the
-printer spooler) can send bytes in <quote>printer protocol</quote>.
-Briefly, this means that for each byte, the eight data lines are set
-up, then a <quote>strobe</quote> line tells the printer to look at the
-data lines, and the printer sets an <quote>acknowledgement</quote>
-line to say that it got the byte.  The printer driver also allows the
-user-space program to read bytes in <quote>nibble mode</quote>, which
-is a way of transferring data from the peripheral to the computer half
-a byte at a time (and so it's quite slow).</para>
-
-<para>In contrast, the <filename>ppdev</filename> driver (accessed via
-<filename>/dev/parport0</filename>) allows you to:</para>
-
-<itemizedlist spacing=compact>
-
-<listitem>
-<para>
-examine status lines,
-</para>
-</listitem>
-
-<listitem>
-<para>
-set control lines,
-</para>
-</listitem>
-
-<listitem>
-<para>
-set/examine data lines (and control the direction of the data lines),
-</para>
-</listitem>
-
-<listitem>
-<para>
-wait for an interrupt (triggered by one of the status lines),
-</para>
-</listitem>
-
-<listitem>
-<para>
-find out how many new interrupts have occurred,
-</para>
-</listitem>
-
-<listitem>
-<para>
-set up a response to an interrupt,
-</para>
-</listitem>
-
-<listitem>
-<para>
-use IEEE 1284 negotiation (for telling peripheral which transfer mode,
-to use)
-</para>
-</listitem>
-
-<listitem>
-<para>
-transfer data using a specified IEEE 1284 mode.
-</para>
-</listitem>
-
-</itemizedlist>
-
-</sect1>
-
-<sect1>
-<title>User-level or kernel-level driver?</title>
-
-<para>The decision of whether to choose to write a kernel-level device
-driver or a user-level device driver depends on several factors.  One
-of the main ones from a practical point of view is speed: kernel-level
-device drivers get to run faster because they are not preemptable,
-unlike user-level applications.</para>
-
-<para>Another factor is ease of development.  It is in general easier
-to write a user-level driver because (a) one wrong move does not
-result in a crashed machine, (b) you have access to user libraries
-(such as the C library), and (c) debugging is easier.</para>
-
-</sect1>
-
-<sect1>
-<title>Programming interface</title>
-
-<para>The <filename>ppdev</filename> interface is largely the same as
-that of other character special devices, in that it supports
-<function>open</function>, <function>close</function>,
-<function>read</function>, <function>write</function>, and
-<function>ioctl</function>.</para>
-
-<sect2>
-<title>Starting and stopping: <function>open</function> and
-<function>close</function></title>
-
-<para>The device node <filename>/dev/parport0</filename> represents
-any device that is connected to <filename>parport0</filename>, the
-first parallel port in the system.  Each time the device node is
-opened, it represents (to the process doing the opening) a different
-device.  It can be opened more than once, but only one instance can
-actually be in control of the parallel port at any time.  A process
-that has opened <filename>/dev/parport0</filename> shares the parallel
-port in the same way as any other device driver.  A user-land driver
-may be sharing the parallel port with in-kernel device drivers as well
-as other user-land drivers.</para>
-</sect2>
-
-<sect2>
-<title>Control: <function>ioctl</function></title>
-
-<para>Most of the control is done, naturally enough, via the
-<function>ioctl</function> call.  Using <function>ioctl</function>,
-the user-land driver can control both the <filename>ppdev</filename>
-driver in the kernel and the physical parallel port itself.  The
-<function>ioctl</function> call takes as parameters a file descriptor
-(the one returned from opening the device node), a command, and
-optionally (a pointer to) some data.</para>
-
-<variablelist>
-<varlistentry><term><constant>PPCLAIM</constant></term>
-<listitem>
-
-<para>Claims access to the port.  As a user-land device driver writer,
-you will need to do this before you are able to actually change the
-state of the parallel port in any way.  Note that some operations only
-affect the <filename>ppdev</filename> driver and not the port, such as
-<constant>PPSETMODE</constant>; they can be performed while access to
-the port is not claimed.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPEXCL</constant></term>
-<listitem>
-
-<para>Instructs the kernel driver to forbid any sharing of the port
-with other drivers, i.e. it requests exclusivity.  The
-<constant>PPEXCL</constant> command is only valid when the port is not
-already claimed for use, and it may mean that the next
-<constant>PPCLAIM</constant> <function>ioctl</function> will fail:
-some other driver may already have registered itself on that
-port.</para>
-
-<para>Most device drivers don't need exclusive access to the port.
-It's only provided in case it is really needed, for example for
-devices where access to the port is required for extensive periods of
-time (many seconds).</para>
-
-<para>Note that the <constant>PPEXCL</constant>
-<function>ioctl</function> doesn't actually claim the port there and
-then---action is deferred until the <constant>PPCLAIM</constant>
-<function>ioctl</function> is performed.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPRELEASE</constant></term>
-<listitem>
-
-<para>Releases the port.  Releasing the port undoes the effect of
-claiming the port.  It allows other device drivers to talk to their
-devices (assuming that there are any).</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPYIELD</constant></term>
-<listitem>
-
-<para>Yields the port to another driver.  This
-<function>ioctl</function> is a kind of short-hand for releasing the
-port and immediately reclaiming it.  It gives other drivers a chance
-to talk to their devices, but afterwards claims the port back.  An
-example of using this would be in a user-land printer driver: once a
-few characters have been written we could give the port to another
-device driver for a while, but if we still have characters to send to
-the printer we would want the port back as soon as possible.</para>
-
-<para>It is important not to claim the parallel port for too long, as
-other device drivers will have no time to service their devices.  If
-your device does not allow for parallel port sharing at all, it is
-better to claim the parallel port exclusively (see
-<constant>PPEXCL</constant>).</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPNEGOT</constant></term>
-<listitem>
-
-<para>Performs IEEE 1284 negotiation into a particular mode.  Briefly,
-negotiation is the method by which the host and the peripheral decide
-on a protocol to use when transferring data.</para>
-
-<para>An IEEE 1284 compliant device will start out in compatibility
-mode, and then the host can negotiate to another mode (such as
-ECP).</para>
-
-<para>The <function>ioctl</function> parameter should be a pointer to
-an <type>int</type>; values for this are in
-<filename>parport.h</filename> and include:</para>
-
-<itemizedlist spacing=compact>
-<listitem><para><constant>IEEE1284_MODE_COMPAT</constant></para></listitem>
-<listitem><para><constant>IEEE1284_MODE_NIBBLE</constant></para></listitem>
-<listitem><para><constant>IEEE1284_MODE_BYTE</constant></para></listitem>
-<listitem><para><constant>IEEE1284_MODE_EPP</constant></para></listitem>
-<listitem><para><constant>IEEE1284_MODE_ECP</constant></para></listitem>
-</itemizedlist>
-
-<para>The <constant>PPNEGOT</constant> <function>ioctl</function>
-actually does two things: it performs the on-the-wire negotiation, and
-it sets the behaviour of subsequent
-<function>read</function>/<function>write</function> calls so that
-they use that mode (but see <constant>PPSETMODE</constant>).</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPSETMODE</constant></term>
-<listitem>
-
-<para>Sets which IEEE 1284 protocol to use for the
-<function>read</function> and <function>write</function> calls.</para>
-
-<para>The <function>ioctl</function> parameter should be a pointer to
-an <type>int</type>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPGETTIME</constant></term>
-<listitem>
-
-<para>Retrieves the time-out value.  The <function>read</function> and
-<function>write</function> calls will time out if the peripheral
-doesn't respond quickly enough.  The <constant>PPGETTIME</constant>
-<function>ioctl</function> retrieves the length of time that the
-peripheral is allowed to have before giving up.</para>
-
-<para>The <function>ioctl</function> parameter should be a pointer to
-a <structname>struct timeval</structname>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPSETTIME</constant></term>
-<listitem>
-
-<para>Sets the time-out.  The <function>ioctl</function> parameter
-should be a pointer to a <structname>struct
-timeval</structname>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPWCONTROL</constant></term>
-<listitem>
-
-<para>Sets the control lines.  The <function>ioctl</function>
-parameter is a pointer to an <type>unsigned char</type>, the bitwise
-OR of the control line values in
-<filename>parport.h</filename>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPRCONTROL</constant></term>
-<listitem>
-
-<para>Returns the last value written to the control register, in the
-form of an <type>unsigned char</type>: each bit corresponds to a
-control line (although some are unused).  The
-<function>ioctl</function> parameter should be a pointer to an
-<type>unsigned char</type>.</para>
-
-<para>This doesn't actually touch the hardware; the last value written
-is remembered in software.  This is because some parallel port
-hardware does not offer read access to the control register.</para>
-
-<para>The control lines bits are defined in
-<filename>parport.h</filename>:</para>
-
-<itemizedlist spacing=compact>
-<listitem><para><constant>PARPORT_CONTROL_STROBE</constant></para></listitem>
-<listitem><para><constant>PARPORT_CONTROL_AUTOFD</constant></para></listitem>
-<listitem><para><constant>PARPORT_CONTROL_SELECT</constant></para></listitem>
-<listitem><para><constant>PARPORT_CONTROL_INIT</constant></para></listitem>
-</itemizedlist>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPFCONTROL</constant></term>
-<listitem>
-
-<para>Frobs the control lines.  Since a common operation is to change
-one of the control signals while leaving the others alone, it would be
-quite inefficient for the user-land driver to have to use
-<constant>PPRCONTROL</constant>, make the change, and then use
-<constant>PPWCONTROL</constant>.  Of course, each driver could
-remember what state the control lines are supposed to be in (they are
-never changed by anything else), but in order to provide
-<constant>PPRCONTROL</constant>, <filename>ppdev</filename> must
-remember the state of the control lines anyway.</para>
-
-<para>The <constant>PPFCONTROL</constant> <function>ioctl</function>
-is for <quote>frobbing</quote> control lines, and is like
-<constant>PPWCONTROL</constant> but acts on a restricted set of
-control lines.  The <function>ioctl</function> parameter is a pointer
-to a <structname>struct ppdev_frob_struct</structname>:</para>
-
-<programlisting>
-<![CDATA[
-struct ppdev_frob_struct {
-        unsigned char mask;
-        unsigned char val;
-};
-]]>
-</programlisting>
-
-<para>The <structfield>mask</structfield> and
-<structfield>val</structfield> fields are bitwise ORs of control line
-names (such as in <constant>PPWCONTROL</constant>).  The operation
-performed by <constant>PPFCONTROL</constant> is:</para>
-
-<programlisting>
-<![CDATA[new_ctr = (old_ctr & ~mask) | val;]]>
-</programlisting>
-
-<para>In other words, the signals named in
-<structfield>mask</structfield> are set to the values in
-<structfield>val</structfield>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPRSTATUS</constant></term>
-<listitem>
-
-<para>Returns an <type>unsigned char</type> containing bits set for
-each status line that is set (for instance,
-<constant>PARPORT_STATUS_BUSY</constant>).  The
-<function>ioctl</function> parameter should be a pointer to an
-<type>unsigned char</type>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPDATADIR</constant></term>
-<listitem>
-
-<para>Controls the data line drivers.  Normally the computer's
-parallel port will drive the data lines, but for byte-wide transfers
-from the peripheral to the host it is useful to turn off those drivers
-and let the peripheral drive the signals. (If the drivers on the
-computer's parallel port are left on when this happens, the port might
-be damaged.)</para>
-
-<para>This is only needed in conjunction with
-<constant>PPWDATA</constant> or <constant>PPRDATA</constant>.</para>
-
-<para>The <function>ioctl</function> parameter is a pointer to an
-<type>int</type>.  If the <type>int</type> is zero, the drivers are
-turned on (forward direction); if non-zero, the drivers are turned off
-(reverse direction).</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPWDATA</constant></term>
-<listitem>
-
-<para>Sets the data lines (if in forward mode).  The
-<function>ioctl</function> parameter is a pointer to an <type>unsigned
-char</type>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPRDATA</constant></term>
-<listitem>
-
-<para>Reads the data lines (if in reverse mode).  The
-<function>ioctl</function> parameter is a pointer to an <type>unsigned
-char</type>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPCLRIRQ</constant></term>
-<listitem>
-
-<para>Clears the interrupt count.  The <filename>ppdev</filename>
-driver keeps a count of interrupts as they are triggered.
-<constant>PPCLRIRQ</constant> stores this count in an
-<type>int</type>, a pointer to which is passed in as the
-<function>ioctl</function> parameter.</para>
-
-<para>In addition, the interrupt count is reset to zero.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPWCTLONIRQ</constant></term>
-<listitem>
-
-<para>Set a trigger response.  Afterwards when an interrupt is
-triggered, the interrupt handler will set the control lines as
-requested.  The <function>ioctl</function> parameter is a pointer to
-an <type>unsigned char</type>, which is interpreted in the same way as
-for <constant>PPWCONTROL</constant>.</para>
-
-<para>The reason for this <function>ioctl</function> is simply speed.
-Without this <function>ioctl</function>, responding to an interrupt
-would start in the interrupt handler, switch context to the user-land
-driver via <function>poll</function> or <function>select</function>,
-and then switch context back to the kernel in order to handle
-<constant>PPWCONTROL</constant>.  Doing the whole lot in the interrupt
-handler is a lot faster.</para>
-
-</listitem></varlistentry>
-
-<!-- PPSETPHASE? -->
-
-</variablelist>
-
-</sect2>
-
-<sect2>
-<title>Transferring data: <function>read</function> and
-<function>write</function></title>
-
-<para>Transferring data using <function>read</function> and
-<function>write</function> is straightforward.  The data is
-transferring using the current IEEE 1284 mode (see the
-<constant>PPSETMODE</constant> <function>ioctl</function>).  For modes
-which can only transfer data in one direction, only the appropriate
-function will work, of course.</para>
-</sect2>
-
-<sect2>
-<title>Waiting for events: <function>poll</function> and
-<function>select</function></title>
-
-<para>The <filename>ppdev</filename> driver provides user-land device
-drivers with the ability to wait for interrupts, and this is done
-using <function>poll</function> (and <function>select</function>,
-which is implemented in terms of <function>poll</function>).</para>
-
-<para>When a user-land device driver wants to wait for an interrupt,
-it sleeps with <function>poll</function>.  When the interrupt arrives,
-<filename>ppdev</filename> wakes it up (with a <quote>read</quote>
-event, although strictly speaking there is nothing to actually
-<function>read</function>).</para>
-
-</sect2>
-
-</sect1>
-
-<sect1>
-<title>Examples</title>
-
-<para>Presented here are two demonstrations of how to write a simple
-printer driver for <filename>ppdev</filename>.  Firstly we will use
-the <function>write</function> function, and after that we will drive
-the control and data lines directly.</para>
-
-<para>The first thing to do is to actually open the device.</para>
-
-<programlisting><![CDATA[
-int drive_printer (const char *name)
-{
-    int fd;
-    int mode; /* We'll need this later. */
-
-    fd = open (name, O_RDWR);
-    if (fd == -1) {
-        perror ("open");
-        return 1;
-    }
-]]></programlisting>
-
-<para>Here <varname>name</varname> should be something along the lines
-of <filename>"/dev/parport0"</filename>. (If you don't have any
-<filename>/dev/parport</filename> files, you can make them with
-<command>mknod</command>; they are character special device nodes with
-major 99.)</para>
-
-<para>In order to do anything with the port we need to claim access to
-it.</para>
-
-<programlisting><![CDATA[
-    if (ioctl (fd, PPCLAIM)) {
-        perror ("PPCLAIM");
-        close (fd);
-        return 1;
-    }
-]]></programlisting>
-
-<para>Our printer driver will copy its input (from
-<varname>stdin</varname>) to the printer, and it can do that it one of
-two ways.  The first way is to hand it all off to the kernel driver,
-with the knowledge that the protocol that the printer speaks is IEEE
-1284's <quote>compatibility</quote> mode.</para>
-
-<programlisting><![CDATA[
-    /* Switch to compatibility mode.  (In fact we don't need
-     * to do this, since we start off in compatibility mode
-     * anyway, but this demonstrates PPNEGOT.)
-    mode = IEEE1284_MODE_COMPAT;
-    if (ioctl (fd, PPNEGOT, &mode)) {
-        perror ("PPNEGOT");
-        close (fd);
-        return 1;
-    }
-
-    for (;;) {
-        char buffer[1000];
-        char *ptr = buffer;
-        size_t got;
-
-        got = read (0 /* stdin */, buffer, 1000);
-        if (got < 0) {
-            perror ("read");
-            close (fd);
-            return 1;
-        }
-
-        if (got == 0)
-            /* End of input */
-            break;
-
-        while (got > 0) {
-            int written = write_printer (fd, ptr, got);
-
-            if (written < 0) {
-                perror ("write");
-                close (fd);
-                return 1;
-            }
-
-            ptr += written;
-            got -= written;
-        }
-    }
-]]></programlisting>
-
-<para>The <function>write_printer</function> function is not pictured
-above.  This is because the main loop that is shown can be used for
-both methods of driving the printer.  Here is one implementation of
-<function>write_printer</function>:</para>
-
-<programlisting><![CDATA[
-ssize_t write_printer (int fd, const void *ptr, size_t count)
-{
-    return write (fd, ptr, count);
-}
-]]></programlisting>
-
-<para>We hand the data to the kernel-level driver (using
-<function>write</function>) and it handles the printer
-protocol.</para>
-
-<para>Now let's do it the hard way!  In this particular example there
-is no practical reason to do anything other than just call
-<function>write</function>, because we know that the printer talks an
-IEEE 1284 protocol.  On the other hand, this particular example does
-not even need a user-land driver since there is already a kernel-level
-one; for the purpose of this discussion, try to imagine that the
-printer speaks a protocol that is not already implemented under
-Linux.</para>
-
-<para>So, here is the alternative implementation of
-<function>write_printer</function> (for brevity, error checking has
-been omitted):</para>
-
-<programlisting><![CDATA[
-ssize_t write_printer (int fd, const void *ptr, size_t count)
-{
-    ssize_t wrote = 0;
-
-    while (wrote < count) {
-        unsigned char status, control, data;
-        unsigned char mask = (PARPORT_STATUS_ERROR
-                              | PARPORT_STATUS_BUSY);
-        unsigned char val = (PARPORT_STATUS_ERROR
-                              | PARPORT_STATUS_BUSY);
-        struct parport_frob_struct frob;
-        struct timespec ts;
-
-        /* Wait for printer to be ready */
-        for (;;) {
-            ioctl (fd, PPRSTATUS, &status);
-
-            if ((status & mask) == val)
-                break;
-
-            ioctl (fd, PPRELEASE);
-            sleep (1);
-            ioctl (fd, PPCLAIM);
-        }
-
-        /* Set the data lines */
-        data = * ((char *) ptr)++;
-        ioctl (fd, PPWDATA, &data);
-
-        /* Delay for a bit */
-        ts.tv_sec = 0;
-        ts.tv_nsec = 1000;
-        nanosleep (&ts, NULL);
-
-        /* Pulse strobe */
-        frob.mask = PARPORT_CONTROL_STROBE;
-        frob.val = PARPORT_CONTROL_STROBE;
-        ioctl (fd, PPFCONTROL, &frob);
-        nanosleep (&ts, NULL);
-
-        /* End the pulse */
-        frob.val = 0;
-        ioctl (fd, PPFCONTROL, &frob);
-        nanosleep (&ts, NULL);
-
-        wrote++;
-    }
-
-    return wrote;
-}
-]]></programlisting>
-
-<para>To show a bit more of the <filename>ppdev</filename> interface,
-here is a small piece of code that is intended to mimic the printer's
-side of printer protocol.</para>
-
-<programlisting><![CDATA[
-  for (;;)
-    {
-      int irqc;
-      int busy = nAck | nFault;
-      int acking = nFault;
-      int ready = Busy | nAck | nFault;
-      char ch;
-
-      /* Set up the control lines when an interrupt happens. */
-      ioctl (fd, PPWCTLONIRQ, &busy);
-
-      /* Now we're ready. */
-      ioctl (fd, PPWCONTROL, &ready);
-
-      /* Wait for an interrupt. */
-      {
-        fd_set rfds;
-        FD_ZERO (&rfds);
-        FD_SET (fd, &rfds);
-        if (!select (fd + 1, &rfds, NULL, NULL, NULL))
-          /* Caught a signal? */
-          continue;
-      }
-
-      /* We are now marked as busy. */
-
-      /* Fetch the data. */
-      ioctl (fd, PPRDATA, &ch);
-
-      /* Clear the interrupt. */
-      ioctl (fd, PPCLRIRQ, &irqc);
-      if (irqc > 1)
-        fprintf (stderr, "Arghh! Missed %d interrupt%s!\n",
-         irqc - 1, irqc == 2 ? "s" : "");
-
-      /* Ack it. */
-      ioctl (fd, PPWCONTROL, &acking);
-      usleep (2);
-      ioctl (fd, PPWCONTROL, &busy);
-
-      putchar (ch);
-    }
-]]></programlisting>
-
-</sect1>
-
-</chapter>
-</book>
\ No newline at end of file
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/DocBook/parportbook.tmpl linux/Documentation/DocBook/parportbook.tmpl
--- v2.3.99-pre3/linux/Documentation/DocBook/parportbook.tmpl	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/DocBook/parportbook.tmpl	Tue Mar 21 14:43:39 2000
@@ -0,0 +1,1747 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="ParportGuide">
+ <bookinfo>
+  <title>The Parallel Port Subsystem</title>
+
+  <authorgroup>
+   <author>
+    <firstname>Tim</firstname>
+    <surname>Waugh</surname>
+    <affiliation>
+     <address>
+      <email>twaugh@redhat.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>1999-2000</year>
+   <holder>Tim Waugh</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>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+<chapter id="design">
+<title>Design goals</title>
+
+<sect1>
+<title>The problems</title>
+
+<!-- Short-comings -->
+<!-- How they are addressed -->
+
+<!-- Short-comings
+     - simplistic lp driver
+     - platform differences
+     - no support for Zip drive pass-through
+     - no support for readback? When did Carsten add it?
+     - more parallel port devices. Figures?
+     - IEEE 1284 transfer modes: no advanced modes
+  -->
+
+<para>The first parallel port support for Linux came with the line
+printer driver, <filename>lp</filename>.  The printer driver is a
+character special device, and (in Linux 2.0) had support for writing,
+via <function>write</function>, and configuration and statistics
+reporting via <function>ioctl</function>.</para>
+
+<para>The printer driver could be used on any computer that had an IBM
+PC-compatible parallel port.  Because some architectures have parallel
+ports that aren't really the same as PC-style ports, other variants of
+the printer driver were written in order to support Amiga and Atari
+parallel ports.</para>
+
+<para>When the Iomega Zip drive was released, and a driver written for
+it, a problem became apparent.  The Zip drive is a parallel port
+device that provides a parallel port of its own---it is designed to
+sit between a computer and an attached printer, with the printer
+plugged into the Zip drive, and the Zip drive plugged into the
+computer.</para>
+
+<para>The problem was that, although printers and Zip drives were both
+supported, for any given port only one could be used at a time.  Only
+one of the two drivers could be present in the kernel at once.  This
+was because of the fact that both drivers wanted to drive the same
+hardware---the parallel port.  When the printer driver initialised, it
+would call the <function>check_region</function> function to make sure
+that the IO region associated with the parallel port was free, and
+then it would call <function>request_region</function> to allocate it.
+The Zip drive used the same mechanism.  Whichever driver initialised
+first would gain exclusive control of the parallel port.</para>
+
+<para>The only way around this problem at the time was to make sure
+that both drivers were available as loadable kernel modules.  To use
+the printer, load the printer driver module; then for the Zip drive,
+unload the printer driver module and load the Zip driver
+module.</para>
+
+<para>The net effect was that printing a document that was stored on a Zip
+drive was a bit of an ordeal, at least if the Zip drive and printer
+shared a parallel port.  A better solution was needed.</para>
+
+<para>Zip drives are not the only devices that presented problems for
+Linux.  There are other devices with pass-through ports, for example
+parallel port CD-ROM drives.  There are also printers that report
+their status textually rather than using simple error pins: sending a
+command to the printer can cause it to report the number of pages that
+it has ever printed, or how much free memory it has, or whether it is
+running out of toner, and so on.  The printer driver didn't originally
+offer any facility for reading back this information (although Carsten
+Gross added nibble mode readback support for kernel 2.2).</para>
+
+<!-- IEEE 1284 transfer modes: no advanced modes --> 
+
+<para>The IEEE has issued a standards document called IEEE 1284, which
+documents existing practice for parallel port communications in a
+variety of modes.  Those modes are: <quote>compatibility</quote>,
+reverse nibble, reverse byte, ECP and EPP.  Newer devices often use
+the more advanced modes of transfer (ECP and EPP).  In Linux 2.0, the
+printer driver only supported <quote>compatibility mode</quote>
+(i.e. normal printer protocol) and reverse nibble mode.</para>
+
+</sect1>
+
+<sect1>
+<title>The solutions</title>
+
+<!-- How they are addressed
+     - sharing model
+     - overview of structure (i.e. port drivers) in 2.2 and 2.3.
+     - IEEE 1284 stuff
+     - whether or not 'platform independence' goal was met
+  -->
+
+<para>The <filename>parport</filename> code in Linux 2.2 was designed
+to meet these problems of architectural differences in parallel ports,
+of port-sharing between devices with pass-through ports, and of lack
+of support for IEEE 1284 transfer modes.</para>
+
+<!-- platform differences -->
+
+<para>There are two layers to the
+<filename>parport</filename> subsystem, only one of which deals
+directly with the hardware.  The other layer deals with sharing and
+IEEE 1284 transfer modes.  In this way, parallel support for a
+particular architecture comes in the form of a module which registers
+itself with the generic sharing layer.</para>
+
+<!-- sharing model -->
+
+<para>The sharing model provided by the <filename>parport</filename>
+subsystem is one of exclusive access.  A device driver, such as the
+printer driver, must ask the <filename>parport</filename> layer for
+access to the port, and can only use the port once access has been
+granted.  When it has finished a <quote>transaction</quote>, it can
+tell the <filename>parport</filename> layer that it may release the
+port for other device drivers to use.</para>
+
+<!-- talk a bit about how drivers can share devices on the same port -->
+
+<para>Devices with pass-through ports all manage to share a parallel
+port with other devices in generally the same way.  The device has a
+latch for each of the pins on its pass-through port.  The normal state
+of affairs is pass-through mode, with the device copying the signal
+lines between its host port and its pass-through port.  When the
+device sees a special signal from the host port, it latches the
+pass-through port so that devices further downstream don't get
+confused by the pass-through device's conversation with the host
+parallel port: the device connected to the pass-through port (and any
+devices connected in turn to it) are effectively cut off from the
+computer.  When the pass-through device has completed its transaction
+with the computer, it enables the pass-through port again.</para>
+
+<mediaobject>
+<imageobject>
+<imagedata Align=center scalefit=1 fileref="parport-share.eps">
+</imageobject>
+</mediaobject>
+
+<para>This technique relies on certain <quote>special signals</quote>
+being invisible to devices that aren't watching for them.  This tends
+to mean only changing the data signals and leaving the control signals
+alone.  IEEE 1284.3 documents a standard protocol for daisy-chaining
+devices together with parallel ports.</para>
+
+<!-- transfer modes -->
+
+<para>Support for standard transfer modes are provided as operations
+that can be performed on a port, along with operations for setting the
+data lines, or the control lines, or reading the status lines.  These
+operations appear to the device driver as function pointers; more
+later.</para>
+
+</sect1>
+
+</chapter>
+
+<chapter id="transfermodes">
+<title>Standard transfer modes</title>
+
+<!-- Defined by IEEE, but in common use (even though there are widely -->
+<!-- varying implementations). -->
+
+<para>The <quote>standard</quote> transfer modes in use over the
+parallel port are <quote>defined</quote> by a document called IEEE
+1284.  It really just codifies existing practice and documents
+protocols (and variations on protocols) that have been in common use
+for quite some time.</para>
+
+<para>The original definitions of which pin did what were set out by
+Centronics Data Computer Corporation, but only the printer-side
+interface signals were specified.</para>
+
+<para>By the early 1980s, IBM's host-side implementation had become
+the most widely used.  New printers emerged that claimed Centronics
+compatibility, but although compatible with Centronics they differed
+from one another in a number of ways.</para>
+
+<para>As a result of this, when IEEE 1284 was published in 1994, all
+that it could really do was document the various protocols that are
+used for printers (there are about six variations on a theme).</para>
+
+<para>In addition to the protocol used to talk to
+Centronics-compatible printers, IEEE 1284 defined other protocols that
+are used for unidirectional peripheral-to-host transfers (reverse
+nibble and reverse byte) and for fast bidirectional transfers (ECP and
+EPP).</para>
+
+</chapter>
+
+<chapter id="structure">
+<title>Structure</title>
+
+<!-- Main structure
+     - sharing core
+     - parports and their IEEE 1284 overrides
+       - IEEE 1284 transfer modes for generic ports
+       - maybe mention muxes here
+     - pardevices
+     - IEEE 1284.3 API
+  -->
+
+<!-- Diagram -->
+
+<mediaobject>
+<imageobject>
+<imagedata Align=Center ScaleFit=1 fileref="parport-structure.eps">
+</imageobject>
+</mediaobject>
+
+<sect1>
+<title>Sharing core</title>
+
+<!-- sharing core -->
+
+<para>At the core of the <filename>parport</filename> subsystem is the
+sharing mechanism (see <filename>drivers/parport/share.c</filename>).
+This module, <filename>parport</filename>, is responsible for
+keeping track of which ports there are in the system, which device
+drivers might be interested in new ports, and whether or not each port
+is available for use (or if not, which driver is currently using
+it).</para>
+
+</sect1>
+
+<sect1>
+<title>Parports and their overrides</title>
+<!-- parports and their overrides -->
+
+<para>The generic <filename>parport</filename> sharing code doesn't
+directly handle the parallel port hardware.  That is done instead by
+<quote>low-level</quote> <filename>parport</filename> drivers.  The
+function of a low-level <filename>parport</filename> driver is to
+detect parallel ports, register them with the sharing code, and
+provide a list of access functions for each port.</para>
+
+<para>The most basic access functions that must be provided are ones
+for examining the status lines, for setting the control lines, and for
+setting the data lines.  There are also access functions for setting
+the direction of the data lines; normally they are in the
+<quote>forward</quote> direction (that is, the computer drives them),
+but some ports allow switching to <quote>reverse</quote> mode (driven
+by the peripheral).  There is an access function for examining the
+data lines once in reverse mode.</para>
+
+</sect1>
+
+<sect1>
+<title>IEEE 1284 transfer modes</title>
+<!-- IEEE 1284 transfer modes -->
+
+<para>Stacked on top of the sharing mechanism, but still in the
+<filename>parport</filename> module, are functions for transferring
+data.  They are provided for the device drivers to use, and are very
+much like library routines.  Since these transfer functions are
+provided by the generic <filename>parport</filename> core they must
+use the <quote>lowest common denominator</quote> set of access
+functions: they can set the control lines, examine the status lines,
+and use the data lines.  With some parallel ports the data lines can
+only be set and not examined, and with other ports accessing the data
+register causes control line activity; with these types of situations,
+the IEEE 1284 transfer functions make a best effort attempt to do the
+right thing.  In some cases, it is not physically possible to use
+particular IEEE 1284 transfer modes.</para>
+
+<para>The low-level <filename>parport</filename> drivers also provide
+IEEE 1284 transfer functions, as names in the access function list.
+The low-level driver can just name the generic IEEE 1284 transfer
+functions for this.  Some parallel ports can do IEEE 1284 transfers in
+hardware; for those ports, the low-level driver can provide functions
+to utilise that feature.</para>
+
+</sect1>
+
+<!-- muxes? -->
+
+<!-- pardevices and pardrivers -->
+
+<sect1>
+<title>Pardevices and parport_drivers</title>
+
+<para>When a parallel port device driver (such as
+<filename>lp</filename>) initialises it tells the sharing layer about
+itself using <function>parport_register_driver</function>.  The
+information is put into a <structname>struct
+parport_driver</structname>, which is put into a linked list.  The
+information in a <structname>struct parport_driver</structname> really
+just amounts to some function pointers to callbacks in the parallel
+port device driver.</para>
+
+<para>During its initialisation, a low-level port driver tells the
+sharing layer about all the ports that it has found (using
+<function>parport_register_port</function>), and the sharing layer
+creates a <structname>struct parport</structname> for each of them.
+Each <structname>struct parport</structname> contains (among other
+things) a pointer to a <structname>struct
+parport_operations</structname>, which is a list of function pointers
+for the various operations that can be performed on a port.  You can
+think of a <structname>struct parport</structname> as a parallel port
+<quote>object</quote>, if <quote>object-orientated</quote> programming
+is your thing.  The <structname>parport</structname> structures are
+chained in a linked list, whose head is <varname>portlist</varname>
+(in <filename>drivers/parport/share.c</filename>).</para>
+
+<para>Once the port has been registered, the low-level port driver
+announces it.  The <function>parport_announce_port</function> function
+walks down the list of parallel port device drivers
+(<structname>struct parport_driver</structname>s) calling the
+<function>attach</function> function of each.</para>
+
+<para>Similarly, a low-level port driver can undo the effect of
+registering a port with the
+<function>parport_unregister_port</function> function, and device
+drivers are notified using the <function>detach</function>
+callback.</para>
+
+<para>Device drivers can undo the effect of registering themselves
+with the <function>parport_unregister_driver</function>
+function.</para>
+
+</sect1>
+
+<!-- IEEE 1284.3 API -->
+
+<sect1>
+<title>The IEEE 1284.3 API</title>
+
+<para>The ability to daisy-chain devices is very useful, but if every
+device does it in a different way it could lead to lots of
+complications for device driver writers.  Fortunately, the IEEE are
+standardising it in IEEE 1284.3, which covers daisy-chain devices and
+port multiplexors.</para>
+
+<para>At the time of writing, IEEE 1284.3 has not been published, but
+the draft specifies the on-the-wire protocol for daisy-chaining and
+multiplexing, and also suggests a programming interface for using it.
+That interface (or most of it) has been implemented in the
+<filename>parport</filename> code in Linux.</para>
+
+<para>At initialisation of the parallel port <quote>bus</quote>, daisy-chained
+devices are assigned addresses starting from zero.  There can only be
+four devices with daisy-chain addresses, plus one device on the end
+that doesn't know about daisy-chaining and thinks it's connected
+directly to a computer.</para>
+
+<para>Another way of connecting more parallel port devices is to use a
+multiplexor.  The idea is to have a device that is connected directly
+to a parallel port on a computer, but has a number of parallel ports
+on the other side for other peripherals to connect to (two or four
+ports are allowed).  The multiplexor switches control to different
+ports under software control---it is, in effect, a programmable
+printer switch.</para>
+
+<para>Combining the ability of daisy-chaining five devices together
+with the ability to multiplex one parallel port between four gives the
+potential to have twenty peripherals connected to the same parallel
+port!</para>
+
+<para>In addition, of course, a single computer can have multiple
+parallel ports.  So, each parallel port peripheral in the system can
+be identified with three numbers, or co-ordinates: the parallel port,
+the multiplexed port, and the daisy-chain address.</para>
+
+<mediaobject>
+<imageobject>
+<imagedata align=center scalefit=1 fileref="parport-multi.eps">
+</imageobject>
+</mediaobject>
+
+<!-- x parport_open -->
+<!-- x parport_close -->
+<!-- x parport_device_id -->
+<!-- x parport_device_num -->
+<!-- x parport_device_coords -->
+<!-- x parport_find_device -->
+<!-- x parport_find_class -->
+
+<para>Each device in the system is numbered at initialisation (by
+<function>parport_daisy_init</function>).  You can convert between
+this device number and its co-ordinates with
+<function>parport_device_num</function> and
+<function>parport_device_coords</function>.</para>
+
+<funcsynopsis><funcprototype>
+  <funcdef>int <function>parport_device_num</function></funcdef>
+  <paramdef>int <parameter>parport</parameter></paramdef>
+  <paramdef>int <parameter>mux</parameter></paramdef>
+  <paramdef>int <parameter>daisy</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<funcsynopsis><funcprototype>
+  <funcdef>int <function>parport_device_coords</function></funcdef>
+  <paramdef>int <parameter>devnum</parameter></paramdef>
+  <paramdef>int *<parameter>parport</parameter></paramdef>
+  <paramdef>int *<parameter>mux</parameter></paramdef>
+  <paramdef>int *<parameter>daisy</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>Any parallel port peripheral will be connected directly or
+indirectly to a parallel port on the system, but it won't have a
+daisy-chain address if it does not know about daisy-chaining, and it
+won't be connected through a multiplexor port if there is no
+multiplexor.  The special co-ordinate value <constant>-1</constant> is
+used to indicate these cases.</para>
+
+<para>Two functions are provided for finding devices based on their
+IEEE 1284 Device ID: <function>parport_find_device</function> and
+<function>parport_find_class</function>.</para>
+
+<funcsynopsis><funcprototype>
+  <funcdef>int <function>parport_find_device</function></funcdef>
+  <paramdef>const char *<parameter>mfg</parameter></paramdef>
+  <paramdef>const char *<parameter>mdl</parameter></paramdef>
+  <paramdef>int <parameter>from</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<funcsynopsis><funcprototype>
+  <funcdef>int <function>parport_find_class</function></funcdef>
+  <paramdef>parport_device_class <parameter>cls</parameter></paramdef>
+  <paramdef>int <parameter>from</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>These functions take a device number (in addition to some other
+things), and return another device number.  They walk through the list
+of detected devices until they find one that matches the requirements,
+and then return that device number (or <constant>-1</constant> if
+there are no more such devices).  They start their search at the
+device after the one in the list with the number given (at
+<parameter>from</parameter>+1, in other words).</para>
+
+</sect1>
+
+</chapter>
+
+<chapter id="drivers">
+<title>Device driver's view</title>
+
+<!-- Cover:
+     - sharing interface, preemption, interrupts, wakeups...
+     - IEEE 1284.3 interface
+     - port operations
+       - why can read data but ctr is faked, etc.
+  -->
+
+<!-- I should take a look at the kernel hackers' guide bit I wrote, -->
+<!-- as that deals with a lot of this.  The main complaint with it  -->
+<!-- was that there weren't enough examples, but 'The printer -->
+<!-- driver' should deal with that later; might be worth mentioning -->
+<!-- in the text. -->
+
+<para>This section is written from the point of view of the device
+driver programmer, who might be writing a driver for a printer or a
+scanner or else anything that plugs into the parallel port.  It
+explains how to use the <filename>parport</filename> interface to find
+parallel ports, use them, and share them with other device
+drivers.</para>
+
+<para>We'll start out with a description of the various functions that
+can be called, and then look at a reasonably simple example of their
+use: the printer driver.</para>
+
+<para>The interactions between the device driver and the
+<filename>parport</filename> layer are as follows.  First, the device
+driver registers its existence with <filename>parport</filename>, in
+order to get told about any parallel ports that have been (or will be)
+detected.  When it gets told about a parallel port, it then tells
+<filename>parport</filename> that it wants to drive a device on that
+port.  Thereafter it can claim exclusive access to the port in order
+to talk to its device.</para>
+
+<para>So, the first thing for the device driver to do is tell
+<filename>parport</filename> that it wants to know what parallel ports
+are on the system.  To do this, it uses the
+<function>parport_register_device</function> function:</para>
+
+<programlisting>
+<![CDATA[
+struct parport_driver {
+        const char *name;
+        void (*attach) (struct parport *);
+        void (*detach) (struct parport *);
+        struct parport_driver *next;
+};
+]]></programlisting>
+
+<funcsynopsis><funcprototype>
+  <funcdef>int <function>parport_register_driver</function></funcdef>
+  <paramdef>struct parport_driver *<parameter>driver</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>In other words, the device driver passes pointers to a couple of
+functions to <filename>parport</filename>, and
+<filename>parport</filename> calls <function>attach</function> for
+each port that's detected (and <function>detach</function> for each
+port that disappears -- yes, this can happen).</para>
+
+<para>The next thing that happens is that the device driver tells
+<filename>parport</filename> that it thinks there's a device on the
+port that it can drive.  This typically will happen in the driver's
+<function>attach</function> function, and is done with
+<function>parport_register_device</function>:</para>
+
+<funcsynopsis><funcprototype>
+  <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
+  <paramdef>struct parport *<parameter>port</parameter></paramdef>
+  <paramdef>const char *<parameter>name</parameter></paramdef>
+  <paramdef>int <parameter>(*pf)</parameter>
+    <funcparams>void *</funcparams></paramdef>
+  <paramdef>void <parameter>(*kf)</parameter>
+    <funcparams>void *</funcparams></paramdef>
+  <paramdef>void <parameter>(*irq_func)</parameter>
+    <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
+  <paramdef>int <parameter>flags</parameter></paramdef>
+  <paramdef>void *<parameter>handle</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>The <parameter>port</parameter> comes from the parameter supplied
+to the <function>attach</function> function when it is called, or
+alternatively can be found from the list of detected parallel ports
+directly with the (now deprecated)
+<function>parport_enumerate</function> function.</para>
+
+<para>The next three parameters, <parameter>pf</parameter>,
+<parameter>kf</parameter>, and <parameter>irq_func</parameter>, are
+more function pointers.  These callback functions get called under
+various circumstances, and are always given the
+<parameter>handle</parameter> as one of their parameters.</para>
+
+<para>The preemption callback, <parameter>pf</parameter>, is called
+when the driver has claimed access to the port but another device
+driver wants access.  If the driver is willing to let the port go, it
+should return zero and the port will be released on its behalf.  There
+is no need to call <function>parport_release</function>.  If
+<parameter>pf</parameter> gets called at a bad time for letting the
+port go, it should return non-zero and no action will be taken.  It is
+good manners for the driver to try to release the port at the earliest
+opportunity after its preemption callback is called.</para>
+
+<para>The <quote>kick</quote> callback, <parameter>kf</parameter>, is
+called when the port can be claimed for exclusive access; that is,
+<function>parport_claim</function> is guaranteed to succeed inside the
+<quote>kick</quote> callback.  If the driver wants to claim the port
+it should do so; otherwise, it need not take any action.</para>
+
+<para>The <parameter>irq_func</parameter> callback is called,
+predictably, when a parallel port interrupt is generated.  But it is
+not the only code that hooks on the interrupt.  The sequence is this:
+the lowlevel driver is the one that has done
+<function>request_irq</function>; it then does whatever
+hardware-specific things it needs to do to the parallel port hardware
+(for PC-style ports, there is nothing special to do); it then tells
+the IEEE 1284 code about the interrupt, which may involve reacting to
+an IEEE 1284 event, depending on the current IEEE 1284 phase; and
+finally the <parameter>irq_func</parameter> function is called.</para>
+
+<para>None of the callback functions are allowed to block.</para>
+
+<para>The <parameter>flags</parameter> are for telling
+<filename>parport</filename> any requirements or hints that are
+useful.  The only useful value here (other than
+<constant>0</constant>, which is the usual value) is
+<constant>PARPORT_DEV_EXCL</constant>.  The point of that flag is to
+request exclusive access at all times---once a driver has successfully
+called <function>parport_register_device</function> with that flag, no
+other device drivers will be able to register devices on that port
+(until the successful driver deregisters its device, of
+course).</para>
+
+<para>The <constant>PARPORT_DEV_EXCL</constant> flag is for preventing
+port sharing, and so should only be used when sharing the port with
+other device drivers is impossible and would lead to incorrect
+behaviour.  Use it sparingly!</para>
+
+<para>Devices can also be registered by device drivers based on their
+device numbers (the same device numbers as in the previous
+section).</para>
+
+<para>The <function>parport_open</function> function is similar to
+<function>parport_register_device</function>, and
+<function>parport_close</function> is the equivalent of
+<function>parport_unregister_device</function>.  The difference is
+that <function>parport_open</function> takes a device number rather
+than a pointer to a <structname>struct parport</structname>.</para>
+
+<funcsynopsis><funcprototype>
+  <funcdef>struct pardevice *<function>parport_open</function></funcdef>
+  <paramdef>int <parameter>devnum</parameter></paramdef>
+  <paramdef>int <parameter>(*pf)</parameter>
+    <funcparams>void *</funcparams></paramdef>
+  <paramdef>int <parameter>(*kf)</parameter>
+    <funcparams>void *</funcparams></paramdef>
+  <paramdef>int <parameter>(*irqf)</parameter>
+    <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
+  <paramdef>int <parameter>flags</parameter></paramdef>
+  <paramdef>void *<parameter>handle</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<funcsynopsis><funcprototype>
+  <funcdef>void <function>parport_close</function></funcdef>
+  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<funcsynopsis><funcprototype>
+  <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
+  <paramdef>struct parport *<parameter>port</parameter></paramdef>
+  <paramdef>const char *<parameter>name</parameter></paramdef>
+  <paramdef>int <parameter>(*pf)</parameter>
+    <funcparams>void *</funcparams></paramdef>
+  <paramdef>int <parameter>(*kf)</parameter>
+    <funcparams>void *</funcparams></paramdef>
+  <paramdef>int <parameter>(*irqf)</parameter>
+    <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
+  <paramdef>int <parameter>flags</parameter></paramdef>
+  <paramdef>void *<parameter>handle</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<funcsynopsis><funcprototype>
+  <funcdef>void <function>parport_unregister_device</function></funcdef>
+  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>The intended use of these functions is during driver
+initialisation while the driver looks for devices that it supports, as
+demonstrated by the following code fragment:</para>
+
+<programlisting>
+<![CDATA[
+int devnum = -1;
+while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM,
+                                     devnum)) != -1) {
+    struct pardevice *dev = parport_open (devnum, ...);
+    ...
+}
+]]></programlisting>
+
+<para>Once your device driver has registered its device and been
+handed a pointer to a <structname>struct pardevice</structname>, the
+next thing you are likely to want to do is communicate with the device
+you think is there.  To do that you'll need to claim access to the
+port.</para>
+
+<funcsynopsis><funcprototype>
+  <funcdef>int <function>parport_claim</function></funcdef>
+  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<funcsynopsis><funcprototype>
+  <funcdef>int <function>parport_claim_or_block</function></funcdef>
+  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<funcsynopsis><funcprototype>
+  <funcdef>void <function>parport_release</function></funcdef>
+  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>To claim access to the port, use
+<function>parport_claim</function> or
+<function>parport_claim_or_block</function>.  The first of these will
+not block, and so can be used from interrupt context.  If
+<function>parport_claim</function> succeeds it will return zero and
+the port is available to use.  It may fail (returning non-zero) if the
+port is in use by another driver and that driver is not willing to
+relinquish control of the port.</para>
+
+<para>The other function, <function>parport_claim_or_block</function>,
+will block if necessary to wait for the port to be free.  If it slept,
+it returns <constant>1</constant>; if it succeeded without needing to
+sleep it returns <constant>0</constant>.  If it fails it will return a
+negative error code.</para>
+
+<para>When you have finished communicating with the device, you can
+give up access to the port so that other drivers can communicate with
+their devices.  The <function>parport_release</function> function
+cannot fail, but it should not be called without the port claimed.
+Similarly, you should not try to claim the port if you already have it
+claimed.</para>
+
+<para>You may find that although there are convenient points for your
+driver to relinquish the parallel port and allow other drivers to talk
+to their devices, it would be preferable to keep hold of the port.
+The printer driver only needs the port when there is data to print,
+for example, but a network driver (such as PLIP) could be sent a
+remote packet at any time.  With PLIP, it is no huge catastrophe if a
+network packet is dropped, since it will likely be sent again, so it
+is possible for that kind of driver to share the port with other
+(pass-through) devices.</para>
+
+<para>The <function>parport_yield</function> and
+<function>parport_yield_blocking</function> functions are for marking
+points in the driver at which other drivers may claim the port and use
+their devices.  Yielding the port is similar to releasing it and
+reclaiming it, but it more efficient because nothing is done if there
+are no other devices needing the port.  In fact, nothing is done even
+if there are other devices waiting but the current device is still
+within its <quote>timeslice</quote>.  The default timeslice is half a
+second, but it can be adjusted via a <filename>/proc</filename>
+entry.</para>
+
+<funcsynopsis><funcprototype>
+  <funcdef>int <function>parport_yield</function></funcdef>
+  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<funcsynopsis><funcprototype>
+  <funcdef>int <function>parport_yield_blocking</function></funcdef>
+  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>The first of these, <function>parport_yield</function>, will not
+block but as a result may fail.  The return value for
+<function>parport_yield</function> is the same as for
+<function>parport_claim</function>.  The blocking version,
+<function>parport_yield_blocking</function>, has the same return code
+as <function>parport_claim_or_block</function>.</para>
+
+<para>Once the port has been claimed, the device driver can use the
+functions in the <structname>struct parport_operations</structname>
+pointer in the <structname>struct parport</structname> it has a
+pointer to.  For example:</para>
+
+<programlisting>
+<![CDATA[
+port->ops->write_data (port, d);
+]]></programlisting>
+
+<para>Some of these operations have <quote>shortcuts</quote>.  For
+instance, <function>parport_write_data</function> is equivalent to the
+above, but may be a little bit faster (it's a macro that in some cases
+can avoid needing to indirect through <varname>port</varname> and
+<varname>ops</varname>).</para>
+
+</chapter>
+
+<chapter id="portdrivers">
+<title>Port drivers</title>
+
+<!-- What port drivers are for (i.e. implementing parport objects). -->
+
+<para>To recap, then:</para>
+
+<itemizedlist spacing=compact>
+
+<listitem>
+<para>
+The device driver registers itself with <filename>parport</filename>.
+</para>
+</listitem>
+
+<listitem>
+<para>
+A low-level driver finds a parallel port and registers it with
+<filename>parport</filename> (these first two things can happen in
+either order).  This registration creates a <structname>struct
+parport</structname> which is linked onto a list of known ports.
+</para>
+</listitem>
+
+<listitem>
+<para>
+<filename>parport</filename> calls the <function>attach</function>
+function of each registered device driver, passing it the pointer to
+the new <structname>struct parport</structname>.
+</para>
+</listitem>
+
+<listitem>
+<para>
+The device driver gets a handle from <filename>parport</filename>, for
+use with
+<function>parport_claim</function>/<function>release</function>.  This
+handle takes the form of a pointer to a <structname>struct
+pardevice</structname>, representing a particular device on the
+parallel port, and is acquired using
+<function>parport_register_device</function>.
+</para>
+</listitem>
+
+<listitem>
+<para>
+The device driver claims the port using
+<function>parport_claim</function> (or
+<function>function_claim_or_block</function>).
+</para>
+</listitem>
+
+<listitem>
+<para>
+Then it goes ahead and uses the port.  When finished it releases the
+port.
+</para>
+</listitem>
+
+</itemizedlist>
+
+<para>The purpose of the low-level drivers, then, is to detect
+parallel ports and provide methods of accessing them
+(i.e. implementing the operations in <structname>struct
+parport_operations</structname>).</para>
+
+<!-- Interaction with sharing engine; port state -->
+<!-- What did I mean by that? -->
+
+<!-- Talk about parport_pc implementation, and contrast with e.g. amiga -->
+
+<para>A more complete description of which operation is supposed to do
+what is available in
+<filename>Documentation/parport-lowlevel.txt</filename>.</para>
+
+</chapter>
+
+<chapter id="lp">
+<title>The printer driver</title>
+
+<!-- Talk the reader through the printer driver. -->
+<!-- Could even talk about parallel port console here. -->
+
+<para>The printer driver, <filename>lp</filename> is a character
+special device driver and a <filename>parport</filename> client.  As a
+character special device driver it registers a <structname>struct
+file_operations</structname> using
+<function>register_chrdev</function>, with pointers filled in for
+<structfield>write</structfield>, <structfield>ioctl</structfield>,
+<structfield>open</structfield> and
+<structfield>release</structfield>.  As a client of
+<filename>parport</filename>, it registers a <structname>struct
+parport_driver</structname> using
+<function>parport_register_driver</function>, so that
+<filename>parport</filename> knows to call
+<function>lp_attach</function> when a new parallel port is discovered
+(and <function>lp_detach</function> when it goes away).</para>
+
+<para>The parallel port console functionality is also implemented in
+<filename>lp.c</filename>, but that won't be covered here (it's quite
+simple though).</para>
+
+<para>The initialisation of the driver is quite easy to understand
+(see <function>lp_init</function>).  The <varname>lp_table</varname>
+is an array of structures that contain information about a specific
+device (the <structname>struct pardevice</structname> associated with
+it, for example).  That array is initialised to sensible values first
+of all.</para>
+
+<para>Next, the printer driver calls
+<function>register_chrdev</function> passing it a pointer to
+<varname>lp_fops</varname>, which contains function pointers for the
+printer driver's implementation of <function>open</function>,
+<function>write</function>, and so on.  This part is the same as for
+any character special device driver.</para>
+
+<para>After successfully registering itself as a character special
+device driver, the printer driver registers itself as a
+<filename>parport</filename> client using
+<function>parport_register_driver</function>.  It passes a pointer to
+this structure:</para>
+
+<programlisting>
+<![CDATA[
+static struct parport_driver lp_driver = {
+        "lp",
+        lp_attach,
+        lp_detach,
+        NULL
+};
+]]></programlisting>
+
+<para>The <function>lp_detach</function> function is not very
+interesting (it does nothing); the interesting bit is
+<function>lp_attach</function>.  What goes on here depends on whether
+the user supplied any parameters.  The possibilities are: no
+parameters supplied, in which case the printer driver uses every port
+that is detected; the user supplied the parameter <quote>auto</quote>,
+in which case only ports on which the device ID string indicates a
+printer is present are used; or the user supplied a list of parallel
+port numbers to try, in which case only those are used.</para>
+
+<para>For each port that the printer driver wants to use (see
+<function>lp_register</function>), it calls
+<function>parport_register_device</function> and stores the resulting
+<structname>struct pardevice</structname> pointer in the
+<varname>lp_table</varname>.  If the user told it to do so, it then
+resets the printer.</para>
+
+<para>The other interesting piece of the printer driver, from the
+point of view of <filename>parport</filename>, is
+<function>lp_write</function>.  In this function, the user space
+process has data that it wants printed, and the printer driver hands
+it off to the <filename>parport</filename> code to deal with.</para>
+
+<para>The <filename>parport</filename> functions it uses that we have
+not seen yet are <function>parport_negotiate</function>,
+<function>parport_set_timeout</function>, and
+<function>parport_write</function>.  These functions are part of the
+IEEE 1284 implementation.</para>
+
+<para>The way the IEEE 1284 protocol works is that the host tells the
+peripheral what transfer mode it would like to use, and the peripheral
+either accepts that mode or rejects it; if the mode is rejected, the
+host can try again with a different mode.  This is the negotation
+phase.  Once the peripheral has accepted a particular transfer mode,
+data transfer can begin that mode.</para>
+
+<para>The particular transfer mode that the printer driver wants to
+use is named in IEEE 1284 as <quote>compatibility</quote> mode, and
+the function to request a particular mode is called
+<function>parport_negotiate</function>.</para>
+
+<funcsynopsis><funcprototype>
+  <funcdef>int <function>parport_negotiate</function></funcdef>
+  <paramdef>struct parport *<parameter>port</parameter></paramdef>
+  <paramdef>int <parameter>mode</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>The <parameter>modes</parameter> parameter is a symbolic
+constant representing an IEEE 1284 mode; in this instance, it is
+<constant>IEEE1284_MODE_COMPAT</constant>. (Compatibility mode is
+slightly different to the other modes---rather than being specifically
+requested, it is the default until another mode is selected.)</para>
+
+<para>Back to <function>lp_write</function> then.  First, access to
+the parallel port is secured with
+<function>parport_claim_or_block</function>.  At this point the driver
+might sleep, waiting for another driver (perhaps a Zip drive driver,
+for instance) to let the port go.  Next, it goes to compatibility mode
+using <function>parport_negotiate</function>.</para>
+
+<para>The main work is done in the write-loop.  In particular, the
+line that hands the data over to <filename>parport</filename>
+reads:</para>
+
+<programlisting>
+<![CDATA[
+        written = parport_write (port, kbuf, copy_size);
+]]></programlisting>
+
+<para>The <function>parport_write</function> function writes data to
+the peripheral using the currently selected transfer mode
+(compatibility mode, in this case).  It returns the number of bytes
+successfully written:</para>
+
+<funcsynopsis><funcprototype>
+  <funcdef>ssize_t <function>parport_write</function></funcdef>
+  <paramdef>struct parport *<parameter>port</parameter></paramdef>
+  <paramdef>const void *<parameter>buf</parameter></paramdef>
+  <paramdef>size_t <parameter>len</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<funcsynopsis><funcprototype>
+  <funcdef>ssize_t <function>parport_read</function></funcdef>
+  <paramdef>struct parport *<parameter>port</parameter></paramdef>
+  <paramdef>void *<parameter>buf</parameter></paramdef>
+  <paramdef>size_t <parameter>len</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>(<function>parport_read</function> does what it sounds like, but
+only works for modes in which reverse transfer is possible.  Of
+course, <function>parport_write</function> only works in modes in
+which forward transfer is possible, too.)</para>
+
+<para>The <parameter>buf</parameter> pointer should be to kernel space
+memory, and obviously the <parameter>len</parameter> parameter
+specifies the amount of data to transfer.</para>
+
+<para>In fact what <function>parport_write</function> does is call the
+appropriate block transfer function from the <structname>struct
+parport_operations</structname>:</para>
+
+<programlisting>
+<![CDATA[
+struct parport_operations {
+        [...]
+
+        /* Block read/write */
+        size_t (*epp_write_data) (struct parport *port, const void *buf,
+                                  size_t len, int flags);
+        size_t (*epp_read_data) (struct parport *port, void *buf, size_t len,
+                                 int flags);
+        size_t (*epp_write_addr) (struct parport *port, const void *buf,
+                                  size_t len, int flags);
+        size_t (*epp_read_addr) (struct parport *port, void *buf, size_t len,
+                                 int flags);
+
+        size_t (*ecp_write_data) (struct parport *port, const void *buf,
+                                  size_t len, int flags);
+        size_t (*ecp_read_data) (struct parport *port, void *buf, size_t len,
+                                 int flags);
+        size_t (*ecp_write_addr) (struct parport *port, const void *buf,
+                                  size_t len, int flags);
+
+        size_t (*compat_write_data) (struct parport *port, const void *buf,
+                                     size_t len, int flags);
+        size_t (*nibble_read_data) (struct parport *port, void *buf,
+                                    size_t len, int flags);
+        size_t (*byte_read_data) (struct parport *port, void *buf,
+                                  size_t len, int flags);
+};
+]]></programlisting>
+
+<para>The transfer code in <filename>parport</filename> will tolerate
+a data transfer stall only for so long, and this timeout can be
+specified with <function>parport_set_timeout</function>, which returns
+the previous timeout:</para>
+
+<funcsynopsis><funcprototype>
+  <funcdef>long <function>parport_set_timeout</function></funcdef>
+  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+  <paramdef>long <parameter>inactivity</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>This timeout is specific to the device, and is restored on
+<function>parport_claim</function>.</para>
+
+</chapter>
+
+<chapter id="ppdev">
+<title>User-level device drivers</title>
+
+<!-- ppdev -->
+<sect1>
+<title>Introduction to ppdev</title>
+
+<para>The printer is accessible through <filename>/dev/lp0</filename>;
+in the same way, the parallel port itself is accessible through
+<filename>/dev/parport0</filename>.  The difference is in the level of
+control that you have over the wires in the parallel port
+cable.</para>
+
+<para>With the printer driver, a user-space program (such as the
+printer spooler) can send bytes in <quote>printer protocol</quote>.
+Briefly, this means that for each byte, the eight data lines are set
+up, then a <quote>strobe</quote> line tells the printer to look at the
+data lines, and the printer sets an <quote>acknowledgement</quote>
+line to say that it got the byte.  The printer driver also allows the
+user-space program to read bytes in <quote>nibble mode</quote>, which
+is a way of transferring data from the peripheral to the computer half
+a byte at a time (and so it's quite slow).</para>
+
+<para>In contrast, the <filename>ppdev</filename> driver (accessed via
+<filename>/dev/parport0</filename>) allows you to:</para>
+
+<itemizedlist spacing=compact>
+
+<listitem>
+<para>
+examine status lines,
+</para>
+</listitem>
+
+<listitem>
+<para>
+set control lines,
+</para>
+</listitem>
+
+<listitem>
+<para>
+set/examine data lines (and control the direction of the data lines),
+</para>
+</listitem>
+
+<listitem>
+<para>
+wait for an interrupt (triggered by one of the status lines),
+</para>
+</listitem>
+
+<listitem>
+<para>
+find out how many new interrupts have occurred,
+</para>
+</listitem>
+
+<listitem>
+<para>
+set up a response to an interrupt,
+</para>
+</listitem>
+
+<listitem>
+<para>
+use IEEE 1284 negotiation (for telling peripheral which transfer mode,
+to use)
+</para>
+</listitem>
+
+<listitem>
+<para>
+transfer data using a specified IEEE 1284 mode.
+</para>
+</listitem>
+
+</itemizedlist>
+
+</sect1>
+
+<sect1>
+<title>User-level or kernel-level driver?</title>
+
+<para>The decision of whether to choose to write a kernel-level device
+driver or a user-level device driver depends on several factors.  One
+of the main ones from a practical point of view is speed: kernel-level
+device drivers get to run faster because they are not preemptable,
+unlike user-level applications.</para>
+
+<para>Another factor is ease of development.  It is in general easier
+to write a user-level driver because (a) one wrong move does not
+result in a crashed machine, (b) you have access to user libraries
+(such as the C library), and (c) debugging is easier.</para>
+
+</sect1>
+
+<sect1>
+<title>Programming interface</title>
+
+<para>The <filename>ppdev</filename> interface is largely the same as
+that of other character special devices, in that it supports
+<function>open</function>, <function>close</function>,
+<function>read</function>, <function>write</function>, and
+<function>ioctl</function>.</para>
+
+<sect2>
+<title>Starting and stopping: <function>open</function> and
+<function>close</function></title>
+
+<para>The device node <filename>/dev/parport0</filename> represents
+any device that is connected to <filename>parport0</filename>, the
+first parallel port in the system.  Each time the device node is
+opened, it represents (to the process doing the opening) a different
+device.  It can be opened more than once, but only one instance can
+actually be in control of the parallel port at any time.  A process
+that has opened <filename>/dev/parport0</filename> shares the parallel
+port in the same way as any other device driver.  A user-land driver
+may be sharing the parallel port with in-kernel device drivers as well
+as other user-land drivers.</para>
+</sect2>
+
+<sect2>
+<title>Control: <function>ioctl</function></title>
+
+<para>Most of the control is done, naturally enough, via the
+<function>ioctl</function> call.  Using <function>ioctl</function>,
+the user-land driver can control both the <filename>ppdev</filename>
+driver in the kernel and the physical parallel port itself.  The
+<function>ioctl</function> call takes as parameters a file descriptor
+(the one returned from opening the device node), a command, and
+optionally (a pointer to) some data.</para>
+
+<variablelist>
+<varlistentry><term><constant>PPCLAIM</constant></term>
+<listitem>
+
+<para>Claims access to the port.  As a user-land device driver writer,
+you will need to do this before you are able to actually change the
+state of the parallel port in any way.  Note that some operations only
+affect the <filename>ppdev</filename> driver and not the port, such as
+<constant>PPSETMODE</constant>; they can be performed while access to
+the port is not claimed.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPEXCL</constant></term>
+<listitem>
+
+<para>Instructs the kernel driver to forbid any sharing of the port
+with other drivers, i.e. it requests exclusivity.  The
+<constant>PPEXCL</constant> command is only valid when the port is not
+already claimed for use, and it may mean that the next
+<constant>PPCLAIM</constant> <function>ioctl</function> will fail:
+some other driver may already have registered itself on that
+port.</para>
+
+<para>Most device drivers don't need exclusive access to the port.
+It's only provided in case it is really needed, for example for
+devices where access to the port is required for extensive periods of
+time (many seconds).</para>
+
+<para>Note that the <constant>PPEXCL</constant>
+<function>ioctl</function> doesn't actually claim the port there and
+then---action is deferred until the <constant>PPCLAIM</constant>
+<function>ioctl</function> is performed.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPRELEASE</constant></term>
+<listitem>
+
+<para>Releases the port.  Releasing the port undoes the effect of
+claiming the port.  It allows other device drivers to talk to their
+devices (assuming that there are any).</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPYIELD</constant></term>
+<listitem>
+
+<para>Yields the port to another driver.  This
+<function>ioctl</function> is a kind of short-hand for releasing the
+port and immediately reclaiming it.  It gives other drivers a chance
+to talk to their devices, but afterwards claims the port back.  An
+example of using this would be in a user-land printer driver: once a
+few characters have been written we could give the port to another
+device driver for a while, but if we still have characters to send to
+the printer we would want the port back as soon as possible.</para>
+
+<para>It is important not to claim the parallel port for too long, as
+other device drivers will have no time to service their devices.  If
+your device does not allow for parallel port sharing at all, it is
+better to claim the parallel port exclusively (see
+<constant>PPEXCL</constant>).</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPNEGOT</constant></term>
+<listitem>
+
+<para>Performs IEEE 1284 negotiation into a particular mode.  Briefly,
+negotiation is the method by which the host and the peripheral decide
+on a protocol to use when transferring data.</para>
+
+<para>An IEEE 1284 compliant device will start out in compatibility
+mode, and then the host can negotiate to another mode (such as
+ECP).</para>
+
+<para>The <function>ioctl</function> parameter should be a pointer to
+an <type>int</type>; values for this are in
+<filename>parport.h</filename> and include:</para>
+
+<itemizedlist spacing=compact>
+<listitem><para><constant>IEEE1284_MODE_COMPAT</constant></para></listitem>
+<listitem><para><constant>IEEE1284_MODE_NIBBLE</constant></para></listitem>
+<listitem><para><constant>IEEE1284_MODE_BYTE</constant></para></listitem>
+<listitem><para><constant>IEEE1284_MODE_EPP</constant></para></listitem>
+<listitem><para><constant>IEEE1284_MODE_ECP</constant></para></listitem>
+</itemizedlist>
+
+<para>The <constant>PPNEGOT</constant> <function>ioctl</function>
+actually does two things: it performs the on-the-wire negotiation, and
+it sets the behaviour of subsequent
+<function>read</function>/<function>write</function> calls so that
+they use that mode (but see <constant>PPSETMODE</constant>).</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPSETMODE</constant></term>
+<listitem>
+
+<para>Sets which IEEE 1284 protocol to use for the
+<function>read</function> and <function>write</function> calls.</para>
+
+<para>The <function>ioctl</function> parameter should be a pointer to
+an <type>int</type>.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPGETTIME</constant></term>
+<listitem>
+
+<para>Retrieves the time-out value.  The <function>read</function> and
+<function>write</function> calls will time out if the peripheral
+doesn't respond quickly enough.  The <constant>PPGETTIME</constant>
+<function>ioctl</function> retrieves the length of time that the
+peripheral is allowed to have before giving up.</para>
+
+<para>The <function>ioctl</function> parameter should be a pointer to
+a <structname>struct timeval</structname>.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPSETTIME</constant></term>
+<listitem>
+
+<para>Sets the time-out.  The <function>ioctl</function> parameter
+should be a pointer to a <structname>struct
+timeval</structname>.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPWCONTROL</constant></term>
+<listitem>
+
+<para>Sets the control lines.  The <function>ioctl</function>
+parameter is a pointer to an <type>unsigned char</type>, the bitwise
+OR of the control line values in
+<filename>parport.h</filename>.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPRCONTROL</constant></term>
+<listitem>
+
+<para>Returns the last value written to the control register, in the
+form of an <type>unsigned char</type>: each bit corresponds to a
+control line (although some are unused).  The
+<function>ioctl</function> parameter should be a pointer to an
+<type>unsigned char</type>.</para>
+
+<para>This doesn't actually touch the hardware; the last value written
+is remembered in software.  This is because some parallel port
+hardware does not offer read access to the control register.</para>
+
+<para>The control lines bits are defined in
+<filename>parport.h</filename>:</para>
+
+<itemizedlist spacing=compact>
+<listitem><para><constant>PARPORT_CONTROL_STROBE</constant></para></listitem>
+<listitem><para><constant>PARPORT_CONTROL_AUTOFD</constant></para></listitem>
+<listitem><para><constant>PARPORT_CONTROL_SELECT</constant></para></listitem>
+<listitem><para><constant>PARPORT_CONTROL_INIT</constant></para></listitem>
+</itemizedlist>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPFCONTROL</constant></term>
+<listitem>
+
+<para>Frobs the control lines.  Since a common operation is to change
+one of the control signals while leaving the others alone, it would be
+quite inefficient for the user-land driver to have to use
+<constant>PPRCONTROL</constant>, make the change, and then use
+<constant>PPWCONTROL</constant>.  Of course, each driver could
+remember what state the control lines are supposed to be in (they are
+never changed by anything else), but in order to provide
+<constant>PPRCONTROL</constant>, <filename>ppdev</filename> must
+remember the state of the control lines anyway.</para>
+
+<para>The <constant>PPFCONTROL</constant> <function>ioctl</function>
+is for <quote>frobbing</quote> control lines, and is like
+<constant>PPWCONTROL</constant> but acts on a restricted set of
+control lines.  The <function>ioctl</function> parameter is a pointer
+to a <structname>struct ppdev_frob_struct</structname>:</para>
+
+<programlisting>
+<![CDATA[
+struct ppdev_frob_struct {
+        unsigned char mask;
+        unsigned char val;
+};
+]]>
+</programlisting>
+
+<para>The <structfield>mask</structfield> and
+<structfield>val</structfield> fields are bitwise ORs of control line
+names (such as in <constant>PPWCONTROL</constant>).  The operation
+performed by <constant>PPFCONTROL</constant> is:</para>
+
+<programlisting>
+<![CDATA[new_ctr = (old_ctr & ~mask) | val;]]>
+</programlisting>
+
+<para>In other words, the signals named in
+<structfield>mask</structfield> are set to the values in
+<structfield>val</structfield>.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPRSTATUS</constant></term>
+<listitem>
+
+<para>Returns an <type>unsigned char</type> containing bits set for
+each status line that is set (for instance,
+<constant>PARPORT_STATUS_BUSY</constant>).  The
+<function>ioctl</function> parameter should be a pointer to an
+<type>unsigned char</type>.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPDATADIR</constant></term>
+<listitem>
+
+<para>Controls the data line drivers.  Normally the computer's
+parallel port will drive the data lines, but for byte-wide transfers
+from the peripheral to the host it is useful to turn off those drivers
+and let the peripheral drive the signals. (If the drivers on the
+computer's parallel port are left on when this happens, the port might
+be damaged.)</para>
+
+<para>This is only needed in conjunction with
+<constant>PPWDATA</constant> or <constant>PPRDATA</constant>.</para>
+
+<para>The <function>ioctl</function> parameter is a pointer to an
+<type>int</type>.  If the <type>int</type> is zero, the drivers are
+turned on (forward direction); if non-zero, the drivers are turned off
+(reverse direction).</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPWDATA</constant></term>
+<listitem>
+
+<para>Sets the data lines (if in forward mode).  The
+<function>ioctl</function> parameter is a pointer to an <type>unsigned
+char</type>.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPRDATA</constant></term>
+<listitem>
+
+<para>Reads the data lines (if in reverse mode).  The
+<function>ioctl</function> parameter is a pointer to an <type>unsigned
+char</type>.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPCLRIRQ</constant></term>
+<listitem>
+
+<para>Clears the interrupt count.  The <filename>ppdev</filename>
+driver keeps a count of interrupts as they are triggered.
+<constant>PPCLRIRQ</constant> stores this count in an
+<type>int</type>, a pointer to which is passed in as the
+<function>ioctl</function> parameter.</para>
+
+<para>In addition, the interrupt count is reset to zero.</para>
+
+</listitem></varlistentry>
+
+<varlistentry><term><constant>PPWCTLONIRQ</constant></term>
+<listitem>
+
+<para>Set a trigger response.  Afterwards when an interrupt is
+triggered, the interrupt handler will set the control lines as
+requested.  The <function>ioctl</function> parameter is a pointer to
+an <type>unsigned char</type>, which is interpreted in the same way as
+for <constant>PPWCONTROL</constant>.</para>
+
+<para>The reason for this <function>ioctl</function> is simply speed.
+Without this <function>ioctl</function>, responding to an interrupt
+would start in the interrupt handler, switch context to the user-land
+driver via <function>poll</function> or <function>select</function>,
+and then switch context back to the kernel in order to handle
+<constant>PPWCONTROL</constant>.  Doing the whole lot in the interrupt
+handler is a lot faster.</para>
+
+</listitem></varlistentry>
+
+<!-- PPSETPHASE? -->
+
+</variablelist>
+
+</sect2>
+
+<sect2>
+<title>Transferring data: <function>read</function> and
+<function>write</function></title>
+
+<para>Transferring data using <function>read</function> and
+<function>write</function> is straightforward.  The data is
+transferring using the current IEEE 1284 mode (see the
+<constant>PPSETMODE</constant> <function>ioctl</function>).  For modes
+which can only transfer data in one direction, only the appropriate
+function will work, of course.</para>
+</sect2>
+
+<sect2>
+<title>Waiting for events: <function>poll</function> and
+<function>select</function></title>
+
+<para>The <filename>ppdev</filename> driver provides user-land device
+drivers with the ability to wait for interrupts, and this is done
+using <function>poll</function> (and <function>select</function>,
+which is implemented in terms of <function>poll</function>).</para>
+
+<para>When a user-land device driver wants to wait for an interrupt,
+it sleeps with <function>poll</function>.  When the interrupt arrives,
+<filename>ppdev</filename> wakes it up (with a <quote>read</quote>
+event, although strictly speaking there is nothing to actually
+<function>read</function>).</para>
+
+</sect2>
+
+</sect1>
+
+<sect1>
+<title>Examples</title>
+
+<para>Presented here are two demonstrations of how to write a simple
+printer driver for <filename>ppdev</filename>.  Firstly we will use
+the <function>write</function> function, and after that we will drive
+the control and data lines directly.</para>
+
+<para>The first thing to do is to actually open the device.</para>
+
+<programlisting><![CDATA[
+int drive_printer (const char *name)
+{
+    int fd;
+    int mode; /* We'll need this later. */
+
+    fd = open (name, O_RDWR);
+    if (fd == -1) {
+        perror ("open");
+        return 1;
+    }
+]]></programlisting>
+
+<para>Here <varname>name</varname> should be something along the lines
+of <filename>"/dev/parport0"</filename>. (If you don't have any
+<filename>/dev/parport</filename> files, you can make them with
+<command>mknod</command>; they are character special device nodes with
+major 99.)</para>
+
+<para>In order to do anything with the port we need to claim access to
+it.</para>
+
+<programlisting><![CDATA[
+    if (ioctl (fd, PPCLAIM)) {
+        perror ("PPCLAIM");
+        close (fd);
+        return 1;
+    }
+]]></programlisting>
+
+<para>Our printer driver will copy its input (from
+<varname>stdin</varname>) to the printer, and it can do that it one of
+two ways.  The first way is to hand it all off to the kernel driver,
+with the knowledge that the protocol that the printer speaks is IEEE
+1284's <quote>compatibility</quote> mode.</para>
+
+<programlisting><![CDATA[
+    /* Switch to compatibility mode.  (In fact we don't need
+     * to do this, since we start off in compatibility mode
+     * anyway, but this demonstrates PPNEGOT.)
+    mode = IEEE1284_MODE_COMPAT;
+    if (ioctl (fd, PPNEGOT, &mode)) {
+        perror ("PPNEGOT");
+        close (fd);
+        return 1;
+    }
+
+    for (;;) {
+        char buffer[1000];
+        char *ptr = buffer;
+        size_t got;
+
+        got = read (0 /* stdin */, buffer, 1000);
+        if (got < 0) {
+            perror ("read");
+            close (fd);
+            return 1;
+        }
+
+        if (got == 0)
+            /* End of input */
+            break;
+
+        while (got > 0) {
+            int written = write_printer (fd, ptr, got);
+
+            if (written < 0) {
+                perror ("write");
+                close (fd);
+                return 1;
+            }
+
+            ptr += written;
+            got -= written;
+        }
+    }
+]]></programlisting>
+
+<para>The <function>write_printer</function> function is not pictured
+above.  This is because the main loop that is shown can be used for
+both methods of driving the printer.  Here is one implementation of
+<function>write_printer</function>:</para>
+
+<programlisting><![CDATA[
+ssize_t write_printer (int fd, const void *ptr, size_t count)
+{
+    return write (fd, ptr, count);
+}
+]]></programlisting>
+
+<para>We hand the data to the kernel-level driver (using
+<function>write</function>) and it handles the printer
+protocol.</para>
+
+<para>Now let's do it the hard way!  In this particular example there
+is no practical reason to do anything other than just call
+<function>write</function>, because we know that the printer talks an
+IEEE 1284 protocol.  On the other hand, this particular example does
+not even need a user-land driver since there is already a kernel-level
+one; for the purpose of this discussion, try to imagine that the
+printer speaks a protocol that is not already implemented under
+Linux.</para>
+
+<para>So, here is the alternative implementation of
+<function>write_printer</function> (for brevity, error checking has
+been omitted):</para>
+
+<programlisting><![CDATA[
+ssize_t write_printer (int fd, const void *ptr, size_t count)
+{
+    ssize_t wrote = 0;
+
+    while (wrote < count) {
+        unsigned char status, control, data;
+        unsigned char mask = (PARPORT_STATUS_ERROR
+                              | PARPORT_STATUS_BUSY);
+        unsigned char val = (PARPORT_STATUS_ERROR
+                              | PARPORT_STATUS_BUSY);
+        struct parport_frob_struct frob;
+        struct timespec ts;
+
+        /* Wait for printer to be ready */
+        for (;;) {
+            ioctl (fd, PPRSTATUS, &status);
+
+            if ((status & mask) == val)
+                break;
+
+            ioctl (fd, PPRELEASE);
+            sleep (1);
+            ioctl (fd, PPCLAIM);
+        }
+
+        /* Set the data lines */
+        data = * ((char *) ptr)++;
+        ioctl (fd, PPWDATA, &data);
+
+        /* Delay for a bit */
+        ts.tv_sec = 0;
+        ts.tv_nsec = 1000;
+        nanosleep (&ts, NULL);
+
+        /* Pulse strobe */
+        frob.mask = PARPORT_CONTROL_STROBE;
+        frob.val = PARPORT_CONTROL_STROBE;
+        ioctl (fd, PPFCONTROL, &frob);
+        nanosleep (&ts, NULL);
+
+        /* End the pulse */
+        frob.val = 0;
+        ioctl (fd, PPFCONTROL, &frob);
+        nanosleep (&ts, NULL);
+
+        wrote++;
+    }
+
+    return wrote;
+}
+]]></programlisting>
+
+<para>To show a bit more of the <filename>ppdev</filename> interface,
+here is a small piece of code that is intended to mimic the printer's
+side of printer protocol.</para>
+
+<programlisting><![CDATA[
+  for (;;)
+    {
+      int irqc;
+      int busy = nAck | nFault;
+      int acking = nFault;
+      int ready = Busy | nAck | nFault;
+      char ch;
+
+      /* Set up the control lines when an interrupt happens. */
+      ioctl (fd, PPWCTLONIRQ, &busy);
+
+      /* Now we're ready. */
+      ioctl (fd, PPWCONTROL, &ready);
+
+      /* Wait for an interrupt. */
+      {
+        fd_set rfds;
+        FD_ZERO (&rfds);
+        FD_SET (fd, &rfds);
+        if (!select (fd + 1, &rfds, NULL, NULL, NULL))
+          /* Caught a signal? */
+          continue;
+      }
+
+      /* We are now marked as busy. */
+
+      /* Fetch the data. */
+      ioctl (fd, PPRDATA, &ch);
+
+      /* Clear the interrupt. */
+      ioctl (fd, PPCLRIRQ, &irqc);
+      if (irqc > 1)
+        fprintf (stderr, "Arghh! Missed %d interrupt%s!\n",
+         irqc - 1, irqc == 2 ? "s" : "");
+
+      /* Ack it. */
+      ioctl (fd, PPWCONTROL, &acking);
+      usleep (2);
+      ioctl (fd, PPWCONTROL, &busy);
+
+      putchar (ch);
+    }
+]]></programlisting>
+
+</sect1>
+
+</chapter>
+</book>
\ No newline at end of file
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/arm/SA1100/Brutus linux/Documentation/arm/SA1100/Brutus
--- v2.3.99-pre3/linux/Documentation/arm/SA1100/Brutus	Thu Feb 10 17:11:01 2000
+++ linux/Documentation/arm/SA1100/Brutus	Mon Mar 27 10:46:29 2000
@@ -23,7 +23,7 @@
 	- RS232 serial ports
 	- audio output
 	- LCD screen
-	- keyboard (needs to be cleaned up badly... any volunteer?)
+	- keyboard
 	
 The actual Brutus support may not be complete without extra patches. 
 If such patches exist, they should be found from 
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/arm/SA1100/ThinClient linux/Documentation/arm/SA1100/ThinClient
--- v2.3.99-pre3/linux/Documentation/arm/SA1100/ThinClient	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/SA1100/ThinClient	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,33 @@
+Thin Client / Single Board Computer
+
+The Thin Client, a low cost high power single board computer, has been
+designed to provide intuitive graphical displays in embedded systems.
+
+For more details, contact Applied Data Systems or see
+http://www.flatpanels.com/products.html
+
+Current Linux support for this product has been provided by Nicolas Pitre
+<nico@cam.org>.
+
+It's currently possible to mount a root filesystem via NFS providing a
+complete Linux environment.  Otherwyse a ramdisk image may be used.  Use
+'make thinclient_config' before any 'make config'.  This will set up
+defaults for ThinClient support.
+
+Supported peripherals:
+- SA1100 LCD frame buffer (only 8bpp yet)
+- on-board SMC 92C94 ethernet NIC
+- SA1100 serial port
+- possibly UCB1200 audio (not tested yet)
+
+To do:
+- touchscreen driver
+- flash memory access
+- 16bpp frame buffer support
+- extra (external) serial port driver
+- pcmcia
+- some console keyboard support (maybe IR?)
+- everything else!  :-)
+
+Any contribution can be sent to nico@cam.org and will be greatly welcome!
+
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/filesystems/ntfs.txt linux/Documentation/filesystems/ntfs.txt
--- v2.3.99-pre3/linux/Documentation/filesystems/ntfs.txt	Tue Apr 28 14:22:04 1998
+++ linux/Documentation/filesystems/ntfs.txt	Mon Apr 10 23:02:59 2000
@@ -4,10 +4,13 @@
 To mount an NTFS volume, use the filesystem type 'ntfs'. The driver
 currently works only in read-only mode, with no fault-tolerance
 supported.  If you enable the experimental write support, make sure
-you can recover from a complete loss of data. For ftdisk support,
-limited success was reported with volume sets on top of the md driver,
-although mirror and stripe sets should work as well - if the md
-driver can be talked into using the same layout as Windows NT.
+you can recover from a complete loss of data and also always run
+chkdsk from within Microsoft Windows NT after performing a write to
+a NTFS partition from Linux to detect any problems as early as 
+possible. For ftdisk support, limited success was reported with 
+volume sets on top of the md driver, although mirror and stripe 
+sets should work as well - if the md driver can be talked into 
+using the same layout as Windows NT.
 
 The ntfs driver supports the following mount options:
 iocharset=name      Character set to use when returning file names.
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/sound/CMI8330 linux/Documentation/sound/CMI8330
--- v2.3.99-pre3/linux/Documentation/sound/CMI8330	Thu Feb 10 17:11:02 2000
+++ linux/Documentation/sound/CMI8330	Mon Mar 27 11:02:54 2000
@@ -2,6 +2,9 @@
 -------------------------------------
 Alessandro Zummo <azummo@ita.flashnet.it>
 
+( Be sure to read Documentation/sound/SoundPro too )
+
+
 This adapter is now directly supported by the sb driver.
 
  The only thing you have to do is to compile the kernel sound
@@ -24,17 +27,6 @@
  for MPU401 support.
 
 
-CONFIG_SOUND_YM3812=m
-
- for OPL3 support. Please note that there are better ways to play midi files, like
- timidity or the softoss2 module.
-
-
-CONFIG_JOYSTICK=y
-
- to activate the joystick port.
-
-
 (I suggest you to use "make menuconfig" or "make xconfig" 
  for a more comfortable configuration editing)
 
@@ -51,25 +43,8 @@
 sb: CMI8330 detected.
 sb: CMI8330 sb base located at 0x220
 sb: CMI8330 mpu base located at 0x330
-sb: CMI8330 gameport base located at 0x200
-sb: CMI8330 opl3 base located at 0x388
 sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>
 sb: ISAPnP reports CMI 8330 SoundPRO at i/o 0x220, irq 7, dma 1,5
-
-
-
-
-To activate the OPL3 support, you need these lines in /etc/modules.conf
-or in a file in /etc/modutils
-
-alias synth0 opl3
-options opl3 io=0x388
-
-and then you can do:
-
- modprobe opl3
-
-
 
 
 
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/sound/PAS16 linux/Documentation/sound/PAS16
--- v2.3.99-pre3/linux/Documentation/sound/PAS16	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/PAS16	Sun Apr  2 15:38:53 2000
@@ -0,0 +1,185 @@
+Pro Audio Spectrum 16 for 2.3.99 and later
+=========================================
+by Thomas Molina (tmolina@home.com)
+last modified 26 Mar 2000
+Acknowledgement to Axel Boldt (boldt@math.ucsb.edu) for stuff taken
+from Configure.help, Riccardo Facchetti for stuff from README.OSS,
+and others whose names I could not find.
+
+This documentation is relevant for the PAS16 driver (pas2_card.c and
+friends) under kernel version 2.3.99 and later.  If you are
+unfamiliar with configuring sound under Linux, please read the
+Sound-HOWTO, linux/Documentation/sound/Introduction and other 
+relevant docs first.
+
+The following information is relevant information from README.OSS
+and legacy docs for the Pro Audio Spectrum 16 (PAS16):
+==================================================================
+
+The pas2_card.c driver supports the following cards --
+Pro Audio Spectrum 16 (PAS16) and compatibles:
+        Pro Audio Spectrum 16
+        Pro Audio Studio 16
+        Logitech Sound Man 16
+        NOTE! The original Pro Audio Spectrum as well as the PAS+ are not
+              and will not be supported by the driver.
+
+The sound driver configuration dialog
+-------------------------------------
+
+Sound configuration starts by making some yes/no questions. Be careful
+when answering to these questions since answering y to a question may
+prevent some later ones from being asked. For example don't answer y to
+the question about (PAS16) if you don't really have a PAS16.  Sound
+configuration may also be made modular by answering m to configuration
+options presented. 
+
+Note also that all questions may not be asked. The configuration program
+may disable some questions depending on the earlier choices. It may also
+select some options automatically as well.
+
+  "ProAudioSpectrum 16 support",
+        - Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_,
+          Pro Audio Studio 16 or Logitech SoundMan 16 (be sure that
+          you read the above list correctly). Don't answer 'y' if you
+          have some other card made by Media Vision or Logitech since they
+          are not PAS16 compatible.
+          NOTE! Since 3.5-beta10 you need to enable SB support (next question)
+          if you want to use the SB emulation of PAS16. It's also possible to
+          the emulation if you want to use a true SB card together with PAS16
+          (there is another question about this that is asked later).
+  "Sound Blaster support",
+        - Answer 'y' if you have an original SB card made by Creative Labs
+          or a full 100% hardware compatible clone (like Thunderboard or
+          SM Games). If your card was in the list of supported cards (above),
+          please look at the card specific instructions later in this file
+          before answering this question. For an unknown card you may answer
+          'y' if the card claims to be SB compatible.
+         Enable this option also with PAS16.
+
+  "Generic OPL2/OPL3 FM synthesizer support",
+        - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+	  The PAS16 has an OPL3-compatible FM chip.
+
+With PAS16 you can use two audio device files at the same time. /dev/dsp (and
+/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and
+/dev/audio1) is connected to the SB emulation (8 bit mono only).
+
+
+The new stuff for 2.3.99 and later
+============================================================================
+The following configuration options from linux/Documentation/Configure.help
+are relevant to configuring the PAS16:
+
+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
+  Documentation/sound/Introduction. The file
+  Documentation/sound/README.OSS contains some slightly outdated but
+  still useful information as well.
+
+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 here for PAS16.
+
+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. Don't answer Y if you have
+  some other card made by Media Vision or Logitech since they are not
+  PAS16 compatible.
+  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.
+
+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.  The PAS16 has 8-bit Soundblaster
+  support, so you can answer Y here for it.
+
+  Please read the file Documentation/sound/Soundblaster.
+
+  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.
+
+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 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 you compile your drivers into the kernel, you MUST configure 
+  OPL3 support as a module for PAS16 support to work properly.
+  You can then get OPL3 functionality by issuing the command:
+  insmod opl3
+  In addition, you must either add the following line to 
+  /etc/modules.conf:
+  options opl3 io=0x388
+  or else add the following line to /etc/lilo.conf:
+  opl3=0x388
+
+
+EXAMPLES
+===================================================================
+To use the PAS16 in my computer I have enabled the following sound
+configuration options:
+
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS=y
+CONFIG_SOUND_TRACEINIT=y
+CONFIG_SOUND_DMAP=y
+CONFIG_SOUND_PAS=y
+CONFIG_SOUND_SB=y
+CONFIG_SOUND_YM3812=m
+
+I have also included the following append line in /etc/lilo.conf:
+append="pas2=0x388,10,3,-1,0x220,5,1,-1 sb=0x220,5,1,-1 opl3=0x388"
+
+The io address of 0x388 is default configuration on the PAS16.  The
+irq of 10 and dma of 3 may not match your installation.  The above 
+configuration enables PAS16, 8-bit Soundblaster and OPL3
+functionality.  If Soundblaster functionality is not desired, the
+following line would be appropriate:
+append="pas2=0x388,10,3,-1,0,-1,-1,-1 opl3=0x388"
+
+If sound is built totally modular, the above options may be 
+specified in /etc/modules.conf for pas2.o, sb.o and opl3.o 
+respectively. 
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/sound/SoundPro linux/Documentation/sound/SoundPro
--- v2.3.99-pre3/linux/Documentation/sound/SoundPro	Fri Jan 21 18:19:15 2000
+++ linux/Documentation/sound/SoundPro	Mon Mar 27 11:02:54 2000
@@ -1,6 +1,8 @@
 Documentation for the SoundPro CMI8330 extensions in the WSS driver (ad1848.o)
 ------------------------------------------------------------------------------
 
+( Be sure to read Documentation/sound/CMI8330 too )
+
 Ion Badulescu, ionut@cs.columbia.edu
 February 24, 1999
 
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/sysrq.txt linux/Documentation/sysrq.txt
--- v2.3.99-pre3/linux/Documentation/sysrq.txt	Sun Mar 19 18:35:30 2000
+++ linux/Documentation/sysrq.txt	Mon Apr 10 23:09:01 2000
@@ -1,7 +1,7 @@
 
-                      MAGIC SYSRQ KEY DOCUMENTATION v1.31
+                      MAGIC SYSRQ KEY DOCUMENTATION v1.32
                      ------------------------------------
-                        [Mon Mar 13 21:45:48 EST 2000]
+                        [Sat Apr  8 22:15:03 CEST 2000]
 
 *  What is the magic SysRQ key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -113,13 +113,13 @@
 
 *  I hit SysRQ, but nothing seems to happen, what's wrong?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-There are some keyboards which do not support 'SysRQ', you can try running
-'showkey -s' and pressing SysRQ or alt-SysRQ to see if it generates any
-0x54 codes. If it doesn't, you may define the magic sysrq sequence to a
-different key. Find the keycode with showkey, and change the define of
-'#define SYSRQ_KEY 0x54' in [/usr/src/linux/]include/asm/keyboard.h to
-the keycode of the key you wish to use, then recompile. Oh, and by the way,
-you exit 'showkey' by not typing anything for ten seconds.
+There are some keyboards that send different scancodes for SysRQ than the
+pre-defined 0x54. So if SysRQ doesn't work out of the box for a certain 
+keyboard, run 'showkey -s' to find out the proper scancode sequence. Then 
+use 'setkeycodes <sequence> 84' to define this sequence to the usual SysRQ 
+code (84 is decimal for 0x54). It's probably best to put this command in a
+boot script. Oh, and by the way, you exit 'showkey' by not typing anything 
+for ten seconds.
 
 *  I have more questions, who can I ask?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/usb/CREDITS linux/Documentation/usb/CREDITS
--- v2.3.99-pre3/linux/Documentation/usb/CREDITS	Fri Jan 28 15:09:06 2000
+++ linux/Documentation/usb/CREDITS	Sun Apr  2 15:20:16 2000
@@ -16,6 +16,7 @@
   Paul Mackerras <paulus@cs.anu.edu.au>
   David E. Nelson <dnelson@jump.net>
   Vojtech Pavlik <vojtech@suse.cz>
+  Bill Ryder <bryder@sgi.com>
   Thomas Sailer <sailer@ife.ee.ethz.ch>
   Gregory P. Smith <greg@electricrain.com>
   Linus Torvalds <torvalds@transmeta.com>
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/usb/acm.txt linux/Documentation/usb/acm.txt
--- v2.3.99-pre3/linux/Documentation/usb/acm.txt	Thu Jan  6 12:57:47 2000
+++ linux/Documentation/usb/acm.txt	Wed Apr  5 16:58:38 2000
@@ -1,94 +1,138 @@
-The ACM driver works with modems and ISDN TAs that use the USB Abstract
-Control Model standard. 
-
-****************************
-Test it:
-Watch out, the driver is not stable and tested. Sync often, make backups,
-most importand: don't blame me...
-
-Create device files:
-mknod /dev/ttyACM0 c 166 0
-mknod /dev/ttyACM1 c 166 1
-mknod /dev/ttyACM2 c 166 2
-mknod /dev/ttyACM3 c 166 3
-Compile a kernel with support for your host controller (uhci only for now!)
-and support for ACM. Boot this kernel. If you connect your device to the
-USB bus you should see messages like the following:
-
-Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
-Jul 19 20:14:29 office kernel: Found 02:09
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office last message repeated 2 times
-Jul 19 20:14:29 office kernel: parsed = 39 len = 67
-Jul 19 20:14:29 office kernel: Expected descriptor 04/09, got 02/09 - skipping
-Jul 19 20:14:29 office kernel:    0 09
-Jul 19 20:14:29 office kernel:    1 02
-Jul 19 20:14:29 office kernel:    2 43
-Jul 19 20:14:29 office kernel:    3 00
-Jul 19 20:14:29 office kernel:    4 02
-Jul 19 20:14:29 office kernel:    5 02
-Jul 19 20:14:29 office kernel:    6 04
-Jul 19 20:14:29 office kernel:    7 60
-Jul 19 20:14:29 office kernel:    8 00
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 02:09
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: parsed = 67 len = 0
-Jul 19 20:14:29 office kernel: getstringtable
-Jul 19 20:14:29 office kernel: acm_probe
-Jul 19 20:14:29 office kernel: USB ACM found
-
-Watch out for the line:
-Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
-and the line:
-Jul 19 20:14:29 office kernel: USB ACM found
-These two lines show that the device was seen by the usb host controller and
-then recognized by the acm driver as a valid device.
-
-If you use a terminal emulation software like minicom with /dev/ttyACM0 you
-should be able to send AT commands to your device and get responses. I've 
-been able to do zmodem downloads to another pc. However downloads from one
-ISDN TA to another ISDN TA connected to the same PC didn't work. Don't
-know why. Flow control is not finised after all and i'd guess there might
-be problems on heavily loades PCs. I also did some tests with ppp but i'm
-not finised with this. There might be a chance to get it working. However
-i'd like to know if your device is recognized as an ACM device. I'm also
-interested if the thing is stable or if it crashes.
-(should i say how it crases?)
-
-You should be able to add and remove devices from the bus. The driver will
-always try to fill up unused ttys. This means if you hotplug devices their
-order may have changed after reboot. This is not the behaviour Linus liked
-to see but it's ok for now. (I hope ;-)
-
-Please report your experiences to me:
-fuerst@in.tum.de
-
-***************************
-I've tested it with:
-3Com ISDN Pro TA.
-
-It should work with (That means i know these devices conform to ACM):
-3Com Office Connect Modem
-3Com Sportster USB (I think that's what it's called)
-
-***************************
-Many thanks to 3Com which did not only support me with hardware but also
-with technical support in USB questions. They also allowed me to do tests in
-their lab. Great!
-
-***************************
-Known bugs:
-Flow control not tested (likely not to work)
-Some tty function calls not implemented (putchar, etc...)
-Huge amounts of debug output (compile in [*] Magic SysRq key and press ALT+PRTSCR+0 )
-Not all mem is freed at close (need terminate irq in hcd)
-
-***************************
-Have fun,
-	Armin Fuerst
+			  Linux ACM driver v0.16
+		 (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
+			     Sponsored by SuSE
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+  This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your option)
+any later version.
+
+  This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+more details.
+
+  You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc., 59
+Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+  Should you need to contact me, the author, you can do so either by e-mail
+- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
+Ucitelska 1576, Prague 8, 182 00 Czech Republic
+
+  For your convenience, the GNU General Public License version 2 is included
+in the package: See the file COPYING.
+
+1. Usage
+~~~~~~~~
+  The drivers/usb/acm.c drivers works with USB modems and USB ISDN terminal
+adapters that conform to the Universal Serial Bus Communication Device Class
+Abstract Control Model (USB CDC ACM) specification.
+
+  Many modems do, here is a list of those I know of:
+
+	3Com OfficeConnect 56k
+	3Com Voice FaxModem Pro
+	3Com Sportster
+	MultiTech MultiModem 56k
+	Zoom 2986L FaxModem
+	Compaq 56k FaxModem
+	ELSA Microlink 56k
+
+  I know of one ISDN TA that does work with the acm driver:
+
+	3Com USR ISDN Pro TA
+
+  Unfortunately many modems and most ISDN TAs use proprietary interfaces and
+thus won't work with this drivers. Check for ACM compliance before buying.
+
+  The driver (with devfs) creates these devices in /dev/usb/acm:
+
+	crw-r--r--   1 root     root     166,   0 Apr  1 10:49 0
+	crw-r--r--   1 root     root     166,   1 Apr  1 10:49 1
+	crw-r--r--   1 root     root     166,   2 Apr  1 10:49 2
+
+  And so on, up to 31, with the limit being possible to change in acm.c to up
+to 256, so you can use up to 256 USB modems with one computer (you'll need
+three USB cards for that, though).
+
+  If you don't use devfs, then you can create device nodes with the same
+minor/major numbers anywhere you want, but either the above location or
+/dev/usb/ttyACM0 is preferred.
+
+  To use the modems you need these modules loaded:
+
+	usbcore.o
+	usb-[uo]hci.o or uhci.o
+	acm.o
+
+  After that, the modem[s] should be accessible. You should be able to use
+minicom, ppp and mgetty with them.
+
+2. Verifying that it works
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The first step would be to check /proc/bus/usb/devices, it should look
+like this:
+
+T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
+B:  Alloc=  0/900 us ( 0%), #Int=  0, #Iso=  0
+D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0000 ProdID=0000 Rev= 0.00
+S:  Product=USB UHCI Root Hub
+S:  SerialNumber=6800
+C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=  0mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
+E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=255ms
+T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
+D:  Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  2
+P:  Vendor=04c1 ProdID=008f Rev= 2.07
+S:  Manufacturer=3Com Inc.
+S:  Product=3Com U.S. Robotics Pro ISDN TA
+S:  SerialNumber=UFT53A49BVT7
+C:  #Ifs= 1 Cfg#= 1 Atr=60 MxPwr=  0mA
+I:  If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=acm
+E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
+C:* #Ifs= 2 Cfg#= 2 Atr=60 MxPwr=  0mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
+E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
+I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
+E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+
+The presence of these three lines (and the Cls= 'comm' and 'data' classes)
+is important, it means it's an ACM device. The Driver=acm means the acm
+driver is used for the device. If you see only Cls=ff(vend.) then you're out
+of luck, you have a device with vendor specific-interface.
+
+D:  Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  2
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
+I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
+
+In the system log you should see:
+
+usb.c: USB new device connect, assigned device number 2
+usb.c: kmalloc IF c7691fa0, numif 1
+usb.c: kmalloc IF c7b5f3e0, numif 2
+usb.c: skipped 4 class/vendor specific interface descriptors
+usb.c: new device strings: Mfr=1, Product=2, SerialNumber=3
+usb.c: USB device number 2 default language ID 0x409
+Manufacturer: 3Com Inc.
+Product: 3Com U.S. Robotics Pro ISDN TA
+SerialNumber: UFT53A49BVT7
+acm.c: probing config 1
+acm.c: probing config 2
+ttyACM0: USB ACM device
+acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0 result: 0
+acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7 result: 7
+usb.c: acm driver claimed interface c7b5f3e0
+usb.c: acm driver claimed interface c7b5f3f8
+usb.c: acm driver claimed interface c7691fa0
+
+If all this seems to be OK, fire up minicom and set it to talk to the ttyACM
+device and try typing 'at'. If it responds with 'OK', then everything is
+working.
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/usb/hid.txt linux/Documentation/usb/hid.txt
--- v2.3.99-pre3/linux/Documentation/usb/hid.txt	Thu Jan  6 12:57:47 2000
+++ linux/Documentation/usb/hid.txt	Wed Dec 31 16:00:00 1969
@@ -1,162 +0,0 @@
-			   Linux HID driver v0.8
-		 (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
-		    (c) 1999 Andreas Gal <agal@uwsp.edu>
-			     Sponsored by SuSE
-----------------------------------------------------------------------------
-
-0. Disclaimer
-~~~~~~~~~~~~~
-  This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2 of the License, or (at your option)
-any later version.
-
-  This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-more details.
-
-  You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc., 59
-Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-  Should you need to contact me, the author, you can do so either by e-mail
-- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
-Ucitelska 1576, Prague 8, 182 00 Czech Republic
-
-  For your convenience, the GNU General Public License version 2 is included
-in the package: See the file COPYING.
-
-1. Introduction
-~~~~~~~~~~~~~~~
-  This is a driver for USB devices conforming to the USB HID (Human Input
-Device) standard. These devices include namely keyboards, mice and
-joysticks.
-
-  However many other devices (monitors, speakers, UPSs ...) also communicate
-through the same protocol, which makes its specification somewhat bloated.
-This isn't a problem, though, because the driver doesn't need to know about
-all the possible devices it can control, and can just parse the protocol and
-leave the rest of the job (for example understanding what the UPS wants to
-say) to the userland.
-
-  Because of this, the USB HID driver has two interfaces. One is via the
-proc filesystem, allowing userland applications send and read arbitrary
-reports to and from a connected USB device. The other is via a very simple
-yet generic input device driver, which dispatches input events (keystrokes,
-mouse or joystick movements) to specific, backward compatible userland
-interfaces. This way a PS/2 mouse, an AT keyboard or a Linux joystick driver
-interface are emulated, and allow applications to immediately work with USB
-mice, USB keyboards and USB joysticks without any changes.
-
-  The input driver is aimed for a little more than USB device handling in
-the future, though. It's generic enough so that it can be used for any
-mouse, keyboard or joystick (and more, of course). A PS/2 mouse driver, a
-serial mouse, Sun mouse, and most of the busmouse drivers were rewritten to
-use this as well as the AT keyboard and Sun keyboard drivers. This will
-hopefully allow conversion of all Linux keyboard and mouse and joystick
-drivers to this scheme.
-
-  This effort has it's home page at:
-
-	http://www.suse.cz/development/input/
-
-You'll find both the latest HID driver and the complete Input driver there.
-There is also a mailing list for this:
-
-	listproc@atrey.karlin.mff.cuni.cz
-
-Send "subscribe linux-joystick Your Name" to subscribe to it.
-
-2. Usage
-~~~~~~~~
-  Since the driver comes with recent 2.3 kernels, all that's needed to use
-it is to enable it either as a module or compiled-in into the kernel. 
-
-  After that, after reboot (and possibly also inserting the USB and HID
-modules) the following will happen:
-
-* If you selected keyboard support, all USB keystrokes will be also routed
-  to the Linux keyboard driver as if being input through the ordinary system
-  keyboard.
-
-* If you selected mouse support, there will be (one or more) simulated PS/2
-  mouse devices on major 10, minor 32, 33 and more. These simulated mice can
-  in addition to a standard 3-button PS/2 mouse behave like MS Intellimice,
-  with a wheel. If you want to use the wheel, just specify '-t imps2' to gpm
-  and 'Protocol "ImPS/2"' to X, and it will work. A single emulated mouse
-  device can be open by any number of processes (unlike the /dev/psaux), and
-  for each of them the emulation is separate, each can use a different mode.
-  The mousedev driver, which emulates the mice, can also emulate a Genius
-  NewScroll 5 buttons-and-a-wheel mouse, if you set it to a Genius PS/2
-  mode ('-t netmouse' 'Protocol "NetMousePS/2"'). However, not gpm, nor X
-  can decode the 5 buttons yet, so this isn't very useful right now.
-
-* If you selected joystick support, the driver will take over major 15, the
-  joystick major number, and will emulate joysticks on it. This means the
-  normal joystick driver can't be used together with it (now, after the
-  normal joystick drivers are converted to the input scheme, all will work
-  nicely together). Also, you'll probably need to calibrate your joystick
-  manually ('man jscal') to be able to use it, because the USB
-  autocalibration is far from perfect yet.
-
-* If you selected event device support, there will be devices on major 10,
-  minors 64, 65 and more for each input device connected through this
-  driver. These devices output raw events the input driver dispatches. Each
-  has a timestamp. This hopefully will be THE way X will talk to keyboard
-  and mice, because it's hardware independent, and not limited by existing
-  de-facto standards.
-
-3. Verifying if it works
-~~~~~~~~~~~~~~~~~~~~~~~~
-  Typing a couple keys on the keyboard should be enough to check that a USB
-keyboard works and is correctly connected to the kernel keyboard driver.
-
-  Doing a cat /dev/hidmouse (c, 10, 32) will verify that a mouse is also
-emulated, characters should appear if you move it.
-
-  You can test the joystick emulation with the 'jstest' utility, available
-in the joystick package (see Documentation/joystick.txt).
-
-  You can test the event devics with the 'evtest' utitily available on the
-input driver homepage (see the URL above).
-
-4. FAQ
-~~~~~~
-Q: Why aren't any questions here yet?
-A: Because none were frequent enough yet.
-
-5. Event interface
-~~~~~~~~~~~~~~~~~~
-  Should you want to add event device support into any application (X, gpm,
-svgalib ...) I (vojtech@suse.cz) will be happy to provide you any help I
-can. Here goes a description of the current state of things, which is going
-to be extended, but not changed incompatibly as time goes:
-
-  You can use blocking and nonblocking reads, also select() on the
-/dev/inputX devices, and you'll always get a whole number of input events on
-a read. Their layout is:
-
-struct input_event {
-	struct timeval time;
-	unsigned short type;
-	unsigned short code;
-	unsigned int value;
-};
-
-  'time' is the timestamp, it returns the time at which the event happened.
-Type is for example EV_REL for relative momement, REL_KEY for a keypress or
-release. More types are defined in include/linux/input.h.
-
-  'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
-list is in include/linux/input.h.
-
-  'value' is the value the event carries. Either a relative change for
-EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
-release, 1 for keypress and 2 for autorepeat.
-
-6. Proc interface
-~~~~~~~~~~~~~~~~~
-  For HID-specific devices there is also the /proc interface. It isn't
-present in this release yet, though, so it's description will appear here
-together with the code in the driver.
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/usb/ibmcam.txt linux/Documentation/usb/ibmcam.txt
--- v2.3.99-pre3/linux/Documentation/usb/ibmcam.txt	Thu Mar  2 14:36:22 2000
+++ linux/Documentation/usb/ibmcam.txt	Sun Apr  2 15:19:56 2000
@@ -7,8 +7,7 @@
 
 This driver was developed using logs of observed USB traffic
 which was produced by standard Windows driver (c-it98.sys).
-I did not have any input from Xirlink. Some people asked about
-data sheets, but nothing came out of that. I didn't try.
+I did not have data sheets from Xirlink.
 
 Video formats:
       128x96  [model 1]
@@ -29,14 +28,16 @@
 IBM "C-It" camera, also known as "Xirlink PC Camera"
 The device uses proprietary ASIC (and compression method);
 it is manufactured by Xirlink. See http://www.xirlink.com/
-or http://www.c-itnow.com/ for details and pictures.
+http://www.ibmpccamera.com or http://www.c-itnow.com/ for
+details and pictures.
 
 The Linux driver was developed with camera with following
 model number (or FCC ID): KSX-XVP510. This camera has three
 interfaces, each with one endpoint (control, iso, iso). This
-type of cameras is referred to as "model 1".
+type of cameras is referred to as "model 1". These cameras are
+no longer manufactured.
 
-It appears that Xirlink made some changes in their cameras recently.
+Xirlink now manufactures new cameras which are somewhat different.
 In particular, following models [FCC ID] belong to that category:
 
 XVP300 [KSX-X9903]
@@ -46,29 +47,20 @@
 (see http://www.xirlink.com/ibmpccamera/ for updates, they refer
 to these new cameras by Windows driver dated 12-27-99, v3005 BETA)
 These cameras have two interfaces, one endpoint in each (iso, bulk).
-Such type of cameras is referred to as "model 2". They are supported.
+Such type of cameras is referred to as "model 2". They are supported
+(with exception of 352x288 native mode).
 
 Quirks of Model 2 cameras:
 -------------------------
 
-These cameras apparently produce only 176x144 native video stream;
-the 352x288 formats are produced from 176x144 RGB stream. In fact,
-Xirlink broke perfectly good Model 1 (which used I420 on all sizes)
-and instead switched to color-separated RGB which is a terrible waste
-of bandwidth and resolution. However it probably allowed to simplify
-the camera and use less RAM. Model 2 camera works visibly worse than
-model 1 even using Xirlink's own driver on Windows. The image quality
-is better on Linux than on Windows, partly thanks to _absence_ of
-annoying automatic color corrections which Windows driver feeds into
-the camera several times per second.
-
 Model 2 does not have hardware contrast control. Corresponding V4L
 control is not used at the moment. It may be possible to implement
 contrast control in software, at cost of extra processor cycles.
 
-The bandwidth demand imposed by RGB quasi-352x288 mode (800 Kbits per
-frame) essentially limits this mode to 10 frames per second or less, in
-ideal conditions on the bus (USB is shared, after all). The frame rate
+This driver provides 352x288 mode by switching the camera into
+quasi-352x288 RGB mode (800 Kbits per frame) essentially limiting
+this mode to 10 frames per second or less, in ideal conditions on
+the bus (USB is shared, after all). The frame rate
 has to be programmed very conservatively. Additional concern is that
 frame rate depends on brightness setting; therefore the picture can
 be good at one brightness and broken at another! I did not want to fix
@@ -81,24 +73,21 @@
 to send all data. However if you regularly use Model 2 cameras you may
 prefer videosize=1 which makes perfectly good I420, with no scaling and
 lesser demands on USB (300 Kbits per second, or 26 frames per second).
-Remember that model 2 cameras never produce images with resolution
-better than "true" 176x144 - or so it seems.
 
 The camera that I had also has a hardware quirk: if disconnected,
 it needs few minutes to "relax" before it can be plugged in again
 (poorly designed USB processor reset circuit?)
 
-Finally, to say something good about Model 2: it is much simpler to program
-than Model 1. Commands are few, and they all are straightforward. This camera
-can be programmed for very high sensitivity (starlight may be enough), this
-makes it convenient for tinkering with. The driver code has enough comments
-to help a programmer to tweak the camera as s/he feels necessary.
+Model 2 camera can be programmed for very high sensitivity (even starlight
+may be enough), this makes it convenient for tinkering with. The driver
+code has enough comments to help a programmer to tweak the camera
+as s/he feels necessary.
 
 WHAT YOU NEED:
 
 - A supported IBM PC (C-it) camera (model 1 or 2)
 
-- A Linux box with USB support (2.3/2.4 or 2.2 w/backport)
+- A Linux box with USB support (2.3/2.4; 2.2 w/backport may work)
 
 - A Video4Linux compatible frame grabber program such as xawtv.
   
@@ -179,6 +168,19 @@
                 FLAGS_OVERLAY_STATS     8  Shows tiny numbers on screen,
                                            useful only for debugging.
                 FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
+                FLAGS_SEPARATE_FRAMES   32 Shows each frame separately, as
+                                           it was received from the camera.
+                                           Default (not set) is to mix the
+                                           preceding frame in to compensate
+                                           for occasional loss of Isoc data
+                                           on high frame rates.
+                FLAGS_CLEAN_FRAMES      64 Forces "cleanup" of each frame
+                                           prior to use; relevant only if
+                                           FLAGS_SEPARATE_FRAMES is set.
+                                           Default is not to clean frames,
+                                           this is a little faster but may
+                                           produce flicker if frame rate is
+                                           too high and Isoc data gets lost.
 
 framerate       This setting controls frame rate of the camera. This is
                 an approximate setting (in terms of "worst" ... "best")
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/usb/input.txt linux/Documentation/usb/input.txt
--- v2.3.99-pre3/linux/Documentation/usb/input.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/input.txt	Wed Apr  5 16:58:38 2000
@@ -0,0 +1,294 @@
+			  Linux Input drivers v0.9
+		 (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
+			     Sponsored by SuSE
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+  This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your option)
+any later version.
+
+  This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+more details.
+
+  You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc., 59
+Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+  Should you need to contact me, the author, you can do so either by e-mail
+- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
+Ucitelska 1576, Prague 8, 182 00 Czech Republic
+
+  For your convenience, the GNU General Public License version 2 is included
+in the package: See the file COPYING.
+
+1. Introduction
+~~~~~~~~~~~~~~~
+  This is a collection of drivers that is designed to support all input
+devices under Linux. However, in the current kernels, although it's
+possibilities are much bigger, it's limited to USB devices only. This is
+also why it resides in the drivers/usb subdirectory.
+
+  The center of the input drivers is the input.o module, which must be
+loaded before any other of the input modules - it serves as a way of
+communication between two groups of modules:
+
+1.1 Device drivers
+~~~~~~~~~~~~~~~~~~
+  These modules talk to the hardware (for example via USB), and provide
+events (keystrokes, mouse movements) to the input.o module.
+
+1.2 Event handlers
+~~~~~~~~~~~~~~~~~~
+  These modules get events from input.o and pass them where needed via
+various interfaces - keystrokes to the kernel, mouse movements via a
+simulated PS/2 interface to GPM and X and so on.
+
+2. Simple Usage
+~~~~~~~~~~~~~~~
+  For the most usual configuration, with one USB mouse and one USB keyboard,
+you'll have to load the following modules (or have them built in to the
+kernel):
+
+	input.o
+	mousedev.o
+	keybdev.o
+	usbcore.o
+	usb-[uo]hci.o
+	hid.o
+
+  After this, the USB keyboard will work straight away, and the USB mouse
+will be available as a character device on major 13, minor 32:
+
+	crw-r--r--   1 root     root      13,  32 Mar 28 22:45 mouse0
+
+  This device, has to be created, unless you use devfs, in which case it's
+created automatically. The commands to do that are:
+
+	cd /dev
+	mkdir input
+	mknod input/mouse0 c 13 32
+
+  After that you have to point GPM (the textmode mouse cut&paste tool) and
+XFree to this device to use it - GPM should be called like:
+
+	gpm -t ps2 -m /dev/input/mouse0
+
+  And in X:
+
+	Section "Pointer"
+	    Protocol    "ImPS/2"
+	    Device      "/dev/input/mouse0"
+	    ZAxisMapping 4 5
+	EndSection
+
+  When you do all of the above, you can use your USB mouse and keyboard.
+
+3. Detailed Description
+~~~~~~~~~~~~~~~~~~~~~~~
+3.1 Device drivers
+~~~~~~~~~~~~~~~~~~
+  Device drivers are the modules that generate events. The events are
+however not useful without being handled, so you also will need to use some
+of the modules from section 3.2.
+
+3.1.1 hid.c
+~~~~~~~~~~~
+  Hid.c is the largest and most complex driver of the whole suite. It
+handles all HID devices, and because there is a very wide variety of them,
+and because the USB HID specification isn't simple, it needs to be this big.
+
+  Currently, it handles USB mice, joysticks, gamepads, steering wheels
+keyboards, trackballs and digitizers.
+
+ However, USB uses HID also for monitor controls, speaker controls, UPSs,
+LCDs and many other purposes.
+
+ The monitor and speaker controls should be easy to add to the hid/input
+interface, but for the UPSs and LCDs it doesn't make much sense. The driver
+doesn't support these yet, and a new, non-event interface should be designed
+for them. If you have any of these devices (I don't), feel free to design
+something and if it's good, it'll get into the driver.
+
+  The usage of the hid.o module is very simple, it takes no parameters,
+detects everything automatically and when a HID device is inserted, it
+detects it appropriately.
+
+  However, because the devices vary wildly, you might happen to have a
+device that doesn't work well. In that case #define DEBUG at the beginning
+of hid.c and send me the syslog traces.
+
+3.1.2 usbmouse.c
+~~~~~~~~~~~~~~~~
+  For embedded systems, for mice with broken HID descriptors and just any
+other use when the big hid.c wouldn't be a good choice, there is the
+usbmouse.c driver. It handles USB mice only. It uses a simpler HIDBP
+protocol. This also means the mice must support this simpler protocol. Not
+all do. If you don't have any strong reason to use this module, use hid.c
+instead.
+
+3.1.3 usbkbd.c
+~~~~~~~~~~~~~~
+  Much like usbmouse.c, this module talks to keyboards with a simpplified
+HIDBP protocol. It's smaller, but doesn't support any extra special keys.
+Use hid.c instead if there isn't any special reason to use this.
+
+3.1.4 wacom.c
+~~~~~~~~~~~~~
+  This is a driver for Wacom Graphire and Intuos tablets. Not for Wacom
+PenPartner, that one is handled by the HID driver. Although the Intuos and
+Graphire tablets claim that they are HID tablets as well, they are not and
+thus need this specific driver.
+
+3.1.5 wmforce.c
+~~~~~~~~~~~~~~~
+  A driver for the Logitech WingMan Force joysticks, when connected via the
+USB port. It works quite well, but there is no force feedback support yet,
+because the interface to do that is a trade secret of Immersion Corp, and
+even Logitech can't disclose it.
+
+  Support for Logitech WingMan Force Wheel isn't present in this driver, but
+if someone has the device, and is willing to cooperate, it should be a
+matter of a couple days to add it.
+
+3.2 Event handlers
+~~~~~~~~~~~~~~~~~~
+  Event handlers distrubite the events from the devices to userland and
+kernel, as needed.
+
+3.2.1 keybdev.c
+~~~~~~~~~~~~~~~
+  Keybdev is currently a rather ugly hack that translates the input events
+into architecture-specific keyboard raw mode (Xlated AT Set2 on x86), and
+passes them into the handle_scancode function of the keyboard.c module. This
+works well enough on all architectures that keybdev can generate rawmode on,
+other architectures can be added to it.
+
+  The right way would be to pass the events to keyboard.c directly, best if
+keyboard.c would itself be an event handler. This is done in the input
+patch, available on the webpage mentioned below.
+
+3.2.2 mousedev.c
+~~~~~~~~~~~~~~~~
+  Mousedev is also a hack to make programs that use mouse input work. It
+takes events from either mice or digitizers/tablets and makes a PS/2-style
+(a la /dev/psaux) mouse device available to the userland. Ideally, the
+programs could use a more reasonable interface, for example evdev.c
+
+  Mousedev devices in /dev/input (as shown above) are:
+
+	crw-r--r--   1 root     root      13,  32 Mar 28 22:45 mouse0
+	crw-r--r--   1 root     root      13,  33 Mar 29 00:41 mouse1
+	crw-r--r--   1 root     root      13,  34 Mar 29 00:41 mouse2
+	crw-r--r--   1 root     root      13,  35 Apr  1 10:50 mouse3
+
+and so on, up to mouse31. Each is assigned to a single mouse or digitizer,
+unless CONFIG_INPUT_MOUSEDEV_MIX is set. In that case all mice and
+digitizers share a single character device, mouse0, and even when none are
+connected, mouse0 is present. This is useful for hotplugging USB mice, so
+that programs can open the device even when no mice are present.
+
+  CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are the size
+of your screen (in pixels) in XFree86. This is needed if you want to use
+your digitizer in X, because it's movement is sent to X via a virtual PS/2
+mouse.
+
+  Mousedev.c will generate either PS/2, ImPS/2 (microsoft intellimouse) or
+GenPS/2 (genius netmouse/netscroll) protocols, depending on what the program
+wishes. You can set GPM and X to any of these. You'll need ImPS/2 if you
+want to make use of a wheel on a USB mouse and GenPS/2 if you want to use
+extra (up to 5) buttons. I'm not sure how much is GenPS/2 supported in X,
+though.
+
+3.2.3 joydev.c
+~~~~~~~~~~~~~~
+  Joydev implements v0.x and v1.x Linux joystick api, much like
+drivers/char/joystick/joystick.c. See joystick-api.txt in the Documentation
+subdirectory for details. Joydev does it on top of the input subsystem,
+though. As soon as any USB joystick is connected, it can be accessed in
+/dev/input on:
+
+	crw-r--r--   1 root     root      13,   0 Apr  1 10:50 js0
+	crw-r--r--   1 root     root      13,   1 Apr  1 10:50 js1
+	crw-r--r--   1 root     root      13,   2 Apr  1 10:50 js2
+	crw-r--r--   1 root     root      13,   3 Apr  1 10:50 js3
+
+And so on up to js31.
+
+3.2.4 evdev.c
+~~~~~~~~~~~~~
+  Evdev is the generic input event interface. It passes the events generated
+in the kernel straight to the program, with timestamps. The API is still
+evolving, but should be useable now. It's described in section 5.
+
+  This should be the way for GPM and X to get keyboard and mouse mouse
+events. It allows for multihead in X without any specific multihead kernel
+support. The event codes are the same on all architectures and are hardware
+independent.
+
+  The devices are in /dev/input:
+
+	crw-r--r--   1 root     root      13,  64 Apr  1 10:49 event0
+	crw-r--r--   1 root     root      13,  65 Apr  1 10:50 event1
+	crw-r--r--   1 root     root      13,  66 Apr  1 10:50 event2
+	crw-r--r--   1 root     root      13,  67 Apr  1 10:50 event3
+
+3. Contacts
+~~~~~~~~~~~
+  This effort has it's home page at:
+
+	http://www.suse.cz/development/input/
+
+You'll find both the latest HID driver and the complete Input driver there.
+There is also a mailing list for this:
+
+	majordomo@atrey.karlin.mff.cuni.cz
+
+Send "subscribe linux-input" to subscribe to it.
+
+4. Verifying if it works
+~~~~~~~~~~~~~~~~~~~~~~~~
+  Typing a couple keys on the keyboard should be enough to check that a USB
+keyboard works and is correctly connected to the kernel keyboard driver.
+
+  Doing a cat /dev/input/mouse0 (c, 13, 32) will verify that a mouse is also
+emulated, characters should appear if you move it.
+
+  You can test the joystick emulation with the 'jstest' utility, available
+in the joystick package (see Documentation/joystick.txt).
+
+  You can test the event devics with the 'evtest' utitily available on the
+input driver homepage (see the URL above).
+
+5. Event interface
+~~~~~~~~~~~~~~~~~~
+  Should you want to add event device support into any application (X, gpm,
+svgalib ...) I <vojtech@suse.cz> will be happy to provide you any help I
+can. Here goes a description of the current state of things, which is going
+to be extended, but not changed incompatibly as time goes:
+
+  You can use blocking and nonblocking reads, also select() on the
+/dev/inputX devices, and you'll always get a whole number of input events on
+a read. Their layout is:
+
+struct input_event {
+	struct timeval time;
+	unsigned short type;
+	unsigned short code;
+	unsigned int value;
+};
+
+  'time' is the timestamp, it returns the time at which the event happened.
+Type is for example EV_REL for relative momement, REL_KEY for a keypress or
+release. More types are defined in include/linux/input.h.
+
+  'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
+list is in include/linux/input.h.
+
+  'value' is the value the event carries. Either a relative change for
+EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
+release, 1 for keypress and 2 for autorepeat.
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt
--- v2.3.99-pre3/linux/Documentation/usb/ov511.txt	Tue Mar 14 19:10:38 2000
+++ linux/Documentation/usb/ov511.txt	Wed Apr  5 17:01:56 2000
@@ -5,42 +5,17 @@
 Author: Mark McClelland
 Homepage: http://alpha.dyndns.org/ov511
 
+NEW IN THIS VERSION:
+ o Support for OV511+
+ o Support for OV7620
+
 INTRODUCTION:
 
 This is a preliminary version of my OV511 Linux device driver. Currently, it can
 grab a frame in color (YUV420) at 640x480 or 320x240 using either vidcat or
 xawtv. Other utilities may work but have not yet been tested.
 
-NEW IN THIS VERSION:
- o Preliminary snapshot support
- o Experimental red-blue misalignment fixes
- o Better YUV420 color conversion
- o Module options
- o Finer-grained debug message control
- o Support for new cameras (4, 36)
- o Uses initcalls
-
-SUPPORTED CAMERAS:
-_________________________________________________________
-Manufacturer     | Model           | Custom ID | Status
------------------+-----------------+-----------+---------
-MediaForte       | MV300           | 0         | Working
-Aiptek           | HyperVCam ?     | 0         | Working
-NetView          | NV300M          | 0         | Working
-D-Link           | DSB-C300        | 3         | Working
-Hawking Tech.    | ???             | 3         | Working
-???              | Generic         | 4         | Untested
-Puretek          | PT-6007         | 5         | Working
-Creative Labs    | WebCam 3        | 21        | Working
-???              | Koala-Cam       | 36        | Untested
-Lifeview         | RoboCam         | 100       | Untested
-AverMedia        | InterCam Elite  | 102       | Working
-MediaForte       | MV300           | 112       | Working
-Omnivision       | OV7110 EV board | 112       | Working*
----------------------------------------------------------
-(*) uses OV7110 (monochrome)
-
-Any camera using the OV511 and the OV7610 CCD should work with this driver. The
+Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. The
 driver only detects known cameras though, based on their custom id number. If
 you have a currently unsupported camera, the ID number should be reported to you
 in the kernel logs. Please send me the model, manufacturer and ID number and I 
@@ -140,7 +115,7 @@
   DESC: The camera normally adjusts exposure, gain, and hue automatically. This
         can be set to 0 to disable this automatic adjustment. Note that there is
         currently no way to set these parameters manually once autoadjust is
-        disabled. (This feature is not working yet)
+        disabled.
 
   NAME: debug
   TYPE: integer (0-6)
@@ -174,7 +149,8 @@
  o Color streaming/capture at 640x480 and 320x240
  o YUV420 color
  o Monochrome
- o Setting/getting of saturation, contrast and brightness (no color yet)
+ o Setting/getting of saturation, contrast and brightness (no hue yet; only
+   works with OV7610, not the OV7620 or OV7620AE)
 
 EXPERIMENTAL FEATURES:
  o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and
@@ -197,13 +173,13 @@
  o Get hue (red/blue channel balance) adjustment working (in ov511_get_picture()
    and ov511_set_picture())
  o Get autoadjust disable working
- o Devise some clean way to support different types of CCDs (based on Custom ID)
- o OV511A support
  o V4L2 support (Probably not until it goes into the kernel)
  o Fix I2C initialization. Some people are reporting problems with reading the
    7610 registers. This could be due to timing differences, an excessive I2C
    clock rate, or a problem with ov511_i2c_read().
  o Get rid of the memory management functions (put them in videodev.c??)
+ o Setting of contrast and brightness not working with 7620
+ o Driver/camera state save/restore for when USB supports suspend/resume
 
 HOW TO CONTACT ME:
 
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/usb/proc_usb_info.txt linux/Documentation/usb/proc_usb_info.txt
--- v2.3.99-pre3/linux/Documentation/usb/proc_usb_info.txt	Thu Jan  6 12:57:47 2000
+++ linux/Documentation/usb/proc_usb_info.txt	Mon Mar 27 10:09:20 2000
@@ -1,16 +1,17 @@
 /proc/bus/usb filesystem output
 ===============================
-(version 19991218)
+(version 2000.03.24)
 
 
 The /proc filesystem for USB devices generates
 /proc/bus/usb/drivers and /proc/bus/usb/devices.
 
-/proc/bus/usb/drivers just lists the registered drivers,
-one per line.  Not very interesting or pretty.
+/proc/bus/usb/drivers lists the registered drivers,
+one per line, with each driver's USB minor dev node
+number range if applicable.
 
 In /proc/bus/usb/devices, each device's output has multiple
-lines (except for a root hub) of ASCII output.
+lines of ASCII output.
 I made it ASCII instead of binary on purpose, so that someone
 can obtain some useful data from it without the use of an
 auxiliary program.  However, with an auxiliary program, the numbers
@@ -22,11 +23,12 @@
 Each line is tagged with a one-character ID for that line:
 
 T = Topology (etc.)
-B = Bandwidth
+B = Bandwidth (applies only to USB host controllers, which are
+    virtualized as root hubs)
 D = Device descriptor info.
 P = Product ID info. (from Device descriptor, but they won't fit
     together on one line)
-S = String info
+S = String descriptors.
 C = Configuration descriptor info. (* = active configuration)
 I = Interface descriptor info.
 E = Endpoint descriptor info.
@@ -93,7 +95,17 @@
 |__String info tag
 
 S:  Product=ssss
-|   |__Product description of this device as read from the device.
+|   |__Product description of this device as read from the device,
+|      except that it is a generated string for USB host controllers
+|      (virtual root hubs), in the form "USB *HCI Root Hub".
+|__String info tag
+
+S:  SerialNumber=ssss
+|   |__Serial Number of this device as read from the device,
+|      except that it is a generated string for USB host controllers
+|      (virtual root hubs), and represent's the host controller's
+|      unique identification in the system (currently I/O or
+|      memory-mapped base address).
 |__String info tag
 
 
@@ -142,7 +154,7 @@
 script, it can display any selected lines (for example, only T, D,
 and P lines) and change their output format.  (The "procusb"
 Perl script is the beginning of this idea.  It will list only
-selected lines [selected from TDPCIE] or "All" lines from
+selected lines [selected from TBDPSCIE] or "All" lines from
 /proc/bus/usb/devices.)
 
 The Topology lines can be used to generate a graphic/pictorial
@@ -163,6 +175,13 @@
 
 T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
 B:  Alloc= 28/900 us ( 3%), #Int=  2, #Iso=  0
+D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0000 ProdID=0000 Rev= 0.00
+S:  Product=USB UHCI Root Hub
+S:  SerialNumber=dce0
+C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=  0mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
+E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=255ms
 T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 4
 D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
 P:  Vendor=0451 ProdID=1446 Rev= 1.00
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/usb/scanner-hp-sane.txt linux/Documentation/usb/scanner-hp-sane.txt
--- v2.3.99-pre3/linux/Documentation/usb/scanner-hp-sane.txt	Fri Jan 28 15:09:06 2000
+++ linux/Documentation/usb/scanner-hp-sane.txt	Mon Mar 27 09:44:58 2000
@@ -1,10 +1,11 @@
 Copyright (C) 1999, 2000 David E. Nelson
 
-Jan. 22, 2000
+Mar. 23, 2000
 
 CHANGES
 
 - Amended for Linux-2.3.40
+- Updated for multiple scanner support
 
 
 INTRODUCTION
@@ -30,13 +31,13 @@
 version SANE-1.0.1.  For instructions on building and installing SANE,
 refer to the various README files within the SANE distribution.
 
-The latest SANE HP backend available from http://www.kirchgessner.net.
+The latest SANE HP backend is available from http://www.kirchgessner.net.
 At the time of this writing, version 0.83 was available.
 
 
 OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
 
-NOTE: $INSTALL_DIR is the location where SANE was installed.  It may
+NOTE: $INSTALL_DIR is the location where SANE is installed.  It may
 be /usr/local, /usr, /opt or somewhere else.  If you don't know, ask
 your system administrator.
 
@@ -53,6 +54,9 @@
 
     /dev/usbscanner
     option connect-device
+
+NOTE: If you are using multiple scanners, make sure to have the correct
+devince, ie /dev/usbscanner0.  See scanner.txt for more info.
 
 3) You should now be able to use SANE (xscanimage or scanimage).
 
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/usb/scanner.txt linux/Documentation/usb/scanner.txt
--- v2.3.99-pre3/linux/Documentation/usb/scanner.txt	Fri Jan 28 15:09:06 2000
+++ linux/Documentation/usb/scanner.txt	Mon Mar 27 09:44:58 2000
@@ -1,12 +1,15 @@
 Copyright (C) 1999, 2000 David E. Nelson
 
-Jan. 22, 2000
+Mar. 23, 2000
 
 CHANGES
 
 - Amended for linux-2.3.40
 - Appended hp_scan.c to end of this README
 - Removed most references to HP
+- Updated uhci/ohci host controller info
+- Updated support for multiple scanner support
+- Updated supported scanners list
 
 
 OVERVIEW
@@ -28,10 +31,8 @@
 REQUIREMENTS
 
 A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
-(Compaq and others) hardware port should work.  However, I've only
-been able to really use an OHCI controller.  At the time of this
-writing, both uhci and ohci work with scanner.c *except* for the HP
-4100C which only works with ohci.  This problem is being investigated.
+(Compaq and others) hardware port should work.  At the time of this
+writing, there are two UHCI drivers and one OHCI.
 
 A Linux development kernel (2.3.x) with USB support enabled or a
 backported version to linux-2.2.x.  See http://www.linux-usb.org for
@@ -69,12 +70,26 @@
 (you may need to execute `depmod -a` to update the module
 dependencies).  Testing was performed only as modules, YMMV.
 
-Add a device for the USB scanner:
-  `mknod /dev/usbscanner c 180 48`
-
-Set appropriate permissions for /dev/usbscanner (don't forget about
-group and world permissions).  Both read and write permissions are
-required for proper operation.
+Beginning with version 0.4 of the driver, up to 16 scanners can be
+connected/used simultaneously.  If you intend to use more than
+one scanner at a time:
+
+   Add a device for the USB scanner:
+	`mknod /dev/usbscanner0 c 180 48`
+	`mknod /dev/usbscanner1 c 180 49`
+                      . 
+                      .
+	`mknod /dev/usb/scanner15 180 63`
+
+
+If you forsee using only one scanner:
+	`mknod /dev/usbscanner0 c 180 48`
+	`ln -s /dev/usbscanner0 /dev/usbscanner`
+
+
+Set appropriate permissions for /dev/usbscanner[0-15] (don't forget
+about group and world permissions).  Both read and write permissions
+are required for proper operation.
 
 Load the appropriate modules (if compiled as modules):
 
@@ -110,25 +125,49 @@
 At the time of this writing, the following scanners were supported by
 scanner.c:
 
+  Acer
+
+    Prisa AcerScan 620U
+
+  Agfa
+
+    SnapScan 1212U, SnapScan Touch
+
+  Genius
+
+    ColorPage Vivid Pro
+
   Hewlett Packard
 
     3300, 4100, 4200, 5200, 6200, 6300, PhotoSmart S20
 
-  AGFA
+  Microtek
 
-    SnapScan 1212U
+    ScanMaker X6-X6U, Phantom 336CX - C3, Phantom C6, ScanMaker V6USL,
+    ScanMaker V6UL - SpicyU
 
-  Umax
+  Mustek
 
-    Astra 2000U
+    1200 CU
+
+  Primax/Colorado
+
+    G2-300, G2-600, G2E-300, G2E-600, ReadyScan 636i, Colorado USB
+    19200, Colorado 600u, Colorado 1200u
 
   Seiko/Epson
 
-    Perfection 636, Perfection 1200U
+    Perfection Perfection 610, Perfection 636U/636Photo, Perfection
+    1200U/1200Photo
 
-  Mustek
+  Umax
+
+    Astra 1220U, 1236U, 2000U
+
+  Visioneer
+
+    OneTouch 5300, OneTouch 7600, 6100,
 
-    1200 CU
 
   User Specified.  See MODULE PARAMETERS for details.
 
@@ -142,11 +181,11 @@
 product=0x****' to the conf.modules/modules.conf file replacing the
 #'s and the *'s with the correct ID's.  The ID's can be retrieved from
 the messages file or using `cat /proc/bus/usb/devices` if USB /proc
-support was selected during kernel configuration.  In later kernels
-(2.3.38+), a new filesystem was introduced, usbdevfs.  To mount the
-filesystem, issue the command `mount -t usbdevfs /proc/bus/usb
-/proc/bus/usb`.  You can then issue ` cat /proc/bus/usb/devices` to
-extract USB device information.
+support was selected during kernel configuration.  **NOTE**:In later
+kernels (2.3.38+), a new filesystem was introduced, usbdevfs.  To
+mount the filesystem, issue the command `mount -t usbdevfs
+/proc/bus/usb /proc/bus/usb`.  You can then issue ` cat
+/proc/bus/usb/devices` to extract USB device information.
 
 
 BUGS
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/usb/usb-help.txt linux/Documentation/usb/usb-help.txt
--- v2.3.99-pre3/linux/Documentation/usb/usb-help.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/usb-help.txt	Mon Mar 27 09:44:58 2000
@@ -0,0 +1,16 @@
+usb-help.txt
+2000-March-24
+
+For USB help other than the readme files that are located in
+linux/Documentation/usb/*, see the following:
+
+Linux-USB project:  http://www.linux-usb.org
+  mirrors at        http://www.suse.cz/development/linux-usb/
+         and        http://usb.in.tum.de/linux-usb/
+Linux USB Guide:    http://linuxusbguide.sourceforge.net
+Linux-USB device overview (working devices and drivers):
+                    http://www.qbik.ch/usb/devices/
+    
+The Linux-USB mailing list is linux-usb@suse.com .
+
+###
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/video4linux/README.cpia linux/Documentation/video4linux/README.cpia
--- v2.3.99-pre3/linux/Documentation/video4linux/README.cpia	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/video4linux/README.cpia	Mon Mar 27 10:22:30 2000
@@ -0,0 +1,191 @@
+This is a driver for the CPiA PPC2 driven parallel connected
+Camera. For example the Creative WebcamII is CPiA driven.
+
+   ) [1]Peter Pregler, Linz 2000, published under the [2]GNU GPL
+
+---------------------------------------------------------------------------
+
+USAGE:
+
+General:
+========
+
+1) Make sure you have created the video devices (/dev/video*):
+
+- if you have a recent MAKEDEV do a 'cd /dev;./MAKEDEV video'
+- otherwise do a:
+
+cd /dev
+mknod video0 c 81 0
+ln -s video0 video
+
+2) Compile the kernel (see below for the list of options to use),
+   configure your parport and reboot.
+
+3) If all worked well you should get messages similar
+   to the following (your versions may be different) on the console:
+
+V4L-Driver for Vision CPiA based cameras v0.7.4
+parport0: read2 timeout.
+parport0: Multimedia device, VLSI Vision Ltd PPC2
+Parallel port driver for Vision CPiA based camera
+  CPIA Version: 1.20 (2.0)
+  CPIA PnP-ID: 0553:0002:0100
+  VP-Version: 1.0 0100
+  1 camera(s) found
+
+
+As modules:
+===========
+
+Make sure you have selected the following kernel options (you can
+select all stuff as modules):
+
+The cpia-stuff is in the section 'Character devices -> Video For Linux'.
+
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_1284=y
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+
+For autoloading of all those modules you need to tell kerneld some
+stuff. Add the following line to your kerneld config-file
+(e.g. /etc/modules.conf or wherever your distribution does store that
+stuff):
+
+options parport_pc dma=3 irq=7
+alias char-major-81 cpia_pp
+
+The first line tells the dma/irq channels to use. Those _must_ match
+the settings of your BIOS. Do NOT simply use the values above.  See
+Documentation/parport.txt for more information about this. The second
+line associates the video-device file with the driver. Of cause you
+can also load the modules once upon boot (usually done in /etc/modules).
+
+Linked into the kernel:
+=======================
+
+Make sure you have selected the following kernel options. Note that
+you cannot compile the parport-stuff as modules and the cpia-driver
+statically (the other way round is okay though).
+
+The cpia-stuff is in the section 'Character devices -> Video For Linux'.
+
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_1284=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_CPIA=y
+CONFIG_VIDEO_CPIA_PP=y
+
+To use DMA/irq you will need to tell the kernel upon boot time the
+hardware configuration of the parport. You can give the boot-parameter
+at the LILO-prompt or specify it in lilo.conf. I use the following
+append-line in lilo.conf:
+
+        append="parport=0x378,7,3"
+
+See Documentation/parport.txt for more information about the
+configuration of the parport and the values given above. Do not simply
+use the values given above.
+
+---------------------------------------------------------------------------
+FEATURES:
+
+- mmap/read v4l-interface (but no overlay)
+- image formats: CIF/QCIF, SIF/QSIF, various others used by isabel;
+  note: all sizes except CIF/QCIF are implemented by clipping, i.e.
+  pixels are not uploaded from the camera
+- palettes: VIDEO_PALETTE_GRAY, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB555,
+  VIDEO_PALETTE_RGB24, VIDEO_PALETTE_RGB32, VIDEO_PALETTE_YUYV,
+  VIDEO_PALETTE_UYVY, VIDEO_PALETTE_YUV422
+- state information (color balance, exposure, ...) is preserved between
+  device opens
+- complete control over camera via proc-interface (_all_ camera settings are
+  supported), there is also a python-gtk application available for this [3]
+- works under SMP (but the driver is completly serialized and synchronous)
+  so you get no benefit from SMP, but at least it does not crash your box
+- might work for non-Intel architecture, let us know about this
+
+---------------------------------------------------------------------------
+TESTED APPLICATIONS:
+
+- a simple test application based on Xt is available at [3]
+- another test-application based on gqcam-0.4 (uses GTK)
+- gqcam-0.6 should work
+- xawtv-3.x (also the webcam software)
+- xawtv-2.46
+- w3cam (cgi-interface and vidcat, e.g. you may try out 'vidcat  |xv
+  -maxpect -root -quit +noresetroot -rmode 5 -')
+- vic, the MBONE video conferencing tool (version 2.8ucl4-1)
+- isabel 3R4beta (barely working, but AFAICT all the problems are on
+  their side)
+- camserv-0.40
+
+See [3] for pointers to v4l-applications.
+
+---------------------------------------------------------------------------
+KNOWN PROBLEMS:
+
+- some applications do not handle the image format correctly, you will
+  see strange horizontal stripes instead of a nice picture -> make sure
+  your application does use a supported image size or queries the driver
+  for the actually used size (reason behind this: the camera cannot
+  provide any image format, so if size NxM is requested the driver will
+  use a format to the closest fitting N1xM1, the application should now
+  query for this granted size, most applications do not).
+- all the todo ;)
+- if there is not enough light and the picture is too dark try to
+  adjust the SetSensorFPS setting, automatic frame rate adjustment
+  has its price
+- do not try out isabel 3R4beta (built 135), you will be disappointed
+
+---------------------------------------------------------------------------
+TODO:
+
+- multiple camera support (struct camera or something) - This should work,
+  but hasn't been tested yet.
+- architecture independence?
+- SMP-safe asynchronous mmap interface
+- nibble mode for old parport interfaces
+- streaming capture, this should give a performance gain
+
+---------------------------------------------------------------------------
+IMPLEMENTATION NOTES:
+
+The camera can act in two modes, streaming or grabbing. Right now a
+polling grab-scheme is used. Maybe interrupt driven streaming will be
+used for a ansychronous mmap interface in the next major release of the
+driver. This might give a better frame rate.
+
+---------------------------------------------------------------------------
+THANKS (in no particular order):
+
+- Scott J. Bertin <sbertin@mindspring.com> for cleanups, the proc-filesystem
+  and much more
+- Henry Bruce <whb@vvl.co.uk> for providing developers information about
+  the CPiA chip, I wish all companies would treat Linux as seriously
+- Karoly Erdei <Karoly.Erdei@risc.uni-linz.ac.at> and RISC-Linz for being
+  my boss ;) resp. my employer and for providing me the hardware and
+  allow me to devote some working time to this project
+- Manuel J. Petit de Gabriel <mpetit@dit.upm.es> for providing help
+  with Isabel (http://isabel.dit.upm.es/)
+- Bas Huisman <bhuism@cs.utwente.nl> for writing the initial parport code
+- Jarl Totland <Jarl.Totland@bdc.no> for setting up the mailing list 
+  and maintaining the web-server[3]
+- Chris Whiteford <Chris@informinteractive.com> for fixes related to the
+  1.02 firmware
+- special kudos to all the tester whose machines crashed and/or
+  will crash. :)
+
+---------------------------------------------------------------------------
+REFERENCES
+
+   1. http://www.risc.uni-linz.ac.at/people/ppregler
+      mailto:Peter_Pregler@email.com
+   2. see the file COPYING in the top directory of the kernel tree
+   3. http://webcam.sourceforge.net/
diff -u --recursive --new-file v2.3.99-pre3/linux/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST
--- v2.3.99-pre3/linux/Documentation/video4linux/bttv/CARDLIST	Tue Mar  7 14:32:25 2000
+++ linux/Documentation/video4linux/bttv/CARDLIST	Sun Apr  2 15:32:49 2000
@@ -37,6 +37,7 @@
   card=35 - Chronos Video Shuttle II
   card=36 - Typhoon TView TV/FM Tuner
   card=37 - PixelView PlayTV pro
+  card=38 - TView99 CPH063
 
 tuner.o
   type=0 - Temic PAL
@@ -53,3 +54,4 @@
   type=11 - Alps TSBB5
   type=12 - Alps TSBE5
   type=13 - Alps TSBC5
+  type=14 - Temic 4006FH5
diff -u --recursive --new-file v2.3.99-pre3/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.99-pre3/linux/MAINTAINERS	Mon Mar 27 08:08:20 2000
+++ linux/MAINTAINERS	Mon Apr 10 23:02:59 2000
@@ -740,6 +740,12 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+NTFS FILESYSTEM
+P:	Anton Altaparmakov
+M:	aia21@cus.cam.ac.uk
+L:	linux-kernel@vger.rutgers.edu
+S:	Odd Fixes
+
 NVIDIA (RIVA) FRAMEBUFFER DRIVER
 P:	Jeff Garzik
 M:	jgarzik@mandrakesoft.com
@@ -822,8 +828,8 @@
 S:	Maintained
 
 PPP PROTOCOL DRIVERS AND COMPRESSORS
-P:	Al Longyear
-M:	longyear@pobox.com
+P:	Paul Mackerras
+M:	paulus@linuxcare.com
 L:	linux-ppp@vger.rutgers.edu
 S:	Maintained
 
diff -u --recursive --new-file v2.3.99-pre3/linux/Makefile linux/Makefile
--- v2.3.99-pre3/linux/Makefile	Mon Mar 27 08:08:20 2000
+++ linux/Makefile	Sun Apr  2 17:28:22 2000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 3
 SUBLEVEL = 99
-EXTRAVERSION = -pre3
+EXTRAVERSION = -pre4
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -88,7 +88,7 @@
 endif
 
 CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
-AFLAGS := $(CPPFLAGS)
+AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
 
 # use '-fno-strict-aliasing', but only if the compiler can take it
 CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi)
@@ -185,9 +185,9 @@
 export	NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -traditional -o $*.s $<
+	$(CPP) $(AFLAGS) -traditional -o $*.s $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
 
 Version: dummy
 	@rm -f include/linux/compile.h
@@ -374,6 +374,7 @@
 	rm -f net/khttpd/times.h
 	rm -f submenu*
 	rm -rf modules
+	$(MAKE) -C Documentation/DocBook clean
 
 mrproper: clean archmrproper
 	rm -f include/linux/autoconf.h include/linux/version.h
@@ -398,8 +399,7 @@
 	rm -f .hdepend scripts/mkdep scripts/split-include scripts/docproc
 	rm -f $(TOPDIR)/include/linux/modversions.h
 	rm -rf $(TOPDIR)/include/linux/modules
-	make clean TOPDIR=$(TOPDIR) -C Documentation/DocBook
-
+	$(MAKE) -C Documentation/DocBook mrproper
 distclean: mrproper
 	rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
 		-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
@@ -412,6 +412,14 @@
 sgmldocs: 
 	$(MAKE) -C $(TOPDIR)/Documentation/DocBook books
 
+psdocs: sgmldocs
+	$(MAKE) -C scripts docproc
+	$(MAKE) -C Documentation/DocBook ps
+
+pdfdocs: sgmldocs
+	$(MAKE) -C scripts docproc
+	$(MAKE) -C Documentation/DocBook pdf
+ 
 sums:
 	find . -type f -print | sort | xargs sum > .SUMS
 
@@ -434,7 +442,10 @@
 	find * -name '*.[hcS]' -type f -print | grep -v scripts/ | sort | xargs $(PERL) -w scripts/checkconfig.pl
 
 checkhelp:
-	$(PERL) -w scripts/checkhelp.pl `find * -name [cC]onfig.in -print`
+	find * -name [cC]onfig.in -print | sort | xargs $(PERL) -w scripts/checkhelp.pl
+
+checkincludes:
+	find * -name '*.[hcS]' -type f -print | sort | xargs $(PERL) -w scripts/checkincludes.pl
 
 ifdef CONFIGURATION
 ..$(CONFIGURATION):
diff -u --recursive --new-file v2.3.99-pre3/linux/Rules.make linux/Rules.make
--- v2.3.99-pre3/linux/Rules.make	Mon Mar 27 08:08:21 2000
+++ linux/Rules.make	Thu Mar 30 16:56:04 2000
@@ -48,7 +48,7 @@
 	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -S $< -o $@
 
 %.i: %.c
-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -E $< > $@
+	$(CPP) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) $< > $@
 
 %.o: %.c
 	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -c -o $@ $<
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile
--- v2.3.99-pre3/linux/arch/alpha/boot/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/alpha/boot/Makefile	Thu Mar 30 16:56:04 2000
@@ -11,9 +11,9 @@
 LINKFLAGS = -static -T bootloader.lds #-N -relax
 
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
+	$(CPP) $(AFLAGS) -traditional -o $*.o $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
 
 OBJECTS = head.o main.o
 BPOBJECTS = head.o bootp.o
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.3.99-pre3/linux/arch/alpha/config.in	Mon Mar 27 08:08:21 2000
+++ linux/arch/alpha/config.in	Mon Mar 27 14:18:32 2000
@@ -65,6 +65,7 @@
 # Most of these machines have ISA slots; not exactly sure which don't,
 # and this doesn't activate hordes of code, so do it always.
 define_bool CONFIG_ISA y
+define_bool CONFIG_SBUS n
 
 if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
 then
@@ -189,6 +190,8 @@
  
 if [ "$CONFIG_HOTPLUG" = "y" ] ; then
    source drivers/pcmcia/Config.in
+else
+   define_bool CONFIG_PCMCIA n
 fi
 
 bool 'Networking support' CONFIG_NET
@@ -274,7 +277,6 @@
 
 source drivers/char/Config.in
 
-source drivers/usb/Config.in
 
 #source drivers/misc/Config.in
 
@@ -299,6 +301,8 @@
   source drivers/sound/Config.in
 fi
 endmenu
+
+source drivers/usb/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.3.99-pre3/linux/arch/alpha/defconfig	Mon Mar 27 08:08:21 2000
+++ linux/arch/alpha/defconfig	Mon Mar 27 09:38:47 2000
@@ -46,11 +46,13 @@
 # CONFIG_ALPHA_SABLE is not set
 # CONFIG_ALPHA_TAKARA is not set
 CONFIG_ISA=y
+# CONFIG_SBUS is not set
 CONFIG_PCI=y
 CONFIG_ALPHA_BROKEN_IRQ_MASK=y
 # CONFIG_SMP is not set
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v2.3.99-pre3/linux/arch/alpha/kernel/Makefile	Sun Mar 19 18:35:30 2000
+++ linux/arch/alpha/kernel/Makefile	Thu Mar 30 16:56:04 2000
@@ -8,9 +8,9 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+	$(CPP) $(AFLAGS) -o $*.s $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+	$(CC) $(AFLAGS) -c -o $*.o $<
 
 O_TARGET := kernel.o
 O_OBJS   := entry.o traps.o process.o osf_sys.o irq.o irq_alpha.o \
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/alpha/kernel/irq_i8259.c linux/arch/alpha/kernel/irq_i8259.c
--- v2.3.99-pre3/linux/arch/alpha/kernel/irq_i8259.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/alpha/kernel/irq_i8259.c	Mon Mar 27 10:55:05 2000
@@ -146,12 +146,6 @@
 	 */
 	int j = *(vuip) IACK_SC;
 	j &= 0xff;
-	if (j == 7) {
-		if (!(inb(0x20) & 0x80)) {
-			/* It's only a passive release... */
-			return;
-		}
-	}
 	handle_irq(j, regs);
 }
 #endif
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.3.99-pre3/linux/arch/alpha/kernel/osf_sys.c	Mon Mar 27 08:08:21 2000
+++ linux/arch/alpha/kernel/osf_sys.c	Sun Apr  2 15:53:28 2000
@@ -42,7 +42,7 @@
 #include <asm/hwrpb.h>
 #include <asm/processor.h>
 
-extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
+extern long do_sys_mount(char *, char *, char *, int, void *);
 extern int do_pipe(int *);
 
 extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
@@ -319,20 +319,16 @@
 asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz)
 {
 	struct file *file;
-	struct dentry *dentry;
 	int retval;
 
-	lock_kernel();
 	retval = -EBADF;
 	file = fget(fd);
-	if (!file)
-		goto out;
-	dentry = file->f_dentry;
-	if (dentry)
-		retval = do_osf_statfs(dentry, buffer, bufsiz);
-	fput(file);
-out:
-	unlock_kernel();
+	if (file) {
+		lock_kernel();
+		retval = do_osf_statfs(file->f_dentry, buffer, bufsiz);
+		unlock_kernel();
+		fput(file);
+	}
 	return retval;
 }
 
@@ -363,32 +359,6 @@
 	uid_t exroot;
 };
 
-static struct dentry *getdev(const char *name, int rdonly)
-{
-	struct dentry *dentry;
-	struct inode *inode;
-	int retval;
-
-	dentry = namei(name);
-	retval = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		return dentry;
-
-	retval = -ENOTBLK;
-	inode = dentry->d_inode;
-	if (!S_ISBLK(inode->i_mode))
-		goto out_dput;
-
-	retval = -EACCES;
-	if (IS_NODEV(inode))
-		goto out_dput;
-	return dentry;
-
-out_dput:
-	dput(dentry);
-	return ERR_PTR(retval);
-}
-
 /*
  * We can't actually handle ufs yet, so we translate UFS mounts to
  * ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS
@@ -400,20 +370,18 @@
 static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
 {
 	int retval;
-	struct dentry *dentry;
 	struct cdfs_args tmp;
+	char *devname;
 
 	retval = -EFAULT;
 	if (copy_from_user(&tmp, args, sizeof(tmp)))
 		goto out;
-
-	dentry = getdev(tmp.devname, 0);
-	retval = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	devname = getname(tmp.devname);
+	retval = PTR_ERR(devname);
+	if (IS_ERR(devname))
 		goto out;
-	retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname, 
-				"ext2", flags, NULL);
-	dput(dentry);
+	retval = do_sys_mount(devname, dirname, "ext2", flags, NULL);
+	putname(devname);
 out:
 	return retval;
 }
@@ -421,20 +389,18 @@
 static int osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags)
 {
 	int retval;
-	struct dentry * dentry;
 	struct cdfs_args tmp;
+	char *devname;
 
 	retval = -EFAULT;
 	if (copy_from_user(&tmp, args, sizeof(tmp)))
 		goto out;
-
-	dentry = getdev(tmp.devname, 1);
-	retval = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	devname = getname(tmp.devname);
+	retval = PTR_ERR(devname);
+	if (IS_ERR(devname))
 		goto out;
-	retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname, 
-				"iso9660", flags, NULL);
-	dput(dentry);
+	retval = do_sys_mount(devname, dirname, "iso9660", flags, NULL);
+	putname(devname);
 out:
 	return retval;
 }
@@ -445,27 +411,36 @@
 
 	if (copy_from_user(&tmp, args, sizeof(tmp)))
 		return -EFAULT;
-	return do_mount(NULL, "", dirname, "proc", flags, NULL);
+
+	return do_sys_mount("", dirname, "proc", flags, NULL);
 }
 
 asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data)
 {
 	int retval = -EINVAL;
+	char *name;
 
 	lock_kernel();
+
+	name = getname(path);
+	retval = PTR_ERR(name);
+	if (IS_ERR(name))
+		goto out;
 	switch (typenr) {
 	case 1:
-		retval = osf_ufs_mount(path, (struct ufs_args *) data, flag);
+		retval = osf_ufs_mount(name, (struct ufs_args *) data, flag);
 		break;
 	case 6:
-		retval = osf_cdfs_mount(path, (struct cdfs_args *) data, flag);
+		retval = osf_cdfs_mount(name, (struct cdfs_args *) data, flag);
 		break;
 	case 9:
-		retval = osf_procfs_mount(path, (struct procfs_args *) data, flag);
+		retval = osf_procfs_mount(name, (struct procfs_args *) data, flag);
 		break;
 	default:
 		printk("osf_mount(%ld, %x)\n", typenr, flag);
 	}
+	putname(name);
+out:
 	unlock_kernel();
 	return retval;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/Makefile linux/arch/arm/Makefile
--- v2.3.99-pre3/linux/arch/arm/Makefile	Sun Mar 19 18:35:30 2000
+++ linux/arch/arm/Makefile	Mon Mar 27 10:46:29 2000
@@ -100,7 +100,7 @@
 
 LIBGCC		:= $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
 
-export	LIBGCC
+export	LIBGCC MACHINE PROCESSOR TEXTADDR
 
 ifeq ($(CONFIG_ARCH_A5K),y)
 MACHINE		 = a5k
@@ -216,7 +216,7 @@
 	@$(MAKEBOOT) clean
 	$(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds
 
-archdep:
+archdep: symlinks
 	@$(MAKEBOOT) dep
 
 # My testing targets (that short circuit a few dependencies)
@@ -256,3 +256,8 @@
 empeg_config:
 	$(RM) arch/arm/defconfig
 	cp arch/arm/def-configs/empeg arch/arm/defconfig
+
+thinclient_config:
+	$(RM) arch/arm/defconfig
+	cp arch/arm/def-configs/thinclient arch/arm/defconfig
+
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/boot/compressed/head-sa1100.S linux/arch/arm/boot/compressed/head-sa1100.S
--- v2.3.99-pre3/linux/arch/arm/boot/compressed/head-sa1100.S	Thu Mar  2 14:36:22 2000
+++ linux/arch/arm/boot/compressed/head-sa1100.S	Mon Mar 27 10:46:29 2000
@@ -17,8 +17,9 @@
 #error What am I doing here...
 #endif
 
-#ifdef CONFIG_SA1100_BRUTUS
-@ need to enter SVC mode
+#if	defined( CONFIG_SA1100_BRUTUS ) || \
+	defined( CONFIG_SA1100_THINCLIENT )
+@ Booting from Angel -- need to enter SVC mode
 #define angel_SWIreason_EnterSVC 0x17   /* from arm.h, in angel source */
 #define angel_SWI_ARM (0xEF123456 & 0xffffff)
 		mov	r0, #angel_SWIreason_EnterSVC
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.3.99-pre3/linux/arch/arm/config.in	Mon Mar 27 08:08:21 2000
+++ linux/arch/arm/config.in	Mon Mar 27 14:18:32 2000
@@ -53,6 +53,7 @@
 	    Itsy		CONFIG_SA1100_ITSY \
 	    LART		CONFIG_SA1100_LART \
 	    PLEB		CONFIG_SA1100_PLEB \
+	    ThinClient		CONFIG_SA1100_THINCLIENT \
 	    Victor		CONFIG_SA1100_VICTOR \
 	    Tifon		CONFIG_SA1100_TIFON" Brutus
 fi
@@ -136,6 +137,9 @@
    define_bool CONFIG_ISA_DMA n
 fi
 
+define_bool CONFIG_SBUS n
+define_bool CONFIG_PCMCIA n
+
 if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
    bool 'Kernel-mode alignment trap handler' CONFIG_ALIGNMENT_TRAP
 fi
@@ -218,7 +222,6 @@
    fi
 fi
 
-source drivers/usb/Config.in
 
 #source drivers/misc/Config.in
 
@@ -297,6 +300,8 @@
 fi
 
 source fs/Config.in
+
+source drivers/usb/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/def-configs/brutus linux/arch/arm/def-configs/brutus
--- v2.3.99-pre3/linux/arch/arm/def-configs/brutus	Tue Dec 14 01:27:23 1999
+++ linux/arch/arm/def-configs/brutus	Mon Mar 27 10:46:29 2000
@@ -2,6 +2,12 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_ARM=y
+CONFIG_UID16=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
 
 #
 # System and processor type
@@ -12,25 +18,21 @@
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_FOOTBRIDGE is not set
 CONFIG_ARCH_SA1100=y
-CONFIG_CPU_SA1100=y
 CONFIG_SA1100_BRUTUS=y
 # CONFIG_SA1100_EMPEG is not set
 # CONFIG_SA1100_ITSY is not set
 # CONFIG_SA1100_LART is not set
 # CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_THINCLIENT is not set
 # CONFIG_SA1100_VICTOR is not set
 # CONFIG_SA1100_TIFON is not set
+CONFIG_DISCONTIGMEM=y
 # CONFIG_ARCH_ACORN is not set
 CONFIG_CPU_32=y
 # CONFIG_CPU_26 is not set
 CONFIG_CPU_32v4=y
-CONFIG_CPU_SA110=y
+CONFIG_CPU_SA1100=y
 # CONFIG_ISA_DMA is not set
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
 # CONFIG_ALIGNMENT_TRAP is not set
 
 #
@@ -48,10 +50,16 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
 CONFIG_NWFPE=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_ARTHUR is not set
+
+#
+# Parallel port support
+#
 # CONFIG_PARPORT is not set
 CONFIG_CMDLINE=""
 
@@ -61,7 +69,6 @@
 # CONFIG_I2O is not set
 # CONFIG_I2O_PCI is not set
 # CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
 # CONFIG_I2O_SCSI is not set
 # CONFIG_I2O_PROC is not set
 
@@ -81,7 +88,6 @@
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
 # CONFIG_BLK_DEV_HD_ONLY is not set
-# CONFIG_BLK_CPQ_DA is not set
 
 #
 # Additional Block Devices
@@ -91,7 +97,6 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -100,9 +105,9 @@
 # Character devices
 #
 CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
+# CONFIG_VT_CONSOLE is not set
 CONFIG_SERIAL_SA1100=y
-# CONFIG_SERIAL_SA1100_CONSOLE is not set
+CONFIG_SERIAL_SA1100_CONSOLE=y
 # CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
@@ -110,11 +115,25 @@
 CONFIG_UNIX98_PTY_COUNT=32
 
 #
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
 # CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
 # CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
@@ -123,11 +142,6 @@
 # Video For Linux
 #
 # CONFIG_VIDEO_DEV is not set
-
-#
-# Joystick support
-#
-# CONFIG_JOYSTICK is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -137,9 +151,11 @@
 #
 # CONFIG_FTAPE is not set
 # CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
 
 #
-# USB drivers - not for the faint of heart
+# USB support
 #
 # CONFIG_USB is not set
 
@@ -148,16 +164,22 @@
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FB_SA1100=y
 # CONFIG_FB_MATROX is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_3DFX is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB2=y
 CONFIG_FBCON_CFB4=y
 CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_FONTWIDTH8_ONLY=y
 CONFIG_FBCON_FONTS=y
 CONFIG_FONT_8x8=y
@@ -172,30 +194,35 @@
 # CONFIG_SCSI is not set
 
 #
-# Filesystems
+# File systems
 #
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
-# CONFIG_UDF_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
 # CONFIG_UFS_FS is not set
 
 #
@@ -203,8 +230,6 @@
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
 # CONFIG_NLS is not set
 
 #
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/def-configs/footbridge linux/arch/arm/def-configs/footbridge
--- v2.3.99-pre3/linux/arch/arm/def-configs/footbridge	Thu Feb 10 17:11:02 2000
+++ linux/arch/arm/def-configs/footbridge	Mon Mar 27 10:46:29 2000
@@ -2,6 +2,7 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_ARM=y
+CONFIG_UID16=y
 
 #
 # Code maturity level options
@@ -19,16 +20,18 @@
 CONFIG_HOST_FOOTBRIDGE=y
 # CONFIG_ADDIN_FOOTBRIDGE is not set
 CONFIG_ARCH_EBSA285=y
-# CONFIG_CATS is not set
+# CONFIG_ARCH_CATS is not set
 CONFIG_ARCH_NETWINDER=y
+# CONFIG_ARCH_PERSONAL_SERVER is not set
 # CONFIG_ARCH_ACORN is not set
 CONFIG_CPU_32=y
 # CONFIG_CPU_26 is not set
 CONFIG_CPU_32v4=y
 CONFIG_CPU_SA110=y
 CONFIG_PCI=y
+CONFIG_PCI_NAMES=y
 CONFIG_ISA_DMA=y
-# CONFIG_ALIGNMENT_TRAP is not set
+CONFIG_ALIGNMENT_TRAP=y
 
 #
 # Loadable module support
@@ -42,7 +45,7 @@
 #
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_SYSCTL=y
 CONFIG_NWFPE=y
 CONFIG_KCORE_ELF=y
@@ -51,10 +54,14 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_ARTHUR is not set
+
+#
+# Parallel port support
+#
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
 CONFIG_PARPORT_PC_FIFO=y
-# CONFIG_PARPORT_PC_PCMCIA is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
 # CONFIG_PARPORT_ARC is not set
 # CONFIG_PARPORT_AMIGA is not set
 # CONFIG_PARPORT_MFC3 is not set
@@ -68,6 +75,11 @@
 # CONFIG_LEDS_CPU is not set
 
 #
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
 # I2O device support
 #
 # CONFIG_I2O is not set
@@ -87,64 +99,9 @@
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_IDEDISK_MULTI_MODE=y
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_IDEDMA_PCI_AUTO=y
-CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y
-CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
-CONFIG_BLK_DEV_OFFBOARD=y
-# CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_CMD646 is not set
-CONFIG_BLK_DEV_CY82C693=y
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_PDC202XX=y
-# CONFIG_PDC202XX_FORCE_BURST_BIT is not set
-# CONFIG_PDC202XX_FORCE_MASTER_MODE is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-CONFIG_BLK_DEV_SL82C105=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_CPQ_DA is not set
-
-#
-# Additional Block Devices
-#
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=m
-CONFIG_MD_STRIPED=m
-CONFIG_MD_MIRRORING=m
-CONFIG_MD_RAID5=m
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=y
 CONFIG_PARIDE=m
+CONFIG_PARIDE_PARPORT=y
 
 #
 # Parallel IDE high-level drivers
@@ -172,8 +129,17 @@
 CONFIG_PARIDE_KTTI=m
 CONFIG_PARIDE_ON20=m
 CONFIG_PARIDE_ON26=m
-CONFIG_BLK_DEV_IDE_MODES=y
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
 
 #
 # Character devices
@@ -183,7 +149,24 @@
 CONFIG_SERIAL=y
 CONFIG_SERIAL_CONSOLE=y
 # CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+CONFIG_SERIAL_21285=y
+CONFIG_SERIAL_21285_CONSOLE=y
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_STALDRV is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
 CONFIG_PRINTER=m
@@ -191,6 +174,14 @@
 # CONFIG_PPDEV is not set
 
 #
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_CHARDEV is not set
+
+#
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
@@ -214,13 +205,14 @@
 CONFIG_SOFT_WATCHDOG=y
 # CONFIG_PCWATCHDOG is not set
 # CONFIG_ACQUIRE_WDT is not set
-# CONFIG_21285_WATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+CONFIG_21285_WATCHDOG=m
 CONFIG_977_WATCHDOG=m
 CONFIG_DS1620=y
 CONFIG_NWBUTTON=y
 CONFIG_NWBUTTON_REBOOT=y
 CONFIG_NWFLASH=m
-# CONFIG_NVRAM is not set
+CONFIG_NVRAM=m
 CONFIG_RTC=y
 
 #
@@ -230,25 +222,29 @@
 # CONFIG_I2C_PARPORT is not set
 
 #
-# Radio/Video Adapters
+# Radio Adapters
 #
 # CONFIG_RADIO_CADET is not set
 # CONFIG_RADIO_RTRACK is not set
 # CONFIG_RADIO_RTRACK2 is not set
 # CONFIG_RADIO_AZTECH is not set
-# CONFIG_VIDEO_BT848 is not set
 # CONFIG_RADIO_GEMTEK is not set
-# CONFIG_VIDEO_PMS is not set
 # CONFIG_RADIO_MIROPCM20 is not set
-# CONFIG_VIDEO_BWQCAM is not set
-# CONFIG_VIDEO_CQCAM is not set
-# CONFIG_VIDEO_SAA5249 is not set
 # CONFIG_RADIO_SF16FMI is not set
-# CONFIG_VIDEO_STRADIS is not set
 # CONFIG_RADIO_TERRATEC is not set
 # CONFIG_RADIO_TRUST is not set
 # CONFIG_RADIO_TYPHOON is not set
 # CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
 # CONFIG_VIDEO_ZORAN is not set
 # CONFIG_VIDEO_BUZ is not set
 # CONFIG_VIDEO_ZR36120 is not set
@@ -263,15 +259,10 @@
 # CONFIG_FTAPE is not set
 # CONFIG_DRM is not set
 # CONFIG_DRM_TDFX is not set
-
-#
-# PCMCIA character device support
-#
-# CONFIG_PCMCIA_SERIAL_CS is not set
 # CONFIG_AGP is not set
 
 #
-# Support for USB
+# USB support
 #
 CONFIG_USB=m
 
@@ -279,32 +270,46 @@
 # USB Controllers
 #
 # CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=m
-CONFIG_USB_OHCI_DEBUG=y
-CONFIG_USB_OHCI_HCD=m
-CONFIG_USB_OHCI_VROOTHUB=y
 
 #
 # Miscellaneous USB options
 #
-# CONFIG_USB_DEBUG_ISOC is not set
-CONFIG_USB_PROC=y
-# CONFIG_USB_EZUSB is not set
+# CONFIG_USB_DEVICEFS is not set
 
 #
 # USB Devices
 #
-CONFIG_USB_MOUSE=m
-# CONFIG_USB_HP_SCANNER is not set
-CONFIG_USB_KBD=m
-CONFIG_USB_AUDIO=m
-CONFIG_USB_ACM=m
 CONFIG_USB_PRINTER=m
+CONFIG_USB_SCANNER=m
+CONFIG_USB_AUDIO=m
+# CONFIG_USB_ACM is not set
 # CONFIG_USB_SERIAL is not set
 # CONFIG_USB_CPIA is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_OV511 is not set
 # CONFIG_USB_DC2XX is not set
-# CONFIG_USB_SCSI is not set
+# CONFIG_USB_STORAGE is not set
 # CONFIG_USB_USS720 is not set
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_PLUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_DSBR is not set
+
+#
+# USB HID
+#
+# CONFIG_USB_HID is not set
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_WMFORCE is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
 
 #
 # Console drivers
@@ -342,10 +347,11 @@
 # CONFIG_FBCON_MAC is not set
 # CONFIG_FBCON_VGA_PLANES is not set
 CONFIG_FBCON_VGA=y
+# CONFIG_FBCON_HGA is not set
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
 CONFIG_FBCON_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
 # CONFIG_FONT_SUN8x16 is not set
 # CONFIG_FONT_SUN12x22 is not set
 # CONFIG_FONT_6x11 is not set
@@ -356,7 +362,7 @@
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
+CONFIG_PACKET_MMAP=y
 # CONFIG_NETLINK is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -371,12 +377,12 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 CONFIG_IP_ALIAS=y
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
 
 #
 # (it is safe to leave these untouched)
 #
-CONFIG_SKB_LARGE=y
+# CONFIG_SKB_LARGE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
@@ -409,7 +415,46 @@
 #
 # IrDA (infrared) support
 #
-# CONFIG_IRDA is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+CONFIG_IRDA_OPTIONS=y
+
+#
+#   IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+# CONFIG_IRDA_COMPRESSION is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+# CONFIG_IRPORT_SIR is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_NSC_FIR is not set
+CONFIG_WINBOND_FIR=m
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
 
 #
 # Network device support
@@ -421,6 +466,7 @@
 #
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_NET_SB1000 is not set
 
@@ -440,30 +486,30 @@
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_RTL8139 is not set
-# CONFIG_DM9102 is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
 # CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
+CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_DE4X5 is not set
-CONFIG_DEC_ELCP=m
+CONFIG_TULIP=m
 # CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_NE3210 is not set
 CONFIG_NE2K_PCI=y
+# CONFIG_RTL8129 is not set
+# CONFIG_8139TOO is not set
 # CONFIG_SIS900 is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
-# CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 
 #
@@ -491,7 +537,7 @@
 # CONFIG_NET_RADIO is not set
 
 #
-# Token Ring driver support
+# Token Ring devices
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
@@ -504,9 +550,70 @@
 # CONFIG_WAN is not set
 
 #
-# PCMCIA network device support
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
 #
-# CONFIG_NET_PCMCIA is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_OFFBOARD=y
+CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+# CONFIG_BLK_DEV_AEC6210 is not set
+# CONFIG_AEC6210_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD7409 is not set
+# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_CMD64X_RAID is not set
+CONFIG_BLK_DEV_CY82C693=y
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_HPT366_FIP is not set
+# CONFIG_HPT366_MODE3 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_PDC202XX=y
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_PDC202XX_MASTER is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
+CONFIG_BLK_DEV_IDE_MODES=y
 
 #
 # SCSI support
@@ -527,8 +634,12 @@
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
 # CONFIG_SOUND_AD1816 is not set
 # CONFIG_SOUND_SGALAXY is not set
+CONFIG_SOUND_ADLIB=m
+# CONFIG_SOUND_ACI_MIXER is not set
 # CONFIG_SOUND_CS4232 is not set
 # CONFIG_SOUND_SSCAPE is not set
 # CONFIG_SOUND_GUS is not set
@@ -539,9 +650,11 @@
 # CONFIG_SOUND_NM256 is not set
 # CONFIG_SOUND_MAD16 is not set
 # CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
 # CONFIG_SOUND_PSS is not set
 # CONFIG_SOUND_SOFTOSS is not set
 CONFIG_SOUND_SB=m
+# CONFIG_SOUND_AWE32_SYNTH is not set
 # CONFIG_SOUND_WAVEFRONT is not set
 # CONFIG_SOUND_MAUI is not set
 # CONFIG_SOUND_VIA82CXXX is not set
@@ -549,24 +662,18 @@
 # CONFIG_SOUND_OPL3SA1 is not set
 # CONFIG_SOUND_OPL3SA2 is not set
 # CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
 # CONFIG_SOUND_VIDC is not set
 CONFIG_SOUND_WAVEARTIST=m
-CONFIG_WAVEARTIST_BASE=250
-CONFIG_WAVEARTIST_IRQ=12
-CONFIG_WAVEARTIST_DMA=3
-CONFIG_WAVEARTIST_DMA2=7
 
 #
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
-
-#
-# Filesystems
+# File systems
 #
 # CONFIG_QUOTA is not set
 CONFIG_AUTOFS_FS=y
-CONFIG_ADFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
@@ -575,12 +682,15 @@
 # CONFIG_UMSDOS_FS is not set
 CONFIG_VFAT_FS=m
 # CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
 CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -606,7 +716,14 @@
 # Partition Types
 #
 CONFIG_PARTITION_ADVANCED=y
+CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_ICS is not set
+CONFIG_ACORN_PARTITION_ADFS=y
+# CONFIG_ACORN_PARTITION_POWERTEC is not set
+# CONFIG_ACORN_PARTITION_RISCIX is not set
 # CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
 # CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
 # CONFIG_BSD_DISKLABEL is not set
@@ -614,13 +731,6 @@
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-CONFIG_ACORN_PARTITION=y
-CONFIG_ACORN_PARTITION_ADFS=y
-# CONFIG_ACORN_PARTITION_ICS is not set
-# CONFIG_ACORN_PARTITION_POWERTEC is not set
-# CONFIG_ACORN_PARTITION_RISCIX is not set
 CONFIG_NLS=y
 
 #
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/def-configs/thinclient linux/arch/arm/def-configs/thinclient
--- v2.3.99-pre3/linux/arch/arm/def-configs/thinclient	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/def-configs/thinclient	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,379 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_UID16=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_FOOTBRIDGE is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_EMPEG is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_PLEB is not set
+CONFIG_SA1100_THINCLIENT=y
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_TIFON is not set
+CONFIG_DISCONTIGMEM=y
+# CONFIG_ARCH_ACORN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+CONFIG_CPU_32v4=y
+CONFIG_CPU_SA1100=y
+# CONFIG_ISA_DMA is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_NWFPE=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+# CONFIG_PARPORT is not set
+CONFIG_CMDLINE="root=nfs"
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_IDE is not set
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_ONLY is not set
+
+#
+# Additional Block Devices
+#
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_EFI_RTC is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Misc devices
+#
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FB=y
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FB_SA1100=y
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB2=y
+CONFIG_FBCON_CFB4=y
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_FONTWIDTH8_ONLY=y
+CONFIG_FBCON_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+CONFIG_NET_VENDOR_SMC=y
+# CONFIG_WD80x3 is not set
+# CONFIG_ULTRA is not set
+# CONFIG_ULTRA32 is not set
+CONFIG_SMC9194=y
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring driver support
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_LL is not set
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/defconfig linux/arch/arm/defconfig
--- v2.3.99-pre3/linux/arch/arm/defconfig	Mon Mar 27 08:08:21 2000
+++ linux/arch/arm/defconfig	Mon Mar 27 09:38:47 2000
@@ -32,6 +32,8 @@
 CONFIG_PCI_NAMES=y
 CONFIG_ISA=y
 CONFIG_ISA_DMA=y
+# CONFIG_SBUS is not set
+# CONFIG_PCMCIA is not set
 # CONFIG_ALIGNMENT_TRAP is not set
 
 #
@@ -537,6 +539,7 @@
 # CONFIG_BLK_DEV_AEC6210 is not set
 # CONFIG_AEC6210_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
 # CONFIG_AMD7409_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile
--- v2.3.99-pre3/linux/arch/arm/kernel/Makefile	Tue Mar 14 19:10:38 2000
+++ linux/arch/arm/kernel/Makefile	Thu Mar 30 16:56:04 2000
@@ -59,12 +59,12 @@
 all: kernel.o $(HEAD_OBJ) init_task.o
 
 $(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
+	$(CC) $(AFLAGS) -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
 
 include $(TOPDIR)/Rules.make
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_$@) -c -o $*.o $<
+	$(CC) $(AFLAGS) $(AFLAGS_$@) -c -o $*.o $<
 
 # Spell out some dependencies that `make dep' doesn't spot
 entry-armv.o: calls.S ../lib/constants.h
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/kernel/arch.c linux/arch/arm/kernel/arch.c
--- v2.3.99-pre3/linux/arch/arm/kernel/arch.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/arm/kernel/arch.c	Mon Mar 27 10:46:29 2000
@@ -23,6 +23,9 @@
 unsigned int number_mfm_drives;
 #endif
 
+extern void setup_initrd(unsigned int start, unsigned int size);
+extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz);
+
 /*
  * Architecture specific fixups.  This is where any
  * parameters in the params struct are fixed up, or
@@ -157,11 +160,15 @@
 #if defined(CONFIG_SA1100_BRUTUS)
 	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
 	setup_ramdisk( 1, 0, 0, 8192 );
-	setup_initrd( __phys_to_virt(0xd8000000), 0x00400000 );
+	setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 );
 #elif defined(CONFIG_SA1100_EMPEG)
 	ROOT_DEV = MKDEV( 3, 1 );  /* /dev/hda1 */
 	setup_ramdisk( 1, 0, 0, 4096 );
 	setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) );
+#elif defined(CONFIG_SA1100_THINCLIENT)
+	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+	setup_ramdisk( 1, 0, 0, 8192 );
+	setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
 #elif defined(CONFIG_SA1100_TIFON)
 	ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0);
 	setup_ramdisk(1, 0, 0, 4096);
@@ -198,7 +205,7 @@
 		"EBSA110",	/* RMK			*/
 		0x00000400,
 		NO_VIDEO,
-		1, 0, 1, 1, 1,
+		1, 0, 1, 0, 1,
 		NULL
 	},
 #endif
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c
--- v2.3.99-pre3/linux/arch/arm/kernel/armksyms.c	Tue Mar 14 19:10:38 2000
+++ linux/arch/arm/kernel/armksyms.c	Mon Mar 27 10:46:29 2000
@@ -190,6 +190,8 @@
 EXPORT_SYMBOL(uaccess_user);
 #endif
 
+	/* consistent area handling */
+EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(consistent_alloc);
 EXPORT_SYMBOL(consistent_free);
 EXPORT_SYMBOL(consistent_sync);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c
--- v2.3.99-pre3/linux/arch/arm/kernel/bios32.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/arm/kernel/bios32.c	Mon Mar 27 10:46:29 2000
@@ -504,6 +504,10 @@
 {
 }
 
+void pcibios_set_master(struct pci_dev *dev)
+{
+}
+
 int pcibios_enable_device(struct pci_dev *dev)
 {
 	u16 cmd, old_cmd;
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- v2.3.99-pre3/linux/arch/arm/kernel/entry-armv.S	Thu Mar  2 14:36:22 2000
+++ linux/arch/arm/kernel/entry-armv.S	Mon Mar 27 10:46:29 2000
@@ -201,6 +201,38 @@
 		.byte	 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2
 		.endm
 
+#elif defined(CONFIG_ARCH_SHARK)
+
+		.macro	disable_fiq
+		.endm
+
+		.macro	get_irqnr_and_base, irqnr, irqstat, base
+		mov	r4, #0xe0000000
+		orr	r4, r4, #0x20
+
+		mov	\irqstat, #0x0C
+		strb	\irqstat, [r4]			@outb(0x0C, 0x20) /* Poll command */
+		ldrb	\irqnr, [r4]			@irq = inb(0x20) & 7
+		and	\irqstat, \irqnr, #0x80
+		teq	\irqstat, #0
+		beq	43f
+		and	\irqnr, \irqnr, #7
+		teq	\irqnr, #2
+		bne	44f
+43:		mov	\irqstat, #0x0C
+		strb	\irqstat, [r4, #0x80]		@outb(0x0C, 0xA0) /* Poll command */
+		ldrb	\irqnr, [r4, #0x80]		@irq = (inb(0xA0) & 7) + 8
+		and	\irqstat, \irqnr, #0x80
+		teq	\irqstat, #0
+		beq	44f
+		and	\irqnr, \irqnr, #7
+		add	\irqnr, \irqnr, #8
+44:		teq	\irqstat, #0
+		.endm
+
+		.macro	irq_prio_table
+		.endm
+
 #elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE)
 #include <asm/dec21285.h>
 
@@ -295,9 +327,40 @@
 		.endm
 
 		.macro	get_irqnr_and_base, irqnr, irqstat, base
-		ldr	r4, =0xffe00000
-		ldr	\irqstat, [r4, #0x180]		@ get interrupts
+		ldr	\irqstat, =INTCONT_BASE
+		ldr	\base, =soft_irq_mask
+		ldr	\irqstat, [\irqstat]		@ get interrupts
+		ldr	\base, [\base]
+		mov	\irqnr, #0
+		and	\irqstat, \irqstat, \base	@ mask out disabled ones
+1001:		tst	\irqstat, #1
+		addeq	\irqnr, \irqnr, #1
+		moveq	\irqstat, \irqstat, lsr #1
+		tsteq	\irqnr, #32
+		beq	1001b
+		teq	\irqnr, #32
+		.endm
+
+		.macro	irq_prio_table
+		.ltorg
+		.bss
+ENTRY(soft_irq_mask)
+		.word	0
+		.text
+		.endm
+
+#elif defined(CONFIG_ARCH_TBOX)
+
+		.macro	disable_fiq
+		.endm
+
+		.macro	get_irqnr_and_base, irqnr, irqstat, base
+		ldr	\irqstat, =0xffff7000
+		ldr	\irqstat, [\irqstat]		@ get interrupts
+		ldr	\base, =soft_irq_mask
+		ldr	\base, [\base]
 		mov	\irqnr, #0
+		and	\irqstat, \irqstat, \base	@ mask out disabled ones
 1001:		tst	\irqstat, #1
 		addeq	\irqnr, \irqnr, #1
 		moveq	\irqstat, \irqstat, lsr #1
@@ -307,6 +370,11 @@
 		.endm
 
 		.macro	irq_prio_table
+		.ltorg
+		.bss
+ENTRY(soft_irq_mask)
+		.word	0
+		.text
 		.endm
 
 #elif defined(CONFIG_ARCH_SA1100)
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- v2.3.99-pre3/linux/arch/arm/kernel/process.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/arm/kernel/process.c	Mon Mar 27 10:46:29 2000
@@ -28,15 +28,24 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/arch/system.h>
 #include <asm/io.h>
 
+/*
+ * Values for cpu_do_idle()
+ */
+#define IDLE_WAIT_SLOW	0
+#define IDLE_WAIT_FAST	1
+#define IDLE_CLOCK_SLOW	2
+#define IDLE_CLOCK_FAST	3
+
 extern char *processor_modes[];
 extern void setup_mm_for_reboot(char mode);
 
 asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
 
-static int hlt_counter;
+static volatile int hlt_counter;
+
+#include <asm/arch/system.h>
 
 void disable_hlt(void)
 {
@@ -64,7 +73,9 @@
 __setup("hlt", hlt_setup);
 
 /*
- * The idle loop on an ARM...
+ * The idle thread.  We try to conserve power, while trying to keep
+ * overall latency low.  The architecture specific idle is passed
+ * a value to indicate the level of "idleness" of the system.
  */
 void cpu_idle(void)
 {
@@ -72,15 +83,13 @@
 	init_idle();
 	current->priority = 0;
 	current->counter = -100;
+
 	while (1) {
-		if (!hlt_counter)
-			arch_do_idle();
-		if (current->need_resched) {
-			schedule();
+		arch_idle();
+		schedule();
 #ifndef CONFIG_NO_PGT_CACHE
-			check_pgt_cache();
+		check_pgt_cache();
 #endif
-		}
 	}
 }
 
@@ -89,7 +98,7 @@
 int __init reboot_setup(char *str)
 {
 	reboot_mode = str[0];
-	return 0;
+	return 1;
 }
 
 __setup("reboot=", reboot_setup);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c
--- v2.3.99-pre3/linux/arch/arm/kernel/setup.c	Tue Mar 14 19:10:39 2000
+++ linux/arch/arm/kernel/setup.c	Mon Mar 27 10:46:29 2000
@@ -228,7 +228,7 @@
 	*cmdline_p = command_line;
 }
 
-static void __init
+void __init
 setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
 {
 #ifdef CONFIG_BLK_DEV_RAM
@@ -246,7 +246,7 @@
 /*
  * initial ram disk
  */
-static void __init setup_initrd(unsigned int start, unsigned int size)
+void __init setup_initrd(unsigned int start, unsigned int size)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (start == 0)
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile
--- v2.3.99-pre3/linux/arch/arm/lib/Makefile	Tue Mar 14 19:10:39 2000
+++ linux/arch/arm/lib/Makefile	Thu Mar 30 16:56:04 2000
@@ -37,7 +37,7 @@
 include $(TOPDIR)/Rules.make
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
 
 constants.h: getconsdata.o extractconstants.pl
 	$(PERL) extractconstants.pl $(OBJDUMP) > $@
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile
--- v2.3.99-pre3/linux/arch/arm/mm/Makefile	Sun Feb 13 19:29:03 2000
+++ linux/arch/arm/mm/Makefile	Thu Mar 30 16:56:04 2000
@@ -34,7 +34,7 @@
 include $(TOPDIR)/Rules.make
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_$@) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) $(AFLAGS_$@) -traditional -c -o $*.o $<
 
 # Special dependencies
 fault-armv.o: fault-common.c
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c
--- v2.3.99-pre3/linux/arch/arm/mm/mm-armv.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/arm/mm/mm-armv.c	Mon Mar 27 10:46:29 2000
@@ -293,9 +293,14 @@
  */
 void setup_mm_for_reboot(char mode)
 {
-	pgd_t *pgd = current->mm->pgd;
+	pgd_t *pgd;
 	pmd_t pmd;
 	int i;
+
+	if (current->mm && current->mm->pgd)
+		pgd = current->mm->pgd;
+	else
+		pgd = init_mm.pgd;
 
 	for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++) {
 		pmd_val(pmd) = (i << PGDIR_SHIFT) |
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c
--- v2.3.99-pre3/linux/arch/arm/mm/mm-sa1100.c	Fri Jan 21 18:19:16 2000
+++ linux/arch/arm/mm/mm-sa1100.c	Mon Mar 27 10:46:29 2000
@@ -36,10 +36,8 @@
 #if defined(CONFIG_SA1100_BRUTUS)
 	{ 0xc0000000, 0x00400000 },	/* 4MB */
 	{ 0xc8000000, 0x00400000 },	/* 4MB */
-#if 0	/* only two banks until the bootmem stuff is fixed... */
 	{ 0xd0000000, 0x00400000 },	/* 4MB */
 	{ 0xd8000000, 0x00400000 }	/* 4MB */
-#endif
 #elif defined(CONFIG_SA1100_EMPEG)
 	{ 0xc0000000, 0x00400000 },	/* 4MB */
 	{ 0xc8000000, 0x00400000 }	/* 4MB */
@@ -50,6 +48,8 @@
 	{ 0xc9000000, 0x00800000 }	/* 8MB */
 #elif defined(CONFIG_SA1100_VICTOR)
 	{ 0xc0000000, 0x00400000 }	/* 4MB */
+#elif defined(CONFIG_SA1100_THINCLIENT)
+	{ 0xc0000000, 0x01000000 }	/* 16MB */
 #elif defined(CONFIG_SA1100_TIFON)
 	{ 0xc0000000, 0x01000000 },	/* 16MB */
 	{ 0xc8000000, 0x01000000 }	/* 16MB */
@@ -67,12 +67,24 @@
 	{ 0xd0000000,      0x00000000,  0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
 #elif defined(CONFIG_SA1100_EMPEG)
 	{ EMPEG_FLASHBASE, 0x00000000,  0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+#elif defined(CONFIG_SA1100_THINCLIENT)
+#if 1
+	/* ThinClient: only one of those... */
+//	{ 0xd0000000,      0x00000000,  0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */
+	{ 0xd0000000,      0x08000000,  0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */
+#else
+	/* GraphicsClient: */
+	{ 0xd0000000,      0x08000000,  0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+	{ 0xd0800000,      0x18000000,  0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 3 */
+#endif
 #elif defined(CONFIG_SA1100_TIFON)
 	{ 0xd0000000,      0x00000000,  0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
 	{ 0xd0800000,      0x08000000,  0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */
 #endif
-#ifdef CONFIG_SA1101
+#if defined( CONFIG_SA1101 )
 	{ 0xdc000000,      SA1101_BASE, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1101 */
+#elif defined( CONFIG_SA1100_THINCLIENT )
+	{ 0xdc000000,      0x10000000,  0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
 #endif
 	{ 0xe0000000,      0x20000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */
 	{ 0xe4000000,      0x30000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/mm/mm-shark.c linux/arch/arm/mm/mm-shark.c
--- v2.3.99-pre3/linux/arch/arm/mm/mm-shark.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mm/mm-shark.c	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,25 @@
+/*
+ * arch/arm/mm/mm-shark.c
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/io.h>
+
+#include "map.h"
+
+struct map_desc io_desc[] __initdata = {
+	{ IO_BASE	, IO_START	, IO_SIZE	, DOMAIN_IO, 0, 1, 0, 0 },
+	{ FB_BASE	, FB_START	, FB_SIZE	, DOMAIN_IO, 0, 1, 0, 0 },
+	{ FBREG_BASE	, FBREG_START	, FBREG_SIZE	, DOMAIN_IO, 0, 1, 0, 0 }
+};
+
+
+#define SIZEOFMAP (sizeof(io_desc) / sizeof(io_desc[0]))
+
+unsigned int __initdata io_desc_size = SIZEOFMAP;
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.3.99-pre3/linux/arch/arm/mm/proc-sa110.S	Sun Mar 19 18:35:30 2000
+++ linux/arch/arm/mm/proc-sa110.S	Mon Mar 27 10:46:29 2000
@@ -435,17 +435,35 @@
 		ldmfd	sp!, {r1, pc}
 
 		.align	5
+idle:		mcr	p15, 0, r0, c15, c8, 2		@ Wait for interrupt
+		mov	r0, r0				@ safety
+		mov	pc, lr
+/*
+ * Function: *_do_idle
+ * Params  : r0 = call type:
+ *           0 = slow idle
+ *           1 = fast idle
+ *           2 = switch to slow processor clock
+ *           3 = switch to fast processor clock
+ */
 ENTRY(cpu_sa110_do_idle)
 ENTRY(cpu_sa1100_do_idle)
-		mov	r0, #0
-		mcr	p15, 0, r0, c15, c2, 2		@ Disable clock switching
-		ldr	r1, =FLUSH_BASE+FLUSH_OFFSET*2	@ load from uncacheable loc
-		ldr	r1, [r1, #0]
-		b	1f
+		mov	ip, #0
+		cmp	r0, #4
+		addcc	pc, pc, r0, lsl #2
+		mov	pc, lr
 
-		.align	5
-1:		mcr	p15, 0, r0, c15, c8, 2		@ Wait for interrupt
-		mcr	p15, 0, r0, c15, c1, 2		@ Enable clock switching
+		b	idle
+		b	idle
+		b	slow_clock
+		b	fast_clock
+
+fast_clock:	mcr	p15, 0, ip, c15, c1, 2		@ enable clock switching
+		mov	pc, lr
+
+slow_clock:	mcr	p15, 0, ip, c15, c2, 2		@ disable clock switching
+		ldr	r1, =UNCACHEABLE_ADDR		@ load from uncacheable loc
+		ldr	r1, [r1, #0]			@ force switch to MCLK
 		mov	pc, lr
 
 /*
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/boot/compressed/head.S linux/arch/i386/boot/compressed/head.S
--- v2.3.99-pre3/linux/arch/i386/boot/compressed/head.S	Sun Mar 19 18:35:30 2000
+++ linux/arch/i386/boot/compressed/head.S	Tue Mar 28 15:33:49 2000
@@ -23,7 +23,6 @@
  */
 .text
 
-#define __ASSEMBLY__
 #include <linux/linkage.h>
 #include <asm/segment.h>
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.99-pre3/linux/arch/i386/config.in	Mon Mar 27 08:08:21 2000
+++ linux/arch/i386/config.in	Tue Apr  4 22:42:30 2000
@@ -6,6 +6,7 @@
 
 define_bool CONFIG_X86 y
 define_bool CONFIG_ISA y
+define_bool CONFIG_SBUS n
 
 define_bool CONFIG_UID16 y
 
@@ -43,11 +44,17 @@
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
 fi
-if [ "$CONFIG_M586TSC" = "y" -o "$CONFIG_MK6" = "y" ]; then
+if [ "$CONFIG_M586TSC" = "y" ]; then
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
 fi
+if [ "$CONFIG_MK6" = "y" ]; then
+   define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_USE_3DNOW y
+   define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+fi
 if [ "$CONFIG_M686" = "y" ]; then
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
@@ -136,6 +143,8 @@
 
 if [ "$CONFIG_HOTPLUG" = "y" ] ; then
    source drivers/pcmcia/Config.in
+else
+   define_bool CONFIG_PCMCIA n
 fi
 
 bool 'System V IPC' CONFIG_SYSVIPC
@@ -252,7 +261,6 @@
 
 source drivers/char/Config.in
 
-source drivers/usb/Config.in
 
 #source drivers/misc/Config.in
 
@@ -278,6 +286,8 @@
    source drivers/sound/Config.in
 fi
 endmenu
+
+source drivers/usb/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.99-pre3/linux/arch/i386/defconfig	Mon Mar 27 08:08:21 2000
+++ linux/arch/i386/defconfig	Tue Apr 11 11:04:35 2000
@@ -3,6 +3,7 @@
 #
 CONFIG_X86=y
 CONFIG_ISA=y
+# CONFIG_SBUS is not set
 CONFIG_UID16=y
 
 #
@@ -22,11 +23,14 @@
 # CONFIG_MK7 is not set
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
+CONFIG_X86_CMPXCHG=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
+CONFIG_X86_L1_CACHE_BYTES=32
 CONFIG_X86_TSC=y
 CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_PGE=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
 # CONFIG_MICROCODE is not set
 CONFIG_NOHIGHMEM=y
 # CONFIG_HIGHMEM4G is not set
@@ -104,7 +108,10 @@
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_STRIPED is not set
 # CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
 
 #
 # Networking options
@@ -185,6 +192,7 @@
 # CONFIG_BLK_DEV_AEC6210 is not set
 # CONFIG_AEC6210_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
 # CONFIG_AMD7409_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
@@ -248,6 +256,7 @@
 # CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
@@ -375,6 +384,7 @@
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
 # CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
 # CONFIG_PCMCIA_3C575 is not set
 # CONFIG_PCMCIA_XIRTULIP is not set
 CONFIG_NET_PCMCIA_RADIO=y
@@ -467,17 +477,13 @@
 # CONFIG_PCMCIA_SERIAL_CB is not set
 
 #
-# USB support
-#
-# CONFIG_USB is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
 # CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
@@ -487,27 +493,34 @@
 # CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
@@ -515,6 +528,16 @@
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
 
 #
 # Partition Types
@@ -533,6 +556,11 @@
 # Sound
 #
 # CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v2.3.99-pre3/linux/arch/i386/kernel/Makefile	Tue Mar 14 19:10:39 2000
+++ linux/arch/i386/kernel/Makefile	Thu Mar 30 16:56:04 2000
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
 
 all: kernel.o head.o init_task.o
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c
--- v2.3.99-pre3/linux/arch/i386/kernel/acpi.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/i386/kernel/acpi.c	Wed Apr  5 17:04:37 2000
@@ -103,13 +103,57 @@
 
 enum
 {
-	ACPI_ENABLED,
-	ACPI_TABLES_ONLY,
-	ACPI_CHIPSET_ONLY,
-	ACPI_DISABLED,
+	ACPI_ENABLED =       0x00000000, // use ACPI if present
+	ACPI_DISABLED =      0x00000001, // never use ACPI
+	ACPI_TABLES_ONLY =   0x00000002, // never use chipset-specific driver
+	ACPI_CHIPSET_ONLY =  0x00000004, // always use chipset-specific driver
+	ACPI_IGNORE_ERRATA = 0x00000008, // ignore any listed platform errata
+	ACPI_COPY_TABLES  =  0x00000010, // copy ACPI tables before use
+	ACPI_TRUST_TABLES =  0x00000020, // use tables even after ioremap fails
+	ACPI_SCI_DISABLED =  0x00000040, // never enable ACPI (info. only)
+	ACPI_C2_DISABLED  =  0x00000080, // never enter C2
+	ACPI_C3_DISABLED  =  0x00000100, // never enter C3
+	ACPI_S1_DISABLED  =  0x00000200, // never enter S1
+	ACPI_S5_DISABLED  =  0x00000400, // never enter S5
 };
 
-static int acpi_enabled = ACPI_ENABLED;
+struct acpi_option_info
+{
+	const char *name;
+	unsigned long value;
+};
+
+static struct acpi_option_info acpi_options[] =
+{
+	{"on", ACPI_ENABLED},
+	{"off", ACPI_DISABLED},
+	{"tables", ACPI_TABLES_ONLY},
+	{"chipset", ACPI_CHIPSET_ONLY},
+	{"no-errata", ACPI_IGNORE_ERRATA},
+	{"copy-tables", ACPI_COPY_TABLES},
+	{"trust-tables", ACPI_TRUST_TABLES},
+	{"no-sci", ACPI_SCI_DISABLED},
+	{"no-c2", ACPI_C2_DISABLED},
+	{"no-c3", ACPI_C3_DISABLED},
+	{"no-s1", ACPI_S1_DISABLED},
+	{"no-s5", ACPI_S5_DISABLED},
+	{NULL, 0},
+};
+
+static unsigned long acpi_opts = ACPI_ENABLED;
+
+struct acpi_errata_info
+{
+	const char *oem;
+	const char *oem_table;
+	u32 oem_rev;
+	unsigned long options;
+};
+
+struct acpi_errata_info acpi_errata[] =
+{
+	{NULL, NULL, 0, 0},
+};
 
 // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
 static unsigned long acpi_slp_typ[] = 
@@ -171,7 +215,7 @@
 	 &acpi_p_lvl3_lat, sizeof(acpi_p_lvl3_lat),
 	 0644, NULL, &acpi_do_ulong},
 
-	{ACPI_P_LVL2_LAT, "enter_lvl2_lat",
+	{ACPI_ENTER_LVL2_LAT, "enter_lvl2_lat",
 	 &acpi_enter_lvl2_lat, sizeof(acpi_enter_lvl2_lat),
 	 0644, NULL, &acpi_do_ulong},
 
@@ -405,6 +449,16 @@
 			printk(KERN_ERR
 			       "ACPI: unreserved table memory @ 0x%p!\n",
 			       (void*) addr);
+
+			if (acpi_opts & ACPI_TRUST_TABLES) {
+				/* OK, trust that the table is there
+				 * if it isn't you'll get an OOPS here
+				 */
+				static u32 sig;
+				table = (struct acpi_table *)
+					phys_to_virt(addr);
+				sig = table->signature;
+			}
 		}
 	}
 	return table;
@@ -423,14 +477,33 @@
 /*
  * Initialize an ACPI table
  */
-static void acpi_init_table(struct acpi_table_info *info,
-			    void *data,
-			    int mapped)
+static int acpi_init_table(struct acpi_table_info *info,
+			   void *data,
+			   int mapped)
 {
 	struct acpi_table *table = (struct acpi_table*) data;
+
+	info->table = NULL;
+	info->size = 0;
+	info->mapped = 0;
+
+	if (!table || table->signature != info->expected_signature)
+		return -EINVAL;
+
+	if (mapped && (acpi_opts & ACPI_COPY_TABLES)) {
+		struct acpi_table *copy
+			= kmalloc(table->length, GFP_KERNEL);
+		if (!copy)
+			return -ENOMEM;
+		memcpy(copy, table, table->length);
+		table = copy;
+		mapped = 0;
+	}
+
 	info->table = table;
-	info->size = (size_t)(table ? table->length:0);
+	info->size = (size_t) table->length;
 	info->mapped = mapped;
+	return 0;
 }
 
 /*
@@ -502,22 +575,13 @@
 	rsdt_entry_count = (int) ((rsdt->length - sizeof(*rsdt)) >> 2);
 	while (rsdt_entry_count) {
 		struct acpi_table *dt = acpi_map_table(*rsdt_entry);
-		if (dt && dt->signature == ACPI_FACP_SIG) {
-			struct acpi_facp *facp = (struct acpi_facp*) dt;
-			acpi_init_table(&acpi_facp, dt, 1);
+		if (!acpi_init_table(&acpi_facp, dt, 1)) {
+			struct acpi_facp *facp
+				= (struct acpi_facp*) acpi_facp.table;
 
 			// map DSDT if it exists
 			dt = acpi_map_table(facp->dsdt);
-			if (dt && dt->signature == ACPI_DSDT_SIG)
-				acpi_init_table(&acpi_dsdt, dt, 1);
-			else
-				acpi_unmap_table(dt);
-
-			// map FACS if it exists
-			dt = acpi_map_table(facp->facs);
-			if (dt && dt->signature == ACPI_FACS_SIG)
-				acpi_init_table(&acpi_facs, dt, 1);
-			else
+			if (acpi_init_table(&acpi_dsdt, dt, 1))
 				acpi_unmap_table(dt);
 		}
 		else {
@@ -769,6 +833,15 @@
 }
 
 /*
+ * Is SCI to be enabled?
+ */
+static inline int
+acpi_sci_enabled(void)
+{
+	return !(acpi_opts & ACPI_SCI_DISABLED);
+}
+
+/*
  * Is ACPI enabled or not?
  */
 static inline int acpi_is_enabled(struct acpi_facp *facp)
@@ -781,7 +854,7 @@
  */
 static int acpi_enable(struct acpi_facp *facp)
 {
-	if (facp->smi_cmd)
+	if (facp->smi_cmd && acpi_sci_enabled())
 		outb(facp->acpi_enable, facp->smi_cmd);
 	return (acpi_is_enabled(facp) ? 0:-1);
 }
@@ -791,16 +864,20 @@
  */
 static int acpi_disable(struct acpi_facp *facp)
 {
-	// disable and clear any pending events
-	acpi_write_gpe_enable(facp, 0);
-	while (acpi_read_gpe_status(facp))
-		acpi_write_gpe_status(facp, acpi_read_gpe_status(facp));
-	acpi_write_pm1_enable(facp, 0);
-	acpi_write_pm1_status(facp, acpi_read_pm1_status(facp));
-
-	/* writing acpi_disable to smi_cmd would be appropriate
-	 * here but this causes a nasty crash on many systems
-	 */
+	if (facp->smi_cmd && acpi_sci_enabled()) {
+		// disable and clear any pending events
+		acpi_write_gpe_enable(facp, 0);
+		while (acpi_read_gpe_status(facp)) {
+			acpi_write_gpe_status(facp,
+					      acpi_read_gpe_status(facp));
+		}
+		acpi_write_pm1_enable(facp, 0);
+		acpi_write_pm1_status(facp, acpi_read_pm1_status(facp));
+
+		/* writing acpi_disable to smi_cmd would be appropriate
+		 * here but this causes a nasty crash on many systems
+		 */
+	}
 
 	return 0;
 }
@@ -860,7 +937,7 @@
 sleep3:
 	sleep_level = 3;
 	if (!acpi_p_lvl3_tested) {
-		printk("ACPI C3 works\n");
+		printk(KERN_INFO "ACPI C3 works\n");
 		acpi_p_lvl3_tested = 1;
 	}
 	wake_on_busmaster(facp);
@@ -916,7 +993,7 @@
 sleep2:
 	sleep_level = 2;
 	if (!acpi_p_lvl2_tested) {
-		printk("ACPI C2 works\n");
+		printk(KERN_INFO "ACPI C2 works\n");
 		acpi_p_lvl2_tested = 1;
 	}
 	wake_on_busmaster(facp);	/* Required to track BM activity.. */
@@ -1006,47 +1083,52 @@
 	}
 }
 
-
 /*
  * Enter system sleep state
  */
-static void acpi_enter_sx(acpi_sstate_t state)
+static int acpi_enter_sx(acpi_sstate_t state)
 {
-	unsigned long slp_typ = acpi_slp_typ[(int) state];
-	if (slp_typ != ACPI_SLP_TYP_DISABLED) {
-		struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table;
-		u16 typa, typb, value;
-
-		// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
-		typa = (slp_typ >> 8) & 0xff;
-		typb = slp_typ & 0xff;
-
-		typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
-		typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
-
-		acpi_sleep_start = get_cmos_time();
-		acpi_enter_dx(ACPI_D3);
-		acpi_sleep_state = state;
-
-		// clear wake status
-		acpi_write_pm1_status(facp, ACPI_WAK);
-
-		// set SLP_TYPa/b and SLP_EN
-		if (facp->pm1a_cnt) {
-			value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
-			outw(value | typa | ACPI_SLP_EN, facp->pm1a_cnt);
-		}
-		if (facp->pm1b_cnt) {
-			value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
-			outw(value | typb | ACPI_SLP_EN, facp->pm1b_cnt);
-		}
-
-		// wait until S1 is entered
-		while (!(acpi_read_pm1_status(facp) & ACPI_WAK)) ;
-		// finished sleeping, update system time
-		acpi_update_clock();
-		acpi_enter_dx(ACPI_D0);
+	unsigned long slp_typ;
+	u16 typa, typb, value;
+	struct acpi_facp *facp;
+
+	slp_typ = acpi_slp_typ[(int) state];
+	if (slp_typ == ACPI_SLP_TYP_DISABLED)
+		return -EPERM;
+
+	// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
+	typa = (slp_typ >> 8) & 0xff;
+	typb = slp_typ & 0xff;
+	
+	typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
+	typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
+
+	acpi_sleep_start = get_cmos_time();
+	acpi_enter_dx(ACPI_D3);
+	acpi_sleep_state = state;
+
+	facp = (struct acpi_facp*) acpi_facp.table;
+	
+	// clear wake status
+	acpi_write_pm1_status(facp, ACPI_WAK);
+	
+	// set SLP_TYPa/b and SLP_EN
+	if (facp->pm1a_cnt) {
+		value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
+		outw(value | typa | ACPI_SLP_EN, facp->pm1a_cnt);
+	}
+	if (facp->pm1b_cnt) {
+		value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
+		outw(value | typb | ACPI_SLP_EN, facp->pm1b_cnt);
 	}
+	
+	// wait until S1 is entered
+	while (!(acpi_read_pm1_status(facp) & ACPI_WAK)) ;
+	// finished sleeping, update system time
+	acpi_update_clock();
+	acpi_enter_dx(ACPI_D0);
+	
+	return 0;
 }
 
 /*
@@ -1113,6 +1195,42 @@
 }
 
 /*
+ * Determine if modification of value is permitted
+ */
+static int
+acpi_verify_mod(int ctl_name)
+{
+	switch (ctl_name) {
+	case ACPI_PM1_ENABLE:
+	case ACPI_GPE_ENABLE:
+	case ACPI_GPE_LEVEL:
+		if (!acpi_sci_enabled())
+			return -EPERM;
+		break;
+	case ACPI_P_LVL2_LAT:
+	case ACPI_ENTER_LVL2_LAT:
+		if (acpi_opts & ACPI_C2_DISABLED)
+			return -EPERM;
+		break;
+	case ACPI_P_LVL3_LAT:
+	case ACPI_ENTER_LVL3_LAT:
+		if (acpi_opts & ACPI_C3_DISABLED)
+			return -EPERM;
+		break;
+	case ACPI_S1_SLP_TYP:
+	case ACPI_SLEEP:
+		if (acpi_opts & ACPI_S1_DISABLED)
+			return -EPERM;
+		break;
+	case ACPI_S5_SLP_TYP:
+		if (acpi_opts & ACPI_S5_DISABLED)
+			return -EPERM;
+		break;
+	}
+	return 0;
+}
+
+/*
  * Examine/modify value
  */
 static int acpi_do_ulong(ctl_table *ctl,
@@ -1141,6 +1259,9 @@
 			*len = 0;
 	}
 	else {
+		if (acpi_verify_mod(ctl->ctl_name))
+			return -EPERM;
+
 		size = sizeof(str) - 1;
 		if (size > *len)
 			size = *len;
@@ -1313,6 +1434,9 @@
 	}
 	else
 	{
+		if (acpi_verify_mod(ctl->ctl_name))
+			return -EPERM;
+
 		// fetch user value
 		size = sizeof(str) - 1;
 		if (size > *len)
@@ -1443,24 +1567,71 @@
 	}
 	else
 	{
-#ifdef CONFIG_ACPI_S1_SLEEP
-		acpi_enter_sx(ACPI_S1);
-#endif
+		if (acpi_verify_mod(ctl->ctl_name) || acpi_enter_sx(ACPI_S1))
+			return -EPERM;
 	}
 	file->f_pos += *len;
 	return 0;
 }
 
+/*
+ * Parse command line options
+ */
+static int __init acpi_setup(char *str)
+{
+	while (str && *str) {
+		struct acpi_option_info *opt = acpi_options;
+		while (opt->name) {
+			if (!strncmp(str, opt->name, strlen(opt->name))) {
+				acpi_opts |= opt->value;
+				break;
+			}
+			opt++;
+		}
+		str = strpbrk(str, ",");
+		if (str)
+			str += strspn(str, ",");
+	}
+
+	if (acpi_opts)
+		printk(KERN_INFO "ACPI: options 0x%08lx\n", acpi_opts);
+
+	return 1;
+}
+
+/*
+ * kernel/module command line interfaces are both "acpi=OPTION,OPTION,..."
+ */
+__setup("acpi=", acpi_setup);
+
+static char * __initdata acpi = NULL;
+
+MODULE_DESCRIPTION("ACPI driver");
+MODULE_PARM(acpi, "s");
+MODULE_PARM_DESC(acpi, "ACPI driver command line");
 
 /*
  * Initialize and enable ACPI
  */
-static int __init acpi_init(void)
+int __init acpi_init(void)
 {
 	struct acpi_facp *facp = NULL;
 
-	switch (acpi_enabled) {
-	case ACPI_ENABLED:
+	if (acpi)
+		acpi_setup(acpi);
+
+	if (acpi_opts & ACPI_DISABLED) {
+		return -ENODEV;
+	}
+	else if (acpi_opts & ACPI_TABLES_ONLY) {
+		if (acpi_find_tables())
+			return -ENODEV;
+	}
+	else if (acpi_opts & ACPI_CHIPSET_ONLY) {
+		if (acpi_find_chipset())
+			return -ENODEV;
+	}
+	else {
 		switch (acpi_find_tables()) {
 		case 0:
 			// found valid ACPI tables
@@ -1474,17 +1645,6 @@
 			// found broken ACPI tables
 			return -ENODEV;
 		}
-		break;
-	case ACPI_TABLES_ONLY:
-		if (acpi_find_tables())
-			return -ENODEV;
-		break;
-	case ACPI_CHIPSET_ONLY:
-		if (acpi_find_chipset())
-			return -ENODEV;
-		break;
-	case ACPI_DISABLED:
-		return -ENODEV;
 	}
 
 	facp = (struct acpi_facp*) acpi_facp.table;
@@ -1502,12 +1662,14 @@
 	 * control in the /proc interfaces.
 	 */
 	if (facp->p_lvl2_lat
-	    && facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
+	    && facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT
+	    && !acpi_verify_mod(ACPI_P_LVL2_LAT)) {
 		acpi_p_lvl2_lat = ACPI_uS_TO_TMR_TICKS(facp->p_lvl2_lat);
 		acpi_enter_lvl2_lat = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000);
 	}
 	if (facp->p_lvl3_lat
-	    && facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
+	    && facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT
+	    && !acpi_verify_mod(ACPI_P_LVL3_LAT)) {
 		acpi_p_lvl3_lat = ACPI_uS_TO_TMR_TICKS(facp->p_lvl3_lat);
 		acpi_enter_lvl3_lat
 			= ACPI_uS_TO_TMR_TICKS(facp->p_lvl3_lat * 5);
@@ -1519,6 +1681,7 @@
 	}
 
 	if (facp->sci_int
+	    && acpi_sci_enabled()
 	    && request_irq(facp->sci_int,
 			   acpi_irq,
 			   SA_INTERRUPT | SA_SHIRQ,
@@ -1529,6 +1692,10 @@
 		goto err_out;
 	}
 
+#ifndef CONFIG_ACPI_S1_SLEEP
+	acpi_opts |= ACPI_S1_DISABLED;
+#endif
+
 	acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
 
 	pm_power_off = acpi_power_off;
@@ -1559,7 +1726,7 @@
 /*
  * Disable and deinitialize ACPI
  */
-static void __exit acpi_exit(void)
+void __exit acpi_exit(void)
 {
 	struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table;
 
@@ -1570,7 +1737,7 @@
 	acpi_disable(facp);
 	acpi_release_ioports(facp);
 
-	if (facp->sci_int)
+	if (facp->sci_int && acpi_sci_enabled())
 		free_irq(facp->sci_int, &acpi_facp);
 
 	acpi_destroy_tables();
@@ -1581,29 +1748,5 @@
 	pm_active = 0;
 }
 
-/*
- * Parse kernel command line options
- */
-static int __init acpi_setup(char *str)
-{
-	while (str && *str) {
-		if (strncmp(str, "on", 2) == 0)
-			acpi_enabled = ACPI_ENABLED;
-		else if (strncmp(str, "tables", 6) == 0)
-			acpi_enabled = ACPI_TABLES_ONLY;
-		else if (strncmp(str, "chipset", 7) == 0)
-			acpi_enabled = ACPI_CHIPSET_ONLY;
-		else if (strncmp(str, "off", 3) == 0)
-			acpi_enabled = ACPI_DISABLED;
-		str = strpbrk(str, ",");
-		if (str)
-			str += strspn(str, ",");
-	}
-	return 1;
-}
-
-__setup("acpi=", acpi_setup);
-
 module_init(acpi_init);
 module_exit(acpi_exit);
-
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.3.99-pre3/linux/arch/i386/kernel/head.S	Sun Mar 19 18:35:30 2000
+++ linux/arch/i386/kernel/head.S	Tue Apr 11 12:20:12 2000
@@ -70,22 +70,28 @@
  */
 #define cr4_bits mmu_cr4_features-__PAGE_OFFSET
 	cmpl $0,cr4_bits
-	je 1f
-	movl %cr4,%eax		# Turn on 4Mb pages
+	je 3f
+	movl %cr4,%eax		# Turn on paging options (PSE,PAE,..)
 	orl cr4_bits,%eax
 	movl %eax,%cr4
+	jmp 3f
+1:
 #endif
 /*
- * Setup paging (intialize tables, then switch them on)
+ * Initialize page tables
  */
-1:
 	movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */
 	movl $007,%eax		/* "007" doesn't mean with right to kill, but
 				   PRESENT+RW+USER */
-1:	stosl
+2:	stosl
 	add $0x1000,%eax
 	cmp $empty_zero_page-__PAGE_OFFSET,%edi
-	jne 1b
+	jne 2b
+
+/*
+ * Enable paging
+ */
+3:
 	movl $swapper_pg_dir-__PAGE_OFFSET,%eax
 	movl %eax,%cr3		/* set the page table pointer.. */
 	movl %cr0,%eax
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.3.99-pre3/linux/arch/i386/kernel/irq.c	Tue Mar 14 19:10:39 2000
+++ linux/arch/i386/kernel/irq.c	Mon Mar 27 14:17:05 2000
@@ -862,7 +862,7 @@
  */
  
 /**
- *	probe_irq_mask
+ *	probe_irq_mask - scan a bitmap of interrupt lines
  *	@val:	mask of interrupts to consider
  *
  *	Scan the ISA bus interrupt lines and return a bitmap of
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.3.99-pre3/linux/arch/i386/kernel/mtrr.c	Tue Mar 14 19:10:39 2000
+++ linux/arch/i386/kernel/mtrr.c	Mon Mar 27 14:17:05 2000
@@ -1281,7 +1281,7 @@
 }   /*  End Function mtrr_add  */
 
 /**
- *	mtrr_del
+ *	mtrr_del - delete a memory type region
  *	@reg: Register returned by mtrr_add
  *	@base: Physical base address
  *	@size: Size of region
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c
--- v2.3.99-pre3/linux/arch/i386/kernel/pci-i386.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/i386/kernel/pci-i386.c	Mon Mar 27 14:29:13 2000
@@ -228,7 +228,7 @@
 				if (!pr || request_resource(pr, r) < 0) {
 					printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
 					/* We'll assign a new address later */
-					r->start -= r->end;
+					r->end -= r->start;
 					r->start = 0;
 				}
 			}
@@ -317,6 +317,8 @@
 		if (r->flags & IORESOURCE_MEM)
 			cmd |= PCI_COMMAND_MEMORY;
 	}
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		cmd |= PCI_COMMAND_MEMORY;
 	if (cmd != old_cmd) {
 		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
--- v2.3.99-pre3/linux/arch/i386/kernel/pci-pc.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/i386/kernel/pci-pc.c	Mon Mar 27 10:33:03 2000
@@ -1188,7 +1188,7 @@
 		} else if (newirq) {
 			DBG(" -> [VIA] set to %02x\n", newirq);
 			x = (pirq & 1) ? ((x & 0x0f) | (newirq << 4)) : ((x & 0xf0) | newirq);
-			pci_write_config_byte(router, reg, y);
+			pci_write_config_byte(router, reg, x);
 			msg = "VIA-NEW";
 		} else DBG(" -> [VIA] sink\n");
 		break;
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.99-pre3/linux/arch/i386/kernel/setup.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/i386/kernel/setup.c	Sun Apr  9 08:12:56 2000
@@ -727,7 +727,7 @@
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (LOADER_TYPE && INITRD_START) {
-		if (INITRD_START + INITRD_SIZE < (max_low_pfn << PAGE_SHIFT)) {
+		if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
 			reserve_bootmem(INITRD_START, INITRD_SIZE);
 			initrd_start =
 				INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
@@ -863,7 +863,7 @@
 				rdmsr(0xC0000082, l, h);
 				if((l&0x0000FFFF)==0)
 				{		
-					l=(1<<0)|(mbytes/4);
+					l=(1<<0)|((mbytes/4)<<1);
 					save_flags(flags);
 					__cli();
 					__asm__ __volatile__ ("wbinvd": : :"memory");
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile
--- v2.3.99-pre3/linux/arch/i386/lib/Makefile	Fri Oct 22 13:21:45 1999
+++ linux/arch/i386/lib/Makefile	Thu Mar 30 16:56:04 2000
@@ -3,7 +3,7 @@
 #
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
 
 L_TARGET = lib.a
 L_OBJS  = checksum.o old-checksum.o delay.o \
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/math-emu/Makefile linux/arch/i386/math-emu/Makefile
--- v2.3.99-pre3/linux/arch/i386/math-emu/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/i386/math-emu/Makefile	Thu Mar 30 16:56:04 2000
@@ -10,7 +10,7 @@
 CFLAGS	:= $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) $(PARANOID) -c $<
+	$(CC) $(AFLAGS) $(PARANOID) -c $<
 
 # From 'C' language sources:
 C_OBJS =fpu_entry.o errors.o \
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/boot/Makefile linux/arch/ia64/boot/Makefile
--- v2.3.99-pre3/linux/arch/ia64/boot/Makefile	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/boot/Makefile	Thu Mar 30 16:56:04 2000
@@ -11,9 +11,9 @@
 LINKFLAGS = -static -T bootloader.lds
 
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
+	$(CPP) $(AFLAGS) -traditional -o $*.o $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
 
 OBJECTS	= bootloader.o
 TARGETS =
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/config.in linux/arch/ia64/config.in
--- v2.3.99-pre3/linux/arch/ia64/config.in	Mon Mar 27 08:08:21 2000
+++ linux/arch/ia64/config.in	Mon Mar 27 14:18:32 2000
@@ -4,6 +4,8 @@
 comment 'General setup'
 
 define_bool CONFIG_IA64 y
+define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS n
 
 choice 'IA-64 system type'					\
 	"Generic		CONFIG_IA64_GENERIC		\
@@ -50,7 +52,12 @@
 bool 'PCI support' CONFIG_PCI
 source drivers/pci/Config.in
 
-source drivers/pcmcia/Config.in
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+if [ "$CONFIG_HOTPLUG" = "y" ]; then
+   source drivers/pcmcia/Config.in
+else
+   define_bool CONFIG_PCMCIA n
+fi
 
 mainmenu_option next_comment
  comment 'Code maturity level options'
@@ -134,7 +141,6 @@
 endmenu
 
 source drivers/char/Config.in
-source drivers/usb/Config.in
 #source drivers/misc/Config.in
 
 source fs/Config.in
@@ -160,6 +166,8 @@
   source drivers/sound/Config.in
 fi
 endmenu
+
+source drivers/usb/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/defconfig linux/arch/ia64/defconfig
--- v2.3.99-pre3/linux/arch/ia64/defconfig	Mon Mar 27 08:08:21 2000
+++ linux/arch/ia64/defconfig	Mon Mar 27 09:38:47 2000
@@ -6,6 +6,8 @@
 # General setup
 #
 CONFIG_IA64=y
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
 # CONFIG_IA64_GENERIC is not set
 CONFIG_IA64_HP_SIM=y
 # CONFIG_IA64_SGI_SN1_SIM is not set
@@ -25,10 +27,7 @@
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI=y
 CONFIG_PCI_NAMES=y
-
-#
-# PCMCIA/CardBus support
-#
+# CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 
 #
@@ -119,6 +118,7 @@
 # CONFIG_BLK_DEV_AEC6210 is not set
 # CONFIG_AEC6210_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
 # CONFIG_AMD7409_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/dig/Makefile linux/arch/ia64/dig/Makefile
--- v2.3.99-pre3/linux/arch/ia64/dig/Makefile	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/dig/Makefile	Thu Mar 30 16:56:04 2000
@@ -6,9 +6,9 @@
 #
 
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+	$(CPP) $(AFLAGS) -o $*.s $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+	$(CC) $(AFLAGS) -c -o $*.o $<
 
 all: dig.a
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/ia32/Makefile linux/arch/ia64/ia32/Makefile
--- v2.3.99-pre3/linux/arch/ia64/ia32/Makefile	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/ia32/Makefile	Thu Mar 30 16:56:04 2000
@@ -3,9 +3,9 @@
 #
 
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+	$(CPP) $(AFLAGS) -o $*.s $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+	$(CC) $(AFLAGS) -c -o $*.o $<
 
 all: ia32.o
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c
--- v2.3.99-pre3/linux/arch/ia64/ia32/sys_ia32.c	Sat Feb 26 22:31:39 2000
+++ linux/arch/ia64/ia32/sys_ia32.c	Sun Apr  2 15:49:08 2000
@@ -2298,7 +2298,9 @@
 	return 0;
 }
 
-extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
+extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
+				unsigned long new_flags, void *data);
+extern long do_sys_mount(char * dev_name, char * dir_name, char * type,
 				unsigned long new_flags, void *data);
 
 #define SMBFS_NAME	"smbfs"
@@ -2328,7 +2330,6 @@
 				 (void *)AA(data));
 	} else {
 		unsigned long dev_page, dir_page, data_page;
-		mm_segment_t old_fs;
 
 		err = copy_mount_stuff_to_kernel((const void *)dev_name,
 						 &dev_page);
@@ -2348,13 +2349,9 @@
 			do_smb_super_data_conv((void *)data_page);
 		else
 			panic("The problem is here...");
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_mount((char *)dev_page, (char *)dir_page,
+		err = do_sys_mount((char *)dev_page, (char *)dir_page,
 				(char *)type_page, new_flags,
 				(void *)data_page);
-		set_fs(old_fs);
-
 		if(data_page)
 			free_page(data_page);
 	dir_out:
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/kdb/Makefile linux/arch/ia64/kdb/Makefile
--- v2.3.99-pre3/linux/arch/ia64/kdb/Makefile	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kdb/Makefile	Thu Mar 30 16:56:04 2000
@@ -13,7 +13,7 @@
 ALL_SUB_DIRS := $(SUB_DIRS)
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
 
 L_TARGET = kdb.a
 L_OBJS  = kdbsupport.o kdb_io.o kdb_bt.o kdb_traps.o
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile
--- v2.3.99-pre3/linux/arch/ia64/kernel/Makefile	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/Makefile	Thu Mar 30 16:56:04 2000
@@ -8,9 +8,9 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+	$(CPP) $(AFLAGS) -o $*.s $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+	$(CC) $(AFLAGS) -c -o $*.o $<
 
 all: kernel.o head.o init_task.o
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/lib/Makefile linux/arch/ia64/lib/Makefile
--- v2.3.99-pre3/linux/arch/ia64/lib/Makefile	Sun Feb 13 19:29:03 2000
+++ linux/arch/ia64/lib/Makefile	Thu Mar 30 16:56:04 2000
@@ -3,7 +3,7 @@
 #
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $@
+	$(CC) $(AFLAGS) -c $< -o $@
 
 OBJS  = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o		\
 	__moddi3.o __modsi3.o __umoddi3.o __umodsi3.o		\
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/sn/Makefile linux/arch/ia64/sn/Makefile
--- v2.3.99-pre3/linux/arch/ia64/sn/Makefile	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/sn/Makefile	Thu Mar 30 16:56:04 2000
@@ -10,9 +10,9 @@
 AFLAGS          :=      $(AFLAGS) -DCONFIG_SGI_SN1 -DSN1 -DSOFTSDV
 
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+	$(CPP) $(AFLAGS) -o $*.s $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+	$(CC) $(AFLAGS) -c -o $*.o $<
 
 all: sn.a
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ia64/sn/sn1/Makefile linux/arch/ia64/sn/sn1/Makefile
--- v2.3.99-pre3/linux/arch/ia64/sn/sn1/Makefile	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/sn/sn1/Makefile	Thu Mar 30 16:56:04 2000
@@ -10,9 +10,9 @@
 AFLAGS          :=      $(AFLAGS) -DCONFIG_SGI_SN1 -DSN1 -DSOFTSDV
 
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+	$(CPP) $(AFLAGS) -o $*.s $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+	$(CC) $(AFLAGS) -c -o $*.o $<
 
 all: sn1.a
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.3.99-pre3/linux/arch/m68k/config.in	Mon Mar 27 08:08:22 2000
+++ linux/arch/m68k/config.in	Mon Apr 10 22:58:59 2000
@@ -16,16 +16,15 @@
 comment 'Platform dependent setup'
 
 define_bool CONFIG_ISA n
+define_bool CONFIG_PCMCIA n
+
 bool 'Amiga support' CONFIG_AMIGA
 bool 'Atari support' CONFIG_ATARI
-if [ "$CONFIG_ATARI" = "y" ]; then
-   bool '  Hades support' CONFIG_HADES
-   if [ "$CONFIG_HADES" = "y" ]; then
-      define_bool CONFIG_PCI y
-   fi  
-fi
-if [ "$CONFIG_HADES" != "y" ]; then
-  define_bool CONFIG_PCI n
+dep_bool '  Hades support' CONFIG_HADES $CONFIG_ATARI
+if [ "$CONFIG_HADES" = "y" ]; then
+   define_bool CONFIG_PCI y
+else
+   define_bool CONFIG_PCI n
 fi  
 bool 'Macintosh support' CONFIG_MAC
 if [ "$CONFIG_MAC" = "y" ]; then
@@ -421,19 +420,21 @@
 if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
    tristate 'HP DCA serial support' CONFIG_HPDCA
 fi
-if [ "$CONFIG_SUN3X" = "y" ]; then
-   bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS
-   if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
-      bool '  Sun keyboard support' CONFIG_SUN_KEYBOARD
-      bool '  Sun mouse support' CONFIG_SUN_MOUSE
-      if [ "$CONFIG_SUN_MOUSE" != "n" ]; then
-         define_bool CONFIG_BUSMOUSE y
-    fi
-    define_bool CONFIG_SBUS y
-    define_bool CONFIG_SBUSCHAR y
-    define_bool CONFIG_SUN_SERIAL y
-  fi  
+
+dep_bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS $CONFIG_SUN3X
+dep_bool '  Sun keyboard support' CONFIG_SUN_KEYBOARD $CONFIG_SUN3X_ZS
+dep_bool '  Sun mouse support' CONFIG_SUN_MOUSE $CONFIG_SUN3X_ZS
+if [ "$CONFIG_SUN_MOUSE" = "y" ]; then
+   define_bool CONFIG_BUSMOUSE y
+fi
+if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
+   define_bool CONFIG_SBUS y
+   define_bool CONFIG_SBUSCHAR y
+   define_bool CONFIG_SUN_SERIAL y
+else
+   define_bool CONFIG_SBUS n
 fi
+
 if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
      "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" -o \
      "$CONFIG_SUN3X" = "y" ]; then
@@ -483,7 +484,7 @@
 
 tristate 'Sound support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
-   dep_tristate '  Amiga or Atari DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND
+   source drivers/sound/dmasound/Config.in
 fi
 endmenu
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/m68k/defconfig linux/arch/m68k/defconfig
--- v2.3.99-pre3/linux/arch/m68k/defconfig	Mon Mar 27 08:08:22 2000
+++ linux/arch/m68k/defconfig	Mon Mar 27 09:38:47 2000
@@ -12,8 +12,10 @@
 # Platform dependent setup
 #
 # CONFIG_ISA is not set
+# CONFIG_PCMCIA is not set
 CONFIG_AMIGA=y
 # CONFIG_ATARI is not set
+# CONFIG_HADES is not set
 # CONFIG_PCI is not set
 # CONFIG_MAC is not set
 # CONFIG_APOLLO is not set
@@ -195,6 +197,10 @@
 # CONFIG_GVPIOEXT_LP is not set
 # CONFIG_GVPIOEXT_PLIP is not set
 # CONFIG_MULTIFACE_III_TTY is not set
+# CONFIG_SUN3X_ZS is not set
+# CONFIG_SUN_KEYBOARD is not set
+# CONFIG_SUN_MOUSE is not set
+# CONFIG_SBUS is not set
 # CONFIG_SERIAL_CONSOLE is not set
 # CONFIG_USERIAL is not set
 # CONFIG_WATCHDOG is not set
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/m68k/fpsp040/Makefile linux/arch/m68k/fpsp040/Makefile
--- v2.3.99-pre3/linux/arch/m68k/fpsp040/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/m68k/fpsp040/Makefile	Thu Mar 30 16:56:04 2000
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
 
 OS_TARGET := fpsp.o
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/m68k/ifpsp060/Makefile linux/arch/m68k/ifpsp060/Makefile
--- v2.3.99-pre3/linux/arch/m68k/ifpsp060/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/m68k/ifpsp060/Makefile	Thu Mar 30 16:56:04 2000
@@ -5,7 +5,7 @@
 # for more details.
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
 
 OS_TARGET := ifpsp.o
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile
--- v2.3.99-pre3/linux/arch/m68k/kernel/Makefile	Sun Feb 13 19:29:03 2000
+++ linux/arch/m68k/kernel/Makefile	Thu Mar 30 16:56:04 2000
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
 
 ifndef CONFIG_SUN3
 all: head.o kernel.o
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/m68k/lib/Makefile linux/arch/m68k/lib/Makefile
--- v2.3.99-pre3/linux/arch/m68k/lib/Makefile	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/lib/Makefile	Thu Mar 30 16:56:04 2000
@@ -3,7 +3,7 @@
 #
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $@
+	$(CC) $(AFLAGS) -traditional -c $< -o $@
 
 L_TARGET = lib.a
 L_OBJS  = ashrdi3.o lshrdi3.o checksum.o memcpy.o memcmp.o memset.o semaphore.o
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/m68k/math-emu/Makefile linux/arch/m68k/math-emu/Makefile
--- v2.3.99-pre3/linux/arch/m68k/math-emu/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/m68k/math-emu/Makefile	Thu Mar 30 16:56:04 2000
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.o:
-	$(CC) $(EXTRA_CFLAGS) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+	$(CC) $(EXTRA_CFLAGS) $(AFLAGS) -traditional -c $< -o $*.o
 
 #EXTRA_CFLAGS=-DFPU_EMU_DEBUG
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/m68k/sun3/Makefile linux/arch/m68k/sun3/Makefile
--- v2.3.99-pre3/linux/arch/m68k/sun3/Makefile	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/sun3/Makefile	Thu Mar 30 16:56:04 2000
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -Wa,-m68020 -c $< -o $*.o
+	$(CC) $(AFLAGS) -traditional -Wa,-m68020 -c $< -o $*.o
 
 O_TARGET := sun3.o 
 O_OBJS   := config.o idprom.o mmu_emu.o sun3ints.o leds.o dvma.o sbus.o intersil.o
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.3.99-pre3/linux/arch/mips/config.in	Mon Mar 27 08:08:22 2000
+++ linux/arch/mips/config.in	Mon Mar 27 14:18:32 2000
@@ -29,6 +29,8 @@
 unset CONFIG_MIPS_JAZZ
 unset CONFIG_VIDEO_G364
 
+define_bool CONFIG_SBUS n
+
 if [ "$CONFIG_ALGOR_P4032" = "y" -o "$CONFIG_SNI_RM200_PCI" = "y" -o \
      "$CONFIG_DDB5074" = "y" ]; then
    define_bool CONFIG_PCI y
@@ -127,7 +129,13 @@
 bool 'Networking support' CONFIG_NET
 
 source drivers/pci/Config.in
-source drivers/pcmcia/Config.in
+
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+if [ "$CONFIG_HOTPLUG" = "y" ]; then
+   source drivers/pcmcia/Config.in
+else
+   define_bool CONFIG_PCMCIA n
+fi
 
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
@@ -252,8 +260,11 @@
 fi
 
 if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
-   source drivers/net/hamradio/Config.in
+   mainmenu_option next_comment
+   # comment 'AX.25 network device drivers'
 
+   source drivers/net/hamradio/Config.in
+   endmenu
 
    mainmenu_option next_comment
    comment 'ISDN subsystem'
@@ -307,7 +318,6 @@
    endmenu
 fi
 
-source drivers/usb/Config.in
 
 #source drivers/misc/Config.in
 
@@ -347,6 +357,8 @@
 if [ "$CONFIG_SGI_IP22" = "y" ]; then
    source drivers/sgi/Config.in
 fi
+
+source drivers/usb/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/mips/defconfig linux/arch/mips/defconfig
--- v2.3.99-pre3/linux/arch/mips/defconfig	Mon Mar 27 08:08:22 2000
+++ linux/arch/mips/defconfig	Mon Mar 27 09:38:47 2000
@@ -19,6 +19,7 @@
 # CONFIG_OLIVETTI_M700 is not set
 CONFIG_SGI_IP22=y
 # CONFIG_SNI_RM200_PCI is not set
+# CONFIG_SBUS is not set
 # CONFIG_PCI is not set
 # CONFIG_ISA is not set
 
@@ -49,10 +50,7 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 CONFIG_NET=y
-
-#
-# PCMCIA/CardBus support
-#
+# CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.3.99-pre3/linux/arch/mips/kernel/sysirix.c	Fri Mar 10 16:40:40 2000
+++ linux/arch/mips/kernel/sysirix.c	Sun Apr  2 15:49:08 2000
@@ -696,7 +696,7 @@
 	return -EINTR;
 }
 
-extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
+extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
 				unsigned long new_flags, void * data);
 
 /* XXX need more than this... */
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/mips64/config.in linux/arch/mips64/config.in
--- v2.3.99-pre3/linux/arch/mips64/config.in	Mon Mar 27 08:08:22 2000
+++ linux/arch/mips64/config.in	Mon Mar 27 14:18:32 2000
@@ -19,11 +19,10 @@
    bool '  Discontiguous Memory Support' CONFIG_DISCONTIGMEM
    #bool '  IP27 XXL' CONFIG_SGI_SN0_XXL
 fi
-endmenu
-
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    bool 'Symmetric Multi-Processing support' CONFIG_SMP
 fi
+endmenu
 
 #
 # Select some configuration options automatically based on user selections
@@ -37,6 +36,7 @@
 unset CONFIG_BINFMT_ELF32
 
 define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS n
 
 if [ "$CONFIG_SGI_IP22" = "y" ]; then
    define_bool CONFIG_BOOT_ELF32 y
@@ -78,7 +78,14 @@
 bool 'Networking support' CONFIG_NET
 
 source drivers/pci/Config.in
-source drivers/pcmcia/Config.in
+
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
+if [ "$CONFIG_HOTPLUG" = "y" ] ; then
+   source drivers/pcmcia/Config.in
+else
+   define_bool CONFIG_PCMCIA n
+fi
 
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
@@ -191,7 +198,6 @@
 
 source drivers/char/Config.in
 
-source drivers/usb/Config.in
 
 #source drivers/misc/Config.in
 
@@ -225,6 +231,8 @@
 if [ "$CONFIG_SGI_IP22" = "y" ]; then
    source drivers/sgi/Config.in
 fi
+
+source drivers/usb/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/mips64/defconfig linux/arch/mips64/defconfig
--- v2.3.99-pre3/linux/arch/mips64/defconfig	Mon Mar 27 08:08:22 2000
+++ linux/arch/mips64/defconfig	Mon Mar 27 09:38:47 2000
@@ -15,6 +15,7 @@
 # CONFIG_SGI_SN0_N_MODE is not set
 # CONFIG_DISCONTIGMEM is not set
 # CONFIG_ISA is not set
+# CONFIG_SBUS is not set
 CONFIG_BOOT_ELF64=y
 CONFIG_ARC64=y
 CONFIG_COHERENT_IO=y
@@ -38,10 +39,7 @@
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_NET=y
 CONFIG_PCI_NAMES=y
-
-#
-# PCMCIA/CardBus support
-#
+# CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/mips64/sgi-ip27/ip27-memory.c linux/arch/mips64/sgi-ip27/ip27-memory.c
--- v2.3.99-pre3/linux/arch/mips64/sgi-ip27/ip27-memory.c	Sat Feb 26 22:31:41 2000
+++ linux/arch/mips64/sgi-ip27/ip27-memory.c	Mon Mar 27 10:24:56 2000
@@ -284,7 +284,7 @@
 		PLAT_NODE_DATA(node)->physstart = (start_pfn << PAGE_SHIFT);
 		PLAT_NODE_DATA(node)->size = (zones_size[ZONE_DMA] << PAGE_SHIFT);
 		free_area_init_node(node, NODE_DATA(node), zones_size, 
-						start_pfn << PAGE_SHIFT);
+						start_pfn << PAGE_SHIFT, 0);
 		PLAT_NODE_DATA(node)->start_mapnr = 
 					(NODE_DATA(node)->node_mem_map - mem_map);
 		if ((PLAT_NODE_DATA(node)->start_mapnr + 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c
--- v2.3.99-pre3/linux/arch/ppc/8xx_io/enet.c	Thu Nov 18 20:25:37 1999
+++ linux/arch/ppc/8xx_io/enet.c	Mon Mar 27 22:30:29 2000
@@ -63,13 +63,13 @@
  * Like the LANCE driver:
  * The driver runs as two independent, single-threaded flows of control.  One
  * is the send-packet routine, which enforces single-threaded use by the
- * dev->tbusy flag.  The other thread is the interrupt handler, which is single
- * threaded by the hardware and other software.
+ * cep->tx_busy flag.  The other thread is the interrupt handler, which is
+ * single threaded by the hardware and other software.
  *
- * The send packet thread has partial control over the Tx ring and 'dev->tbusy'
- * flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
- * queue slot is empty, it clears the tbusy flag when finished otherwise it sets
- * the 'lp->tx_full' flag.
+ * The send packet thread has partial control over the Tx ring and the
+ * 'cep->tx_busy' flag.  It sets the tx_busy flag whenever it's queuing a Tx
+ * packet. If the next queue slot is empty, it clears the tx_busy flag when
+ * finished otherwise it sets the 'lp->tx_full' flag.
  *
  * The MBX has a control register external to the MPC8xx that has some
  * control of the Ethernet interface.  Control Register 1 has the
@@ -149,8 +149,10 @@
 	cbd_t	*dirty_tx;	/* The ring entries to be free()ed. */
 	scc_t	*sccp;
 	struct	net_device_stats stats;
-	char	tx_full;
+	uint	tx_full;
+	uint	tx_busy;
 	unsigned long lock;
+	int	interrupt;
 };
 
 static int cpm_enet_open(struct net_device *dev);
@@ -190,10 +192,7 @@
 	 * a simple way to do that.
 	 */
 
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-
+	netif_start_queue(dev);
 	return 0;					/* Always succeed */
 }
 
@@ -205,7 +204,7 @@
 	unsigned long flags;
 
 	/* Transmitter timeout, serious problems. */
-	if (dev->tbusy) {
+	if (cep->tx_busy) {
 		int tickssofar = jiffies - dev->trans_start;
 		if (tickssofar < 200)
 			return 1;
@@ -233,22 +232,23 @@
 		}
 #endif
 
-		dev->tbusy=0;
+		cep->tx_busy=0;
 		dev->trans_start = jiffies;
 
 		return 0;
 	}
 
 	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+	 * done with atomic_swap(1, cep->tx_busy), but set_bit() works as well.
+	 */
+	if (test_and_set_bit(0, (void*)&cep->tx_busy) != 0) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
 
 	if (test_and_set_bit(0, (void*)&cep->lock) != 0) {
 		printk("%s: tx queue lock!.\n", dev->name);
-		/* don't clear dev->tbusy flag. */
+		/* don't clear cep->tx_busy flag. */
 		return 1;
 	}
 
@@ -258,7 +258,7 @@
 #ifndef final_version
 	if (bdp->cbd_sc & BD_ENET_TX_READY) {
 		/* Ooops.  All transmit buffers are full.  Bail out.
-		 * This should not happen, since dev->tbusy should be set.
+		 * This should not happen, since cep->tx_busy should be set.
 		 */
 		printk("%s: tx queue full!.\n", dev->name);
 		cep->lock = 0;
@@ -314,7 +314,7 @@
 	if (bdp->cbd_sc & BD_ENET_TX_READY)
 		cep->tx_full = 1;
 	else
-		dev->tbusy=0;
+		cep->tx_busy=0;
 	restore_flags(flags);
 
 	cep->cur_tx = (cbd_t *)bdp;
@@ -335,10 +335,10 @@
 	int	must_restart;
 
 	cep = (struct cpm_enet_private *)dev->priv;
-	if (dev->interrupt)
+	if (cep->interrupt)
 		printk("%s: Re-entering the interrupt handler.\n", dev->name);
 
-	dev->interrupt = 1;
+	cep->interrupt = 1;
 
 	/* Get the interrupt events that caused us to be here.
 	*/
@@ -399,7 +399,7 @@
 
 		/* Free the sk buffer associated with this last transmit.
 		*/
-		dev_kfree_skb(cep->tx_skbuff[cep->skb_dirty]/*, FREE_WRITE*/);
+		dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]);
 		cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;
 
 		/* Update pointer to next buffer descriptor to be transmitted.
@@ -421,10 +421,10 @@
 		/* Since we have freed up a buffer, the ring is no longer
 		 * full.
 		 */
-		if (cep->tx_full && dev->tbusy) {
+		if (cep->tx_full && cep->tx_busy) {
 			cep->tx_full = 0;
-			dev->tbusy = 0;
-			mark_bh(NET_BH);
+			cep->tx_busy = 0;
+			netif_wake_queue(dev);
 		}
 
 		cep->dirty_tx = (cbd_t *)bdp;
@@ -455,7 +455,7 @@
 		printk("CPM ENET: BSY can't happen.\n");
 	}
 
-	dev->interrupt = 0;
+	cep->interrupt = 0;
 
 	return;
 }
@@ -564,6 +564,7 @@
 {
 	/* Don't know what to do yet.
 	*/
+	netif_stop_queue(dev);
 
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c
--- v2.3.99-pre3/linux/arch/ppc/8xx_io/uart.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/8xx_io/uart.c	Sun Apr  2 15:38:53 2000
@@ -28,6 +28,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/serialP.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
@@ -1937,6 +1938,7 @@
 		printk("rs_open returning after block_til_ready with %d\n",
 		       retval);
 #endif
+		MOD_DEC_USE_COUNT;
 		return retval;
 	}
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.3.99-pre3/linux/arch/ppc/Makefile	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/Makefile	Mon Mar 27 22:30:29 2000
@@ -72,7 +72,7 @@
 
 ifdef CONFIG_8xx
 SUBDIRS += arch/ppc/8xx_io
-DRIVERS += arch/ppc/8xx_io/8xx_io.a drivers/net/net.a
+DRIVERS += arch/ppc/8xx_io/8xx_io.a
 endif
 
 ifdef CONFIG_APUS
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.3.99-pre3/linux/arch/ppc/boot/Makefile	Fri Mar 10 16:40:40 2000
+++ linux/arch/ppc/boot/Makefile	Thu Mar 30 16:56:04 2000
@@ -16,9 +16,9 @@
 .c.o:
 	$(CC) $(CFLAGS)  -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -D__BOOTER__ -c -o $*.o $<
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
+	$(CPP) $(AFLAGS) -traditional -o $*.o $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
 
 ZOFF = 0
 ZSZ = 0
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile
--- v2.3.99-pre3/linux/arch/ppc/chrpboot/Makefile	Fri Mar 10 16:40:40 2000
+++ linux/arch/ppc/chrpboot/Makefile	Thu Mar 30 16:56:04 2000
@@ -12,9 +12,9 @@
 .c.o:
 	$(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $<
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
+	$(CPP) $(AFLAGS) -traditional -o $*.o $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
 
 CFLAGS	= $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS
 LD_ARGS = -Ttext 0x00400000
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.3.99-pre3/linux/arch/ppc/config.in	Mon Mar 27 08:08:22 2000
+++ linux/arch/ppc/config.in	Mon Apr 10 22:58:59 2000
@@ -83,12 +83,13 @@
 comment 'General setup'
 
 define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS n
 
 if [ "$CONFIG_APUS" = "y" -o "$CONFIG_4xx" = "y" -o \
      "$CONFIG_82xx" = "y" ]; then
    define_bool CONFIG_PCI n
 else
-   if [ "$CONFIG_6xx" = "y" -o CONFIG_PPC64 ]; then
+   if [ "$CONFIG_6xx" = "y" -o "$CONFIG_PPC64" = "y" ]; then
       define_bool CONFIG_PCI y
    else
    # CONFIG_8xx
@@ -115,6 +116,8 @@
 
 if [ "$CONFIG_HOTPLUG" = "y" ]; then
    source drivers/pcmcia/Config.in
+else
+   define_bool CONFIG_PCMCIA n
 fi
 
 source drivers/parport/Config.in
@@ -247,14 +250,13 @@
 endmenu
 
 source drivers/char/Config.in
-source drivers/usb/Config.in
 source fs/Config.in
 
 mainmenu_option next_comment
 comment 'Sound'
 tristate 'Sound card support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
-  dep_tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND
+  source drivers/sound/dmasound/Config.in
   source drivers/sound/Config.in
 fi
 
@@ -263,6 +265,8 @@
 if [ "$CONFIG_8xx" = "y" ]; then
 source arch/ppc/8xx_io/Config.in
 fi
+
+source drivers/usb/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.3.99-pre3/linux/arch/ppc/defconfig	Mon Mar 27 08:08:22 2000
+++ linux/arch/ppc/defconfig	Mon Mar 27 09:38:47 2000
@@ -34,6 +34,7 @@
 # General setup
 #
 # CONFIG_ISA is not set
+# CONFIG_SBUS is not set
 CONFIG_PCI=y
 CONFIG_NET=y
 CONFIG_SYSCTL=y
@@ -45,6 +46,7 @@
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PCI_NAMES is not set
 # CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
 
 #
 # Parallel port support
@@ -185,6 +187,7 @@
 # CONFIG_BLK_DEV_AEC6210 is not set
 # CONFIG_AEC6210_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
 # CONFIG_AMD7409_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c
--- v2.3.99-pre3/linux/arch/ppc/kernel/feature.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/ppc/kernel/feature.c	Mon Apr 10 22:58:59 2000
@@ -184,14 +184,14 @@
 	if (controller_count)
 		printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
 
-#ifdef CONFIG_PMAC_PBOOK
-#ifdef CONFIG_DMASOUND_MODULE
-	/* On PowerBooks, we disable the sound chip when dmasound is a module */
+#if defined(CONFIG_PMAC_PBOOK) && !defined(CONFIG_DMASOUND_AWACS)
+	/* On PowerBooks, we disable the sound chip when dmasound is a module
+	 * or not used at all
+	 */
 	if (controller_count && find_devices("via-pmu") != NULL) {
 		feature_clear(controllers[0].device, FEATURE_Sound_power);
 		feature_clear(controllers[0].device, FEATURE_Sound_CLK_enable);
 	}
-#endif	
 #endif
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c
--- v2.3.99-pre3/linux/arch/ppc/kernel/m8xx_setup.c	Wed Dec 29 13:13:12 1999
+++ linux/arch/ppc/kernel/m8xx_setup.c	Mon Mar 27 22:30:25 2000
@@ -276,7 +276,6 @@
 	int i;
 	void cpm_interrupt_init(void);
 
-        ppc8xx_pic.irq_offset = 0;
         for ( i = 0 ; i < NR_SIU_INTS ; i++ )
                 irq_desc[i].handler = &ppc8xx_pic;
 	
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/lib/Makefile linux/arch/ppc/lib/Makefile
--- v2.3.99-pre3/linux/arch/ppc/lib/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/ppc/lib/Makefile	Thu Mar 30 16:56:04 2000
@@ -3,7 +3,7 @@
 #
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $*.o
+	$(CC) $(AFLAGS) -c $< -o $*.o
 
 O_TARGET = lib.o
 O_OBJS  = checksum.o string.o strcase.o
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/math-emu/math.c linux/arch/ppc/math-emu/math.c
--- v2.3.99-pre3/linux/arch/ppc/math-emu/math.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/math-emu/math.c	Mon Mar 27 22:30:30 2000
@@ -233,14 +233,14 @@
 	case LFD:
 		idx = (insn >> 16) & 0x1f;
 		sdisp = (insn & 0xffff);
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
 		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
 		lfd(op0, op1, op2, op3);
 		break;
 	case LFDU:
 		idx = (insn >> 16) & 0x1f;
 		sdisp = (insn & 0xffff);
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
 		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
 		lfd(op0, op1, op2, op3);
 		regs->gpr[idx] = (unsigned long)op1;
@@ -248,21 +248,21 @@
 	case STFD:
 		idx = (insn >> 16) & 0x1f;
 		sdisp = (insn & 0xffff);
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
 		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
 		stfd(op0, op1, op2, op3);
 		break;
 	case STFDU:
 		idx = (insn >> 16) & 0x1f;
 		sdisp = (insn & 0xffff);
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
 		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
 		stfd(op0, op1, op2, op3);
 		regs->gpr[idx] = (unsigned long)op1;
 		break;
 	case OP63:
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
-		op1 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+		op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
 		fmr(op0, op1, op2, op3);
 		break;
 	default:
@@ -359,28 +359,28 @@
 
 	switch (type) {
 	case AB:
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
-		op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
-		op2 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+		op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
+		op2 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
 		break;
 
 	case AC:
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
-		op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
-		op2 = (void *)&current->tss.fpr[(insn >>  6) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+		op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
+		op2 = (void *)&current->thread.fpr[(insn >>  6) & 0x1f];
 		break;
 
 	case ABC:
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
-		op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
-		op2 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
-		op3 = (void *)&current->tss.fpr[(insn >>  6) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+		op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
+		op2 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
+		op3 = (void *)&current->thread.fpr[(insn >>  6) & 0x1f];
 		break;
 
 	case D:
 		idx = (insn >> 16) & 0x1f;
 		sdisp = (insn & 0xffff);
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
 		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
 		break;
 
@@ -390,22 +390,22 @@
 			goto illegal;
 
 		sdisp = (insn & 0xffff);
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
 		op1 = (void *)(regs->gpr[idx] + sdisp);
 		break;
 
 	case X:
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
 		break;
 
 	case XA:
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
-		op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+		op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
 		break;
 
 	case XB:
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
-		op1 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+		op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
 		break;
 
 	case XE:
@@ -413,13 +413,13 @@
 		if (!idx)
 			goto illegal;
 
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
 		op1 = (void *)(regs->gpr[idx] + regs->gpr[(insn >> 11) & 0x1f]);
 		break;
 
 	case XEU:
 		idx = (insn >> 16) & 0x1f;
-		op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
 		op1 = (void *)((idx ? regs->gpr[idx] : 0)
 				+ regs->gpr[(insn >> 11) & 0x1f]);
 		break;
@@ -427,8 +427,8 @@
 	case XCR:
 		op0 = (void *)&regs->ccr;
 		op1 = (void *)((insn >> 23) & 0x7);
-		op2 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
-		op3 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+		op2 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
+		op3 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
 		break;
 
 	case XCRL:
@@ -448,7 +448,7 @@
 
 	case XFLB:
 		op0 = (void *)((insn >> 17) & 0xff);
-		op1 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+		op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
 		break;
 
 	default:
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/math-emu/sfp-machine.h linux/arch/ppc/math-emu/sfp-machine.h
--- v2.3.99-pre3/linux/arch/ppc/math-emu/sfp-machine.h	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/math-emu/sfp-machine.h	Mon Mar 27 22:30:29 2000
@@ -166,7 +166,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
-#define __FPU_FPSCR	(current->tss.fpscr)
+#define __FPU_FPSCR	(current->thread.fpscr)
 
 /* We only actually write to the destination register
  * if exceptions signalled (if any) will not trap.
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/mbxboot/Makefile linux/arch/ppc/mbxboot/Makefile
--- v2.3.99-pre3/linux/arch/ppc/mbxboot/Makefile	Fri Mar 10 16:40:40 2000
+++ linux/arch/ppc/mbxboot/Makefile	Thu Mar 30 16:56:04 2000
@@ -16,9 +16,9 @@
 .c.o:
 	$(CC) $(CFLAGS)  -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $<
 .S.s:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
+	$(CPP) $(AFLAGS) -traditional -o $*.o $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
 
 ZOFF = 0
 ZSZ = 0
@@ -26,7 +26,7 @@
 ISZ = 0
 
 TFTPIMAGE=/tftpboot/zImage.mbx
-ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00180000
 
 OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o
 CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.3.99-pre3/linux/arch/ppc/mm/fault.c	Tue Dec  7 09:32:42 1999
+++ linux/arch/ppc/mm/fault.c	Mon Mar 27 22:30:30 2000
@@ -182,34 +182,44 @@
 
 #ifdef CONFIG_8xx
 
-unsigned long va_to_phys(unsigned long address)
+/* The pgtable.h claims some functions generically exist, but I
+ * can't find them......
+ */
+pte_t *find_pte(struct mm_struct *mm, unsigned long address)
 {
 	pgd_t *dir;
 	pmd_t *pmd;
 	pte_t *pte;
-	
-	dir = pgd_offset(current->mm, address & PAGE_MASK);
-	if (dir)
-	{
+
+	dir = pgd_offset(mm, address & PAGE_MASK);
+	if (dir) {
 		pmd = pmd_offset(dir, address & PAGE_MASK);
-		if (pmd && pmd_present(*pmd))
-		{
+		if (pmd && pmd_present(*pmd)) {
 			pte = pte_offset(pmd, address & PAGE_MASK);
-			if (pte && pte_present(*pte))
-			{
-				return(pte_page(*pte) | (address & ~(PAGE_MASK-1)));
+			if (pte && pte_present(*pte)) {
+				return(pte);
 			}
-		} else
-		{
+		}
+		else {
 			return (0);
 		}
-	} else
-	{
+	}
+	else {
 		return (0);
 	}
 	return (0);
 }
 
+unsigned long va_to_phys(unsigned long address)
+{
+	pte_t *pte;
+	
+	pte = find_pte(current->mm, address);
+	if (pte)
+		return((unsigned long)(pte_page(*pte)) | (address & ~(PAGE_MASK-1)));
+	return (0);
+}
+
 void
 print_8xx_pte(struct mm_struct *mm, unsigned long addr)
 {
@@ -227,8 +237,8 @@
                                 printk(" (0x%08lx)->(0x%08lx)->0x%08lx\n",
                                         (long)pgd, (long)pte, (long)pte_val(*pte));
 #define pp ((long)pte_val(*pte))				
-				printk(" RPN: %05x PP: %x SPS: %x SH: %x "
-				       "CI: %x v: %x\n",
+				printk(" RPN: %05x PP: %x SPS: %x SH: %lx "
+				       "CI: %lx v: %lx\n",
 				       pp>>12,    /* rpn */
 				       (pp>>10)&3, /* pp */
 				       (pp>>3)&1, /* small */
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/Makefile linux/arch/sh/Makefile
--- v2.3.99-pre3/linux/arch/sh/Makefile	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/Makefile	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.2 1999/12/23 12:13:53 gniibe Exp gniibe $
+# $Id: Makefile,v 1.4 2000/03/08 15:14:14 gniibe Exp $
 #
 # This file is subject to the terms and conditions of the GNU General Public
 # License.  See the file "COPYING" in the main directory of this archive
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/config.in linux/arch/sh/config.in
--- v2.3.99-pre3/linux/arch/sh/config.in	Mon Mar 27 08:08:22 2000
+++ linux/arch/sh/config.in	Mon Mar 27 10:26:15 2000
@@ -48,6 +48,7 @@
 comment 'General setup'
 
 define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS n
 
 bool 'Networking support' CONFIG_NET
 
@@ -73,6 +74,8 @@
 
 if [ "$CONFIG_HOTPLUG" = "y" ] ; then
    source drivers/pcmcia/Config.in
+else
+   define_bool CONFIG_PCMCIA n
 fi
 
 bool 'System V IPC' CONFIG_SYSVIPC
@@ -169,8 +172,6 @@
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/char/pcmcia/Config.in
 fi
-
-#source drivers/misc/Config.in
 
 source fs/Config.in
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/defconfig linux/arch/sh/defconfig
--- v2.3.99-pre3/linux/arch/sh/defconfig	Mon Mar 27 08:08:22 2000
+++ linux/arch/sh/defconfig	Mon Mar 27 09:38:47 2000
@@ -29,10 +29,12 @@
 # General setup
 #
 # CONFIG_ISA is not set
+# CONFIG_SBUS is not set
 # CONFIG_NET is not set
 CONFIG_CF_ENABLER=y
 # CONFIG_PCI is not set
 # CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
 # CONFIG_SYSVIPC is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile
--- v2.3.99-pre3/linux/arch/sh/kernel/Makefile	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/Makefile	Thu Mar 30 16:56:04 2000
@@ -7,7 +7,7 @@
 #
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
 
 O_TARGET := kernel.o
 O_OBJS   := process.o signal.o entry.o traps.o irq.o irq_onchip.o \
@@ -29,7 +29,7 @@
 entry.o: entry.S
 
 head.o: head.S
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
+	$(CC) $(AFLAGS) -traditional -c $*.S -o $*.o
 
 clean:
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S
--- v2.3.99-pre3/linux/arch/sh/kernel/entry.S	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/entry.S	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.55 2000/03/05 01:48:58 gniibe Exp $
+/* $Id: entry.S,v 1.71 2000/03/22 13:29:33 gniibe Exp $
  *
  *  linux/arch/sh/entry.S
  *
@@ -33,10 +33,9 @@
  *
  *	syscall #
  *	ssr
- *	r15 = stack pointer
  *	r0
  *      ...
- *	r14
+ *	r15 = stack pointer
  *	gbr
  *	mach
  *	macl
@@ -46,7 +45,7 @@
  */
 
 /*
- * these are offsets into the task-struct.
+ * These are offsets into the task-struct.
  */
 state		=  0
 flags		=  4
@@ -78,8 +77,8 @@
 /* Offsets to the stack */
 SYSCALL_NR =  0
 SR	   =  4
-SP	   =  8
-R0         =  12
+R0         =  8
+SP	   =  (8+15*4)
 
 #define k0	r0
 #define k1	r1
@@ -96,7 +95,7 @@
 	k2	scratch (Exception code)
 	k3	scratch (Return address)
 	k4	Stack base = current+8192
-	k5	reserved
+	k5	Global Interrupt Mask (0--15)
 	k6	reserved
 	k7	reserved
 */
@@ -115,109 +114,113 @@
 ! this first version depends *much* on C implementation.
 !
 
-#define DO_FAULT(write)			\
-	mov.l	4f,r0;			\
-	mov.l	@r0,r6; 		\
-	/* STI */ 			\
-	mov.l	3f,r1; 			\
-	stc	sr,r0; 			\
-	and	r1,r0; 			\
-	ldc	r0,sr; 			\
-	/*    */ 			\
-	mov	r15,r4; 		\
-	mov.l	2f,r0; 			\
-	jmp	@r0; 			\
-	 mov	#write,r5;
+#define RESTORE_FLAGS()			\
+	mov.l	@(SR,$r15), $r0;	\
+	and	#0xf0, $r0;		\
+	shlr8	$r0;			\
+	cmp/eq	#0x0f, $r0;		\
+	bt	9f;			\
+	mov.l	__INV_IMASK, $r1;	\
+	stc	$sr, $r0;		\
+	and	$r1, $r0;		\
+	stc	$r5_bank, $r1;		\
+	or	$r1, $r0;		\
+	ldc	$r0, $sr
 
 	.balign	4
 tlb_protection_violation_load:
 tlb_miss_load:
-	mov	#-1,r0
-	mov.l	r0,@r15		! syscall nr = -1
-	DO_FAULT(0)
+	mov	#-1, $r0
+	mov.l	$r0, @$r15	! syscall nr = -1
+	mov.l	2f, $r0
+	mov.l	@$r0, $r6
+	RESTORE_FLAGS()
+9:	mov	$r15, $r4
+	mov.l	1f, $r0
+	jmp	@$r0
+	 mov	#0, $r5
 
 	.balign	4
 tlb_protection_violation_store:
 tlb_miss_store:
 initial_page_write:
-	mov	#-1,r0
-	mov.l	r0,@r15		! syscall nr = -1
-	DO_FAULT(1)
+	mov	#-1, $r0
+	mov.l	$r0, @$r15	! syscall nr = -1
+	mov.l	2f, $r0
+	mov.l	@$r0, $r6
+	RESTORE_FLAGS()
+9:	mov	$r15, $r4
+	mov.l	1f, $r0
+	jmp	@$r0
+	 mov	#1, $r5
 
 	.balign 4
-2:	.long	SYMBOL_NAME(do_page_fault)
-3:	.long	0xefffffff	! BL=0
-4:	.long	MMU_TEA
+1:	.long	SYMBOL_NAME(do_page_fault)
+2:	.long	MMU_TEA
 
 #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
 	.balign	4
 	/* Unwind the stack and jmp to the debug entry */
 debug:
-	add	#4,r15		! skip syscall number
-	mov.l	@r15+,r11	! SSR
-	mov.l	@r15+,r10	! original stack
-	mov.l	@r15+,r0
-	mov.l	@r15+,r1
-	mov.l	@r15+,r2
-	mov.l	@r15+,r3
-	mov.l	@r15+,r4
-	mov.l	@r15+,r5
-	mov.l	@r15+,r6
-	mov.l	@r15+,r7
-	stc	sr,r14
-	mov.l	8f,r9			! BL =1, RB=1
-	or	r9,r14
-	ldc	r14,sr			! here, change the register bank
-	mov	r10,k0
-	mov	r11,k1
-	mov.l	@r15+,r8
-	mov.l	@r15+,r9
-	mov.l	@r15+,r10
-	mov.l	@r15+,r11
-	mov.l	@r15+,r12
-	mov.l	@r15+,r13
-	mov.l	@r15+,r14
-	ldc.l	@r15+,gbr
-	lds.l	@r15+,mach
-	lds.l	@r15+,macl
-	lds.l	@r15+,pr
-	ldc.l	@r15+,spc
-	mov	k0,r15
-	!
-	mov.l	9f,k0
-	jmp	@k0
-	 ldc	k1,ssr
+	add	#4, $r15	! skip syscall number
+	mov.l	@$r15+, $r11	! SSR
+	mov.l	@$r15+, $r0
+	mov.l	@$r15+, $r1
+	mov.l	@$r15+, $r2
+	mov.l	@$r15+, $r3
+	mov.l	@$r15+, $r4
+	mov.l	@$r15+, $r5
+	mov.l	@$r15+, $r6
+	mov.l	@$r15+, $r7
+	stc	$sr, $r14
+	mov.l	1f, $r9			! BL =1, RB=1
+	or	$r9, $r14
+	ldc	$r14, $sr		! here, change the register bank
+	mov	$r11, $k1
+	mov.l	@$r15+, $r8
+	mov.l	@$r15+, $r9
+	mov.l	@$r15+, $r10
+	mov.l	@$r15+, $r11
+	mov.l	@$r15+, $r12
+	mov.l	@$r15+, $r13
+	mov.l	@$r15+, $r14
+	mov.l	@$r15+, $k0
+	ldc.l	@$r15+, $gbr
+	lds.l	@$r15+, $mach
+	lds.l	@$r15+, $macl
+	lds.l	@$r15+, $pr
+	ldc.l	@$r15+, $spc
+	mov	$k0, $r15
+	!
+	mov.l	2f, $k0
+	jmp	@$k0
+	 ldc	$k1, $ssr
 	.balign	4
-8:	.long	0x300000f0
-9:	.long	0xa0000100
+1:	.long	0x300000f0
+2:	.long	0xa0000100
 #endif
 
 	.balign	4
 error:	
-	! STI
-	mov.l	2f,r1
-	stc	sr,r0
-	and	r1,r0
-	ldc	r0,sr
-	!
-	mov.l	1f,r1
-	mov	#-1,r0
-	jmp	@r1
-	 mov.l	r0,@r15		! syscall nr = -1
+	!
+	RESTORE_FLAGS()
+9:	mov.l	1f, $r1
+	mov	#-1, $r0
+	jmp	@$r1
+	 mov.l	$r0, @$r15		! syscall nr = -1
 	.balign	4
 1:	.long	SYMBOL_NAME(do_exception_error)
-2:	.long	0xefffffff	! BL=0
 
-badsys:	mov	#-ENOSYS,r0
+badsys:	mov	#-ENOSYS, $r0
 	rts			! go to ret_from_syscall..
-	 mov.l	r0,@(R0,r15)
+	 mov.l	$r0, @(R0,$r15)
 
 !
 !
 !
 ENTRY(ret_from_fork)
 	bra	SYMBOL_NAME(ret_from_syscall)
-	 add	#4,r15		! pop down bogus r0 (see switch_to MACRO)
+	 add	#4, $r15	! pop down bogus r0 (see switch_to MACRO)
 
 !
 ! The immediate value of "trapa" indicates the number of arguments
@@ -226,83 +229,77 @@
 ! Note that TRA register contains the value = Imm x 4.
 !
 system_call:
-	mov.l	1f,r2
-	mov.l	@r2,r8
+	mov.l	1f, $r2
+	mov.l	@$r2, $r8
 	!
 	! DEBUG DEBUG
-	! mov.l	led,r1
-	! mov	r0,r2
-	! mov.b	r2,@r1
+	! mov.l	led, $r1
+	! mov	$r0, $r2
+	! mov.b	$r2, @$r1
 	!
 #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
-	mov	#0x20,r1
-	extu.b	r1,r1
-	shll2	r1
-	cmp/hs	r1,r8
+	mov	#0x20, $r1
+	extu.b	$r1, $r1
+	shll2	$r1
+	cmp/hs	$r1, $r8
 	bt	debug
 #endif
-	! STI
-	mov.l	2f,r1
-	stc	sr,r2
-	and	r1,r2
-	ldc	r2,sr
-	!
-	mov.l	__n_sys,r1
-	cmp/hs	r1,r0
-	bt/s	badsys
-	 mov	r0,r2
-	!
-	stc	ksp,r1		!
-	mov.l	__tsk_flags,r0	!
-	add	r0,r1		!
-	mov.l	@r1,r0		! Is it trace?
-	tst	#PF_TRACESYS,r0
+	!
+	mov	$r0, $r2
+	RESTORE_FLAGS()
+9:	mov.l	__n_sys, $r1
+	cmp/hs	$r1, $r2
+	bt	badsys
+	!
+	stc	$ksp, $r1
+	mov.l	__tsk_flags, $r0
+	add	$r0, $r1	!
+	mov.l	@$r1, $r0	! Is it trace?
+	tst	#PF_TRACESYS, $r0
 	bt	5f
 	!                     Trace system call
-	mov	#-ENOSYS,r1
-	mov.l	r1,@(R0,r15)
-	mov.l	3f,r1
-	jsr	@r1
+	mov	#-ENOSYS, $r1
+	mov.l	$r1, @(R0,$r15)
+	mov.l	3f, $r1
+	jsr	@$r1
 	 nop
-	mova	4f,r0
+	mova	3f, $r0
 	bra	6f
-	 lds	r0,pr
+	 lds	$r0, $pr
 	!
-5:	mova	ret,r0		! normal case
-	lds	r0,pr
-	!			Build the stack frame if TRA > 0
-	!
-6:	mov	r2,r3
-	mov	r8,r2
-	cmp/pl	r8
-	bf	9f
-	mov.l	@(SP,r15),r0	! get original stack
-7:	add	#-4,r8
-8:	mov.l	@(r0,r8),r1	! May cause address error exception..
-	mov.l	r1,@-r15
-	cmp/pl	r8
+5:	mova	syscall_ret, $r0
+	lds	$r0, $pr
+	!				  Build the stack frame if TRA > 0
+6:	mov	$r2, $r3
+	mov	$r8, $r2
+	cmp/pl	$r8
+	bf	0f
+	mov	#SP, $r0
+	mov.l	@($r0,$r15), $r0	! get original stack
+7:	add	#-4, $r8
+4:	mov.l	@($r0,$r8), $r1		! May cause address error exception..
+	mov.l	$r1, @-$r15
+	cmp/pl	$r8
 	bt	7b
 	!
-9:	mov	r3,r0
-	shll2	r0		! x4
-	mov.l	__sct,r1
-	add	r1,r0
-	mov.l	@r0,r1
-	jmp	@r1
-	 mov	r2,r8
-
+0:	mov	$r3, $r0
+	shll2	$r0		! x4
+	mov.l	__sct, $r1
+	add	$r1, $r0
+	mov.l	@$r0, $r1
+	jmp	@$r1
+	 mov	$r2, $r8
 	! In case of trace
 	.balign	4
-4:	add	r8,r15		! pop off the arguments
-	mov.l	r0,@(R0,r15)	! save the return value
-	mov.l	3f,r1
-	mova	SYMBOL_NAME(ret_from_syscall),r0
-	jmp	@r1
-	 lds	r0,pr
+3:	add	$r8, $r15		! pop off the arguments
+	mov.l	$r0, @(R0,$r15)		! save the return value
+	mov.l	2f, $r1
+	mova	SYMBOL_NAME(ret_from_syscall), $r0
+	jmp	@$r1
+	 lds	$r0, $pr
 	.balign	4
-3:	.long	SYMBOL_NAME(syscall_trace)
-2:	.long	0xefffffff	! BL=0
 1:	.long	TRA
+2:	.long	SYMBOL_NAME(syscall_trace)
 __n_sys:	.long	NR_syscalls
 __sct:		.long	SYMBOL_NAME(sys_call_table)
 __tsk_flags:	.long	flags-8192	! offset from stackbase to tsk->flags
@@ -311,85 +308,80 @@
 	.section	.fixup,"ax"
 fixup_syscall_argerr:
 	rts
-	 mov.l	1f,r0
+	 mov.l	1f, $r0
 1:	.long	-22	! -EINVAL
 .previous
 
 	.section	__ex_table, "a"
 	.balign	4
-	.long	8b,fixup_syscall_argerr
+	.long	4b,fixup_syscall_argerr
 .previous
 
+	.balign	4
 reschedule:
-	mova	SYMBOL_NAME(ret_from_syscall),r0
-	mov.l	1f,r1
-	jmp	@r1
-	 lds	r0,pr
+	mova	SYMBOL_NAME(ret_from_syscall), $r0
+	mov.l	1f, $r1
+	jmp	@$r1
+	 lds	$r0, $pr
 	.balign	4
 1:	.long	SYMBOL_NAME(schedule)
 
 ENTRY(ret_from_irq)
-	mov.l	@(SR,r15),r0	! get status register
-	shll	r0
-	shll	r0		! kernel space?
+	mov.l	@(SR,$r15), $r0	! get status register
+	shll	$r0
+	shll	$r0		! kernel space?
 	bt	restore_all	! Yes, it's from kernel, go back soon
-	! STI
-	mov.l	1f, $r1
-	stc	$sr, $r2
-	and	$r1, $r2
-	ldc	$r2, $sr
 	!
-	bra	ret_with_reschedule
+	RESTORE_FLAGS()
+9:	bra	ret_with_reschedule
 	 nop
 
 ENTRY(ret_from_exception)
-	mov.l	@(SR,r15),r0	! get status register
-	shll	r0
-	shll	r0		! kernel space?
+	mov.l	@(SR,$r15), $r0	! get status register
+	shll	$r0
+	shll	$r0		! kernel space?
 	bt	restore_all	! Yes, it's from kernel, go back soon
-	! STI
-	mov.l	1f, $r1
-	stc	$sr, $r2
-	and	$r1, $r2
-	ldc	$r2, $sr
 	!
-	bra	ret_from_syscall
+	RESTORE_FLAGS()
+9:	bra	ret_from_syscall
 	 nop
 	.balign	4
-1:	.long	0xefffffff	! BL=0
+__INV_IMASK:
+	.long	0xffffff0f	! ~(IMASK)
 
 	.balign 4
-ret:	add	r8,r15		! pop off the arguments
-	mov.l	r0,@(R0,r15)	! save the return value
+syscall_ret:
+	add	$r8, $r15	! pop off the arguments
+	mov.l	$r0, @(R0,$r15)	! save the return value
 	/* fall through */
 
 ENTRY(ret_from_syscall)
-	mov.l	__softirq_state,r0
-	mov.l	@r0,r1
-	mov.l	@(4,r0),r2
-	tst	r2,r1
+	mov.l	__softirq_state, $r0
+	mov.l	@$r0, $r1
+	mov.l	@(4,$r0), $r2
+	tst	$r2, $r1
 	bt	ret_with_reschedule
 handle_softirq:
-	mov.l	__do_softirq,r0
-	jsr	@r0
+	mov.l	__do_softirq, $r0
+	jsr	@$r0
 	 nop
 ret_with_reschedule:
-	stc	ksp,r1
-	mov.l	__minus8192,r0
-	add	r0,r1
-	mov.l	@(need_resched,r1),r0
-	tst	#0xff,r0
+	stc	$ksp, $r1
+	mov.l	__minus8192, $r0
+	add	$r0, $r1
+	mov.l	@(need_resched,$r1), $r0
+	tst	#0xff, $r0
 	bf	reschedule
-	mov.l	@(sigpending,r1),r0
-	tst	#0xff,r0
+	mov.l	@(sigpending,$r1), $r0
+	tst	#0xff, $r0
 	bt	restore_all
 signal_return:
-	mov	r15,r4
-	mov	#0,r5
-	mov.l	__do_signal,r1
-	mova	restore_all,r0
-	jmp	@r1
-	 lds	r0,pr
+	mov	$r15, $r4
+	mov	#0, $r5
+	mov.l	__do_signal, $r1
+	mova	restore_all, $r0
+	jmp	@$r1
+	 lds	$r0, $pr
 	.balign	4
 __do_signal:
 	.long	SYMBOL_NAME(do_signal)
@@ -407,56 +399,57 @@
 	jsr	@$r1
 	 stc	$sr, $r4
 #endif
-	add	#4,r15		! Skip syscall number
-	mov.l	@r15+,r11	! Got SSR into R11
+	add	#4, $r15	! Skip syscall number
+	mov.l	@$r15+, $r11	! Got SSR into R11
 #if defined(__SH4__)
 	mov	$r11, $r12
 #endif
 	!
-	mov.l	1f,r1
-	stc	sr,r0
-	and	r1,r0		! Get IMASK+FD
-	mov.l	2f,r1
-	and	r1,r11
-	or	r0,r11		! Inherit the IMASK+FD value of SR
-	!
-	mov.l	@r15+,r10	! original stack
-	mov.l	@r15+,r0
-	mov.l	@r15+,r1
-	mov.l	@r15+,r2
-	mov.l	@r15+,r3
-	mov.l	@r15+,r4
-	mov.l	@r15+,r5
-	mov.l	@r15+,r6
-	mov.l	@r15+,r7
-	stc	sr,r14
-	mov.l	__blrb_flags,r9		! BL =1, RB=1
-	or	r9,r14
-	ldc	r14,sr			! here, change the register bank
-	mov	r10,k0
-	mov	r11,k1
+	mov.l	1f, $r1
+	stc	$sr, $r0
+	and	$r1, $r0	! Get FD
+	mov.l	2f, $r1
+	and	$r1, $r11
+	or	$r0, $r11	! Inherit the FD value of SR
+	stc	$r5_bank, $r0
+	or	$r0, $r11	! Inherit the IMASK value
+	!
+	mov.l	@$r15+, $r0
+	mov.l	@$r15+, $r1
+	mov.l	@$r15+, $r2
+	mov.l	@$r15+, $r3
+	mov.l	@$r15+, $r4
+	mov.l	@$r15+, $r5
+	mov.l	@$r15+, $r6
+	mov.l	@$r15+, $r7
+	stc	$sr, $r14
+	mov.l	__blrb_flags, $r9	! BL =1, RB=1
+	or	$r9, $r14
+	ldc	$r14, $sr		! here, change the register bank
+	mov	$r11, $k1
 #if defined(__SH4__)
 	mov	$r12, $k2
 #endif
-	mov.l	@r15+,r8
-	mov.l	@r15+,r9
-	mov.l	@r15+,r10
-	mov.l	@r15+,r11
-	mov.l	@r15+,r12
-	mov.l	@r15+,r13
-	mov.l	@r15+,r14
-	ldc.l	@r15+,gbr
-	lds.l	@r15+,mach
-	lds.l	@r15+,macl
-	lds.l	@r15+,pr
-	ldc.l	@r15+,spc
-	ldc	k1,ssr
+	mov.l	@$r15+, $r8
+	mov.l	@$r15+, $r9
+	mov.l	@$r15+, $r10
+	mov.l	@$r15+, $r11
+	mov.l	@$r15+, $r12
+	mov.l	@$r15+, $r13
+	mov.l	@$r15+, $r14
+	mov.l	@$r15+, $k0	! original stack
+	ldc.l	@$r15+, $gbr
+	lds.l	@$r15+, $mach
+	lds.l	@$r15+, $macl
+	lds.l	@$r15+, $pr
+	ldc.l	@$r15+, $spc
+	ldc	$k1, $ssr
 #if defined(__SH4__)
 	shll	$k1
 	shll	$k1
 	bf	9f		! user mode
 	/* Kernel to kernel transition */
-	mov.l	3f, $k1
+	mov.l	1f, $k1
 	tst	$k1, $k2
 	bf	9f		! it hadn't FPU
 	! Kernel to kernel and FPU was used
@@ -496,7 +489,7 @@
 	lds.l	@$r15+, $fpul
 9:
 #endif
-	mov	k0,r15
+	mov	$k0, $r15
 	rte
 	 nop
 
@@ -510,9 +503,8 @@
 __PF_USEDFPU:
 	.long	PF_USEDFPU
 #endif
-1:	.long	0x000080f0	! IMASK+FD
+1:	.long	0x00008000	! FD
 2:	.long	0xffff7f0f	! ~(IMASK+FD)
-3:	.long	0x00008000	! FD=1
 
 ! Exception Vector Base
 !
@@ -524,10 +516,10 @@
 !
 	.balign 	256,0,256
 general_exception:
-	mov.l	1f,k2
-	mov.l	2f,k3
+	mov.l	1f, $k2
+	mov.l	2f, $k3
 	bra	handle_exception
-	 mov.l	@k2,k2
+	 mov.l	@$k2, $k2
 	.balign	4
 2:	.long	SYMBOL_NAME(ret_from_exception)
 1:	.long	EXPEVT
@@ -535,17 +527,17 @@
 !
 	.balign 	1024,0,1024
 tlb_miss:
-	mov.l	1f,k2
-	mov.l	4f,k3
+	mov.l	1f, $k2
+	mov.l	4f, $k3
 	bra	handle_exception
-	 mov.l	@k2,k2
+	 mov.l	@$k2, $k2
 !
 	.balign 	512,0,512
 interrupt:
-	mov.l	2f,k2
-	mov.l	3f,k3
+	mov.l	2f, $k2
+	mov.l	3f, $k3
 	bra	handle_exception
-	 mov.l	@k2,k2
+	 mov.l	@$k2, $k2
 
 	.balign	4
 1:	.long	EXPEVT
@@ -559,9 +551,9 @@
 	! 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)
-	shll	k0
+	stc	$ssr, $k0	! from kernel space?
+	shll	$k0		! Check MD bit (bit30)
+	shll	$k0
 #if defined(__SH4__)
 	bf/s	8f		! it's from user to kernel transition
 	 mov	$r15, $k0	! save original stack to k0
@@ -569,6 +561,7 @@
 	mov.l	2f, $k1
 	stc	$ssr, $k0
 	tst	$k1, $k0
+	mov.l	4f, $k1
 	bf/s	9f		! FPU is not used
 	 mov	$r15, $k0	! save original stack to k0
 	! FPU is used, save FPU
@@ -593,64 +586,63 @@
 	fmov.s	$fr1, @-$r15
 	fmov.s	$fr0, @-$r15
 	bra 9f
-	 mov	#0, $k1
+	 mov.l	3f, $k1
 #else
+	mov.l	3f, $k1
 	bt/s	9f		! it's from kernel to kernel transition
-	 mov	r15,k0		! save original stack to k0 anyway
+	 mov	$r15, $k0	! save original stack to k0 anyway
 #endif
 8:	/* User space to kernel */
-	mov	kernel_sp, $r15	! change to kernel stack
-#if defined(__SH4__)
-	mov.l	2f, $k1		! let kernel release FPU
-#endif
-9:	stc.l	spc,@-r15
-	sts.l	pr,@-r15
-	!
-	lds	k3,pr		! Set the return address to pr
-	!
-	sts.l	macl,@-r15
-	sts.l	mach,@-r15
-	stc.l	gbr,@-r15
-	mov.l	r14,@-r15
-	!
-	stc	sr,r14		! Back to normal register bank, and
-#if defined(__SH4__)
-	or	$k1, $r14	! may release FPU
-#endif
-	mov.l	3f,k1
-	and	k1,r14		! ...
-	ldc	r14,sr		! ...changed here.
-	!
-	mov.l	r13,@-r15
-	mov.l	r12,@-r15
-	mov.l	r11,@-r15
-	mov.l	r10,@-r15
-	mov.l	r9,@-r15
-	mov.l	r8,@-r15
-	mov.l	r7,@-r15
-	mov.l	r6,@-r15
-	mov.l	r5,@-r15
-	mov.l	r4,@-r15
-	mov.l	r3,@-r15
-	mov.l	r2,@-r15
-	mov.l	r1,@-r15
-	mov.l	r0,@-r15
-	stc.l	r0_bank,@-r15	! save orignal stack
-	stc.l	ssr,@-r15
-	mov.l	r0,@-r15	! push r0 again (for syscall number)
+	mov	$kernel_sp, $r15	! change to kernel stack
+	mov.l	4f, $k1			! let kernel release FPU
+9:	stc.l	$spc, @-$r15
+	sts.l	$pr, @-$r15
+	!
+	lds	$k3, $pr		! Set the return address to pr
+	!
+	sts.l	$macl, @-$r15
+	sts.l	$mach, @-$r15
+	stc.l	$gbr, @-$r15
+	mov.l	$k0, @-$r15	! save orignal stack
+	mov.l	$r14, @-$r15
+	!
+	stc	$sr, $r14	! Back to normal register bank, and
+	or	$k1, $r14	! Block all interrupts, may release FPU
+	mov.l	5f, $k1
+	and	$k1, $r14	! ...
+	ldc	$r14, $sr	! ...changed here.
+	!
+	mov.l	$r13, @-$r15
+	mov.l	$r12, @-$r15
+	mov.l	$r11, @-$r15
+	mov.l	$r10, @-$r15
+	mov.l	$r9, @-$r15
+	mov.l	$r8, @-$r15
+	mov.l	$r7, @-$r15
+	mov.l	$r6, @-$r15
+	mov.l	$r5, @-$r15
+	mov.l	$r4, @-$r15
+	mov.l	$r3, @-$r15
+	mov.l	$r2, @-$r15
+	mov.l	$r1, @-$r15
+	mov.l	$r0, @-$r15
+	stc.l	$ssr, @-$r15
+	mov.l	$r0, @-$r15	! push $r0 again (for syscall number)
 	! Then, dispatch to the handler, according to the excepiton code.
-	stc	k_ex_code,r1
-	shlr2	r1
-	shlr	r1
-	mov.l	1f,r0
-	add	r1,r0
-	mov.l	@r0,r0
-	jmp	@r0
-	 mov.l	@r15,r0		! recovering r0..
+	stc	$k_ex_code, $r1
+	shlr2	$r1
+	shlr	$r1
+	mov.l	1f, $r0
+	add	$r1, $r0
+	mov.l	@$r0, $r0
+	jmp	@$r0
+	 mov.l	@$r15, $r0	! recovering $r0..
 	.balign	4
 1:	.long	SYMBOL_NAME(exception_handling_table)
 2:	.long	0x00008000	! FD=1
-3:	.long	0xdfffffff	! RB=0, leave BL=1
+3:	.long	0x000000f0	! FD=0, IMASK=15
+4:	.long	0x000080f0	! FD=1, IMASK=15
+5:	.long	0xcfffffff	! RB=0, BL=0
 
 none:
 	rts
@@ -679,7 +671,7 @@
 ENTRY(nmi_slot)
 	.long	none				! Not implemented yet
 ENTRY(user_break_point_trap)
-	.long	error				! Not implemented yet
+	.long	break_point_trap
 ENTRY(interrupt_table)
 	! external hardware
 	.long	SYMBOL_NAME(do_IRQ)	! 0000
@@ -985,6 +977,8 @@
 	.long SYMBOL_NAME(sys_setfsuid)		/* 215 */
 	.long SYMBOL_NAME(sys_setfsgid)
 	.long SYMBOL_NAME(sys_pivot_root)
+	.long SYMBOL_NAME(sys_mincore)
+	.long SYMBOL_NAME(sys_madvise)
 
 	/*
 	 * NOTE!! This doesn't have to be exact - we just have
@@ -992,7 +986,7 @@
 	 * entries. Don't panic if you notice that this hasn't
 	 * been shrunk every time we add a new system call.
 	 */
-	.rept NR_syscalls-217
+	.rept NR_syscalls-219
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/kernel/fpu.c linux/arch/sh/kernel/fpu.c
--- v2.3.99-pre3/linux/arch/sh/kernel/fpu.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/fpu.c	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-/* $Id: fpu.c,v 1.27 2000/03/05 01:48:34 gniibe Exp $
+/* $Id: fpu.c,v 1.29 2000/03/22 13:42:10 gniibe Exp $
  *
  * linux/arch/sh/kernel/fpu.c
  *
@@ -114,8 +114,6 @@
  * has the property that no matter wether considered as single or as
  * double precission represents signaling NANS.  
  */
-/* Double presision, NANS as NANS, rounding to nearest, no exceptions */
-#define FPU_DEFAULT  0x00080000
 
 void fpu_init(void)
 {
@@ -156,7 +154,7 @@
 		     "fsts	$fpul, $fr15\n\t"
 		     "frchg"
 		     : /* no output */
-		     : "r" (0), "r" (FPU_DEFAULT));
+		     : "r" (0), "r" (FPSCR_INIT));
 }
 
 asmlinkage void
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/kernel/head.S linux/arch/sh/kernel/head.S
--- v2.3.99-pre3/linux/arch/sh/kernel/head.S	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/head.S	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.16 2000/03/02 00:01:15 gniibe Exp $
+/* $Id: head.S,v 1.17 2000/03/06 12:44:24 gniibe Exp $
  *
  *  arch/sh/kernel/head.S
  *
@@ -37,8 +37,11 @@
  */
 ENTRY(_stext)
 	!			Initialize Status Register
-	mov.l	1f, $r0		! MD=1, RB=0, BL=1
+	mov.l	1f, $r0		! MD=1, RB=0, BL=0, IMASK=0xF
 	ldc	$r0, $sr
+	!			Initialize global interrupt mask
+	mov	#0, $r0
+	ldc	$r0, $r5_bank
 	!
 	mov.l	2f, $r0
 	mov	$r0, $r15	! Set initial r15 (stack pointer)
@@ -62,7 +65,7 @@
 	 nop
 
 	.balign 4
-1:	.long	0x50000000		! MD=1, RB=0, BL=1, FD=0
+1:	.long	0x400000F0		! MD=1, RB=0, BL=0, FD=0, IMASK=0xF
 2:	.long	SYMBOL_NAME(stack)
 3:	.long	SYMBOL_NAME(__bss_start)
 4:	.long	SYMBOL_NAME(_end)
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c
--- v2.3.99-pre3/linux/arch/sh/kernel/irq.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/irq.c	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.11 2000/02/29 11:03:40 gniibe Exp $
+/* $Id: irq.c,v 1.12 2000/03/06 14:07:50 gniibe Exp $
  *
  * linux/arch/sh/kernel/irq.c
  *
@@ -238,11 +238,11 @@
 	regs.syscall_nr = -1;	/* It's not system call */
 
 	/* Get IRQ number */
-	asm volatile("stc	r2_bank,%0\n\t"
+	asm volatile("stc	$r2_bank, %0\n\t"
 		     "shlr2	%0\n\t"
 		     "shlr2	%0\n\t"
 		     "shlr	%0\n\t"
-		     "add	#-16,%0\n\t"
+		     "add	#-16, %0\n\t"
 		     :"=z" (irq));
 
 	kstat.irqs[cpu][irq]++;
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/kernel/irq_imask.c linux/arch/sh/kernel/irq_imask.c
--- v2.3.99-pre3/linux/arch/sh/kernel/irq_imask.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/irq_imask.c	Mon Mar 27 10:26:15 2000
@@ -1,8 +1,8 @@
-/* $Id: irq_imask.c,v 1.2 2000/02/11 04:57:40 gniibe Exp $
+/* $Id: irq_imask.c,v 1.6 2000/03/06 14:11:32 gniibe Exp $
  *
  * linux/arch/sh/kernel/irq_imask.c
  *
- * Copyright (C) 1999  Niibe Yutaka
+ * Copyright (C) 1999, 2000  Niibe Yutaka
  *
  * Simple interrupt handling using IMASK of SR register.
  *
@@ -52,35 +52,40 @@
 	end_imask_irq
 };
 
-void disable_imask_irq(unsigned int irq)
+void static inline set_interrupt_registers(int ip)
 {
 	unsigned long __dummy;
 
+	asm volatile("ldc	%2, $r5_bank\n\t"
+		     "stc	$sr, %0\n\t"
+		     "and	#0xf0, %0\n\t"
+		     "shlr8	%0\n\t"
+		     "cmp/eq	#0x0f, %0\n\t"
+		     "bt	1f	! CLI-ed\n\t"
+		     "stc	$sr, %0\n\t"
+		     "and	%1, %0\n\t"
+		     "or	%2, %0\n\t"
+		     "ldc	%0, $sr\n"
+		     "1:"
+		     : "=&z" (__dummy)
+		     : "r" (~0xf0), "r" (ip << 4));
+}
+
+void disable_imask_irq(unsigned int irq)
+{
 	clear_bit(irq, &imask_mask);
 	if (interrupt_priority < IMASK_PRIORITY - irq)
 		interrupt_priority = IMASK_PRIORITY - irq;
 
-	asm volatile("stc	sr,%0\n\t"
-		     "and	%1,%0\n\t"
-		     "or	%2,%0\n\t"
-		     "ldc	%0,sr"
-		     : "=&r" (__dummy)
-		     : "r" (0xffffff0f), "r" (interrupt_priority << 4));
+	set_interrupt_registers(interrupt_priority);
 }
 
 static void enable_imask_irq(unsigned int irq)
 {
-	unsigned long __dummy;
-
 	set_bit(irq, &imask_mask);
 	interrupt_priority = IMASK_PRIORITY - ffz(imask_mask);
 
-	asm volatile("stc	sr,%0\n\t"
-		     "and	%1,%0\n\t"
-		     "or	%2,%0\n\t"
-		     "ldc	%0,sr"
-		     : "=&r" (__dummy)
-		     : "r" (0xffffff0f), "r" (interrupt_priority << 4));
+	set_interrupt_registers(interrupt_priority);
 }
 
 static void mask_and_ack_imask(unsigned int irq)
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- v2.3.99-pre3/linux/arch/sh/kernel/process.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/process.c	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.28 2000/03/05 02:16:15 gniibe Exp $
+/* $Id: process.c,v 1.33 2000/03/25 00:06:15 gniibe Exp $
  *
  *  linux/arch/sh/kernel/process.c
  *
@@ -94,7 +94,7 @@
 {
 	printk("\n");
 	printk("PC  : %08lx SP  : %08lx SR  : %08lx TEA : %08lx\n",
-	       regs->pc, regs->sp, regs->sr, ctrl_inl(MMU_TEA));
+	       regs->pc, regs->regs[15], regs->sr, ctrl_inl(MMU_TEA));
 	printk("R0  : %08lx R1  : %08lx R2  : %08lx R3  : %08lx\n",
 	       regs->regs[0],regs->regs[1],
 	       regs->regs[2],regs->regs[3]);
@@ -210,22 +210,22 @@
 		struct task_struct *p, struct pt_regs *regs)
 {
 	struct pt_regs *childregs;
+#if defined(__SH4__)
 	struct task_struct *tsk = current;
 
-	childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p)) - 1;
-	struct_cpy(childregs, regs);
-
-#if defined(__SH4__)
 	if (tsk != &init_task) {
 		unlazy_fpu(tsk);
-		struct_cpy(&p->thread.fpu, &current->thread.fpu);
+		p->thread.fpu = current->thread.fpu;
 		p->used_math = tsk->used_math;
 	}
 #endif
+	childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p)) - 1;
+	*childregs = *regs;
+
 	if (user_mode(regs)) {
-		childregs->sp = usp;
+		childregs->regs[15] = usp;
 	} else {
-		childregs->sp = (unsigned long)p+2*PAGE_SIZE;
+		childregs->regs[15] = (unsigned long)p+2*PAGE_SIZE;
 	}
 	childregs->regs[0] = 0; /* Set return value for child */
 	childregs->sr |= SR_FD; /* Invalidate FPU flag */
@@ -244,7 +244,7 @@
 	dump->magic = CMAGIC;
 	dump->start_code = current->mm->start_code;
 	dump->start_data  = current->mm->start_data;
-	dump->start_stack = regs->sp & ~(PAGE_SIZE - 1);
+	dump->start_stack = regs->regs[15] & ~(PAGE_SIZE - 1);
 	dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
 	dump->u_dsize = (current->mm->brk + (PAGE_SIZE-1) - dump->start_data) >> PAGE_SHIFT;
 	dump->u_ssize = (current->mm->start_stack - dump->start_stack +
@@ -279,7 +279,7 @@
 			unsigned long r6, unsigned long r7,
 			struct pt_regs regs)
 {
-	return do_fork(SIGCHLD, regs.sp, &regs);
+	return do_fork(SIGCHLD, regs.regs[15], &regs);
 }
 
 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
@@ -287,7 +287,7 @@
 			 struct pt_regs regs)
 {
 	if (!newsp)
-		newsp = regs.sp;
+		newsp = regs.regs[15];
 	return do_fork(clone_flags, newsp, &regs);
 }
 
@@ -305,7 +305,7 @@
 			 unsigned long r6, unsigned long r7,
 			 struct pt_regs regs)
 {
-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, &regs);
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], &regs);
 }
 
 /*
@@ -369,4 +369,13 @@
 	       (current->flags&PF_USEDFPU)?'C':' ',
 	       (init_task.flags&PF_USEDFPU)?'K':' ', (sr&SR_FD)?' ':'F');
 	restore_flags(flags);
+}
+
+asmlinkage void break_point_trap(void)
+{
+	/* Clear traicng.  */
+	ctrl_outw(0, UBC_BBRA);
+	ctrl_outw(0, UBC_BBRB);
+
+	force_sig(SIGTRAP, current);
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/kernel/ptrace.c linux/arch/sh/kernel/ptrace.c
--- v2.3.99-pre3/linux/arch/sh/kernel/ptrace.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sh/kernel/ptrace.c	Mon Mar 27 10:26:15 2000
@@ -1,6 +1,13 @@
-/*
- * Surely this doesn't work... (we need to design ptrace for SupreH)
+/* $Id: ptrace.c,v 1.4 2000/03/22 13:59:01 gniibe Exp $
+ *
  * linux/arch/sh/kernel/ptrace.c
+ *
+ * Original x86 implementation:
+ *	By Ross Biro 1/23/92
+ *	edited by Linus Torvalds
+ *
+ * SuperH version:   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
+ *
  */
 
 #include <linux/kernel.h>
@@ -12,135 +19,126 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 
+#include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/processor.h>
+#include <asm/mmu_context.h>
 
 /*
  * does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
  */
 
-/* determines which flags the user has access to. */
-/* 1 = access 0 = no access */
-#define FLAG_MASK 0x00044dd5
-
-/* set's the trap flag. */
-#define TRAP_FLAG 0x100
-
 /*
- * Offset of eflags on child stack..
+ * This routine will get a word off of the process kernel stack.
  */
-#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
-
-/*
- * this routine will get a word off of the processes privileged stack. 
- * the offset is how far from the base addr as stored in the TSS.  
- * this routine assumes that all the privileged stacks are in our
- * data space.
- */   
 static inline int get_stack_long(struct task_struct *task, int offset)
 {
 	unsigned char *stack;
 
-	stack = (unsigned char *)task->thread.sp;
+	stack = (unsigned char *)task + THREAD_SIZE - sizeof(struct pt_regs);
 	stack += offset;
 	return (*((int *)stack));
 }
 
 /*
- * this routine will put a word on the processes privileged stack. 
- * the offset is how far from the base addr as stored in the TSS.  
- * this routine assumes that all the privileged stacks are in our
- * data space.
+ * This routine will put a word on the process kernel stack.
  */
 static inline int put_stack_long(struct task_struct *task, int offset,
-	unsigned long data)
+				 unsigned long data)
 {
-	unsigned char * stack;
+	unsigned char *stack;
 
-	stack = (unsigned char *) task->thread.sp;
+	stack = (unsigned char *)task + THREAD_SIZE - sizeof(struct pt_regs);
 	stack += offset;
 	*(unsigned long *) stack = data;
 	return 0;
 }
 
-static int putreg(struct task_struct *child,
-	unsigned long regno, unsigned long value)
+static void
+compute_next_pc(struct pt_regs *regs, unsigned short inst,
+		unsigned long *pc1, unsigned long *pc2)
 {
-#if 0
-	switch (regno >> 2) {
-		case ORIG_EAX:
-			return -EIO;
-		case FS:
-			if (value && (value & 3) != 3)
-				return -EIO;
-			child->thread.fs = value;
-			return 0;
-		case GS:
-			if (value && (value & 3) != 3)
-				return -EIO;
-			child->thread.gs = value;
-			return 0;
-		case DS:
-		case ES:
-			if (value && (value & 3) != 3)
-				return -EIO;
-			value &= 0xffff;
-			break;
-		case SS:
-		case CS:
-			if ((value & 3) != 3)
-				return -EIO;
-			value &= 0xffff;
-			break;
-		case EFL:
-			value &= FLAG_MASK;
-			value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;
-	}
-	if (regno > GS*4)
-		regno -= 2*4;
-	put_stack_long(child, regno - sizeof(struct pt_regs), value);
-#endif
-	return 0;
+	int nib[4]
+		= { (inst >> 12) & 0xf,
+		    (inst >> 8) & 0xf,
+		    (inst >> 4) & 0xf,
+		    inst & 0xf};
+
+	/* bra & bsr */
+	if (nib[0] == 0xa || nib[0] == 0xb) {
+		*pc1 = regs->pc + 4 + ((short) ((inst & 0xfff) << 4) >> 3);
+		*pc2 = (unsigned long) -1;
+		return;
+	}
+
+	/* bt & bf */
+	if (nib[0] == 0x8 && (nib[1] == 0x9 || nib[1] == 0xb)) {
+		*pc1 = regs->pc + 4 + ((char) (inst & 0xff) << 1);
+		*pc2 = regs->pc + 2;
+		return;
+	}
+
+	/* bt/s & bf/s */
+	if (nib[0] == 0x8 && (nib[1] == 0xd || nib[1] == 0xf)) {
+		*pc1 = regs->pc + 4 + ((char) (inst & 0xff) << 1);
+		*pc2 = regs->pc + 4;
+		return;
+	}
+
+	/* jmp & jsr */
+	if (nib[0] == 0x4 && nib[3] == 0xb
+	    && (nib[2] == 0x0 || nib[2] == 0x2)) {
+		*pc1 = regs->regs[nib[1]];
+		*pc2 = (unsigned long) -1;
+		return;
+	}
+
+	/* braf & bsrf */
+	if (nib[0] == 0x0 && nib[3] == 0x3
+	    && (nib[2] == 0x0 || nib[2] == 0x2)) {
+		*pc1 = regs->pc + 4 + regs->regs[nib[1]];
+		*pc2 = (unsigned long) -1;
+		return;
+	}
+
+	if (inst == 0x000b) {
+		*pc1 = regs->pr;
+		*pc2 = (unsigned long) -1;
+		return;
+	}
+
+	*pc1 = regs->pc + 2;
+	*pc2 = (unsigned long) -1;
+	return;
 }
 
-static unsigned long getreg(struct task_struct *child,
-	unsigned long regno)
+/* Tracing by user break controller.  */
+static void
+ubc_set_tracing(int asid, unsigned long nextpc1, unsigned nextpc2)
 {
-	unsigned long retval = ~0UL;
-
-#if 0
-	switch (regno >> 2) {
-		case FS:
-			retval = child->thread.fs;
-			break;
-		case GS:
-			retval = child->thread.gs;
-			break;
-		case DS:
-		case ES:
-		case SS:
-		case CS:
-			retval = 0xffff;
-			/* fall through */
-		default:
-			if (regno > GS*4)
-				regno -= 2*4;
-			regno = regno - sizeof(struct pt_regs);
-			retval &= get_stack_long(child, regno);
+	ctrl_outl(nextpc1, UBC_BARA);
+	ctrl_outb(asid, UBC_BASRA);
+	ctrl_outb(BAMR_12, UBC_BAMRA);
+	ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA);
+
+	if (nextpc2 != (unsigned long) -1) {
+		ctrl_outl(nextpc2, UBC_BARB);
+		ctrl_outb(asid, UBC_BASRB);
+		ctrl_outb(BAMR_12, UBC_BAMRB);
+		ctrl_outw(BBR_INST | BBR_READ, UBC_BBRB);
 	}
-#endif
-	return retval;
+	ctrl_outw(BRCR_PCBA | BRCR_PCBB, UBC_BRCR);
 }
 
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
-	struct task_struct *child;
+	struct task_struct *child, *tsk = current;
 	struct user * dummy = NULL;
 	unsigned long flags;
-	int i, ret;
+	int ret;
 
 	lock_kernel();
 	ret = -EPERM;
@@ -163,16 +161,16 @@
 	if (pid == 1)		/* you may not mess with init */
 		goto out;
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
+		if (child == tsk)
 			goto out;
 		if ((!child->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-	 	    (current->gid != child->sgid) ||
-	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+		    (tsk->uid != child->euid) ||
+		    (tsk->uid != child->suid) ||
+		    (tsk->uid != child->uid) ||
+	 	    (tsk->gid != child->egid) ||
+	 	    (tsk->gid != child->sgid) ||
+	 	    (!cap_issubset(child->cap_permitted, tsk->cap_permitted)) ||
+	 	    (tsk->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
 			goto out;
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED)
@@ -180,9 +178,9 @@
 		child->flags |= PF_PTRACED;
 
 		write_lock_irqsave(&tasklist_lock, flags);
-		if (child->p_pptr != current) {
+		if (child->p_pptr != tsk) {
 			REMOVE_LINKS(child);
-			child->p_pptr = current;
+			child->p_pptr = tsk;
 			SET_LINKS(child);
 		}
 		write_unlock_irqrestore(&tasklist_lock, flags);
@@ -198,257 +196,180 @@
 		if (request != PTRACE_KILL)
 			goto out;
 	}
-	if (child->p_pptr != current)
+	if (child->p_pptr != tsk)
 		goto out;
 
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
-		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-		case PTRACE_PEEKDATA: {
-			unsigned long tmp;
-			int copied;
-
-			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-			ret = -EIO;
-			if (copied != sizeof(tmp))
-				goto out;
-			ret = put_user(tmp,(unsigned long *) data);
-			goto out;
-		}
+	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKDATA: {
+		unsigned long tmp;
+		int copied;
+
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		ret = -EIO;
+		if (copied != sizeof(tmp))
+			break;
+		ret = put_user(tmp,(unsigned long *) data);
+		break;
+	}
 
 	/* read the word at location addr in the USER area. */
-		case PTRACE_PEEKUSR: {
-			unsigned long tmp;
+	case PTRACE_PEEKUSR: {
+		unsigned long tmp;
 
-			ret = -EIO;
-			if ((addr & 3) || addr < 0 || 
-			    addr > sizeof(struct user) - 3)
-				goto out;
-
-			tmp = 0;  /* Default return condition */
-			if(addr < 17*sizeof(long))
-				tmp = getreg(child, addr);
-#if 0
-			if(addr >= (long) &dummy->u_debugreg[0] &&
-			   addr <= (long) &dummy->u_debugreg[7]){
-				addr -= (long) &dummy->u_debugreg[0];
-				addr = addr >> 2;
-				tmp = child->thread.debugreg[addr];
-			};
-#endif
-			ret = put_user(tmp,(unsigned long *) data);
-			goto out;
-		}
+		ret = -EIO;
+		if ((addr & 3) || addr < 0 || 
+		    addr > sizeof(struct user) - 3)
+			break;
 
-      /* when I and D space are separate, this will have to be fixed. */
-		case PTRACE_POKETEXT: /* write the word at location addr. */
-		case PTRACE_POKEDATA:
-			ret = 0;
-			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
-				goto out;
-			ret = -EIO;
-			goto out;
+		if (addr < sizeof(struct pt_regs))
+			tmp = get_stack_long(child, addr);
+		else if (addr >= (long) &dummy->fpu &&
+			 addr < (long) &dummy->u_fpvalid) {
+			if (!child->used_math) {
+				if (addr == (long)&dummy->fpu.fpscr)
+					tmp = FPSCR_INIT;
+				else
+					tmp = 0;
+			} else
+				tmp = ((long *)&child->thread.fpu)
+					[(addr - (long)&dummy->fpu) >> 2];
+		} else if (addr == (long) &dummy->u_fpvalid)
+			tmp = child->used_math;
+		else
+			tmp = 0;
+		ret = put_user(tmp, (unsigned long *)data);
+		break;
+	}
 
-		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-			ret = -EIO;
-			if ((addr & 3) || addr < 0 || 
-			    addr > sizeof(struct user) - 3)
-				goto out;
-
-			if (addr < 17*sizeof(long)) {
-				ret = putreg(child, addr, data);
-				goto out;
-			}
-
-		  /* We need to be very careful here.  We implicitly
-		     want to modify a portion of the task_struct, and we
-		     have to be selective about what portions we allow someone
-		     to modify. */
-#if 0
-		  if(addr >= (long) &dummy->u_debugreg[0] &&
-		     addr <= (long) &dummy->u_debugreg[7]){
-
-			  if(addr == (long) &dummy->u_debugreg[4]) return -EIO;
-			  if(addr == (long) &dummy->u_debugreg[5]) return -EIO;
-			  if(addr < (long) &dummy->u_debugreg[4] &&
-			     ((unsigned long) data) >= TASK_SIZE-3) return -EIO;
-			  
-			  ret = -EIO;
-			  if(addr == (long) &dummy->u_debugreg[7]) {
-				  data &= ~DR_CONTROL_RESERVED;
-				  for(i=0; i<4; i++)
-					  if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
-						  goto out;
-			  };
-
-			  addr -= (long) &dummy->u_debugreg;
-			  addr = addr >> 2;
-			  child->thread.debugreg[addr] = data;
-			  ret = 0;
-			  goto out;
-		  };
-#endif
-		  ret = -EIO;
-		  goto out;
+	/* when I and D space are separate, this will have to be fixed. */
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		ret = 0;
+		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+			break;
+		ret = -EIO;
+		break;
 
-		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-		case PTRACE_CONT: { /* restart after signal. */
-			long tmp;
-
-			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
-				goto out;
-			if (request == PTRACE_SYSCALL)
-				child->flags |= PF_TRACESYS;
-			else
-				child->flags &= ~PF_TRACESYS;
-			child->exit_code = data;
-	/* make sure the single step bit is not set. */
-#if 0
-			tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
-			put_stack_long(child, EFL_OFFSET,tmp);
-#endif
-			wake_up_process(child);
+	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+		ret = -EIO;
+		if ((addr & 3) || addr < 0 || 
+		    addr > sizeof(struct user) - 3)
+			break;
+
+		if (addr < sizeof(struct pt_regs))
+			ret = put_stack_long(child, addr, data);
+		else if (addr >= (long) &dummy->fpu &&
+			 addr < (long) &dummy->u_fpvalid) {
+			child->used_math = 1;
+			((long *)&child->thread.fpu)
+				[(addr - (long)&dummy->fpu) >> 2] = data;
+			ret = 0;
+		} else if (addr == (long) &dummy->u_fpvalid) {
+			child->used_math = data?1:0;
 			ret = 0;
-			goto out;
 		}
+		break;
+
+	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: { /* restart after signal. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL)
+			child->flags |= PF_TRACESYS;
+		else
+			child->flags &= ~PF_TRACESYS;
+		child->exit_code = data;
+		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;
+		child->exit_code = SIGKILL;
+		wake_up_process(child);
+		break;
+	}
 
-			ret = 0;
-			if (child->state == TASK_ZOMBIE)	/* already dead */
-				goto out;
-			child->exit_code = SIGKILL;
-	/* make sure the single step bit is not set. */
-#if 0
-			tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
-			put_stack_long(child, EFL_OFFSET, tmp);
-#endif
-			wake_up_process(child);
-			goto out;
-		}
+	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+		long tmp, pc;
+		struct pt_regs *dummy = NULL;
+		struct pt_regs *regs;
+		unsigned long nextpc1, nextpc2;
+		unsigned short insn;
 
-		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
-			long tmp;
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		child->flags &= ~PF_TRACESYS;
+		if ((child->flags & PF_DTRACE) == 0) {
+			/* Spurious delayed TF traps may occur */
+			child->flags |= PF_DTRACE;
+		}
 
-			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
-				goto out;
-			child->flags &= ~PF_TRACESYS;
-			if ((child->flags & PF_DTRACE) == 0) {
-				/* Spurious delayed TF traps may occur */
-				child->flags |= PF_DTRACE;
-			}
-#if 0
-			tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
-			put_stack_long(child, EFL_OFFSET, tmp);
+		/* Compute next pc.  */
+		pc = get_stack_long(child, (long)&dummy->pc);
+		regs = (struct pt_regs *)((unsigned long)child + THREAD_SIZE - sizeof(struct pt_regs));
+		if (access_process_vm(child, pc&~3, &tmp, sizeof(tmp), 1) != sizeof(data))
+			break;
+ 
+#ifdef  __LITTLE_ENDIAN__
+		if (pc & 3)
+			insn = tmp >> 16;
+		else
+			insn = tmp & 0xffff;
+#else
+		if (pc & 3)
+			insn = tmp & 0xffff;
+		else
+			insn = tmp >> 16;
 #endif
-			child->exit_code = data;
-	/* give it a chance to run. */
-			wake_up_process(child);
-			ret = 0;
-			goto out;
-		}
+		compute_next_pc (regs, insn, &nextpc1, &nextpc2);
 
-		case PTRACE_DETACH: { /* detach a process that was attached. */
-			long tmp;
+		if (nextpc1 & 0x80000000)
+			break;
+		if (nextpc2 != (unsigned long) -1 && (nextpc2 & 0x80000000))
+			break;
 
-			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
-				goto out;
-			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
-			child->exit_code = data;
-			write_lock_irqsave(&tasklist_lock, flags);
-			REMOVE_LINKS(child);
-			child->p_pptr = child->p_opptr;
-			SET_LINKS(child);
-			write_unlock_irqrestore(&tasklist_lock, flags);
-	/* make sure the single step bit is not set. */
-#if 0
-			tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
-			put_stack_long(child, EFL_OFFSET, tmp);
-#endif
-			wake_up_process(child);
-			ret = 0;
-			goto out;
-		}
-#if 0
-		case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-		  	if (!access_ok(VERIFY_WRITE, (unsigned *)data,
-				       17*sizeof(long)))
-			  {
-			    ret = -EIO;
-			    goto out;
-			  }
-			for ( i = 0; i < 17*sizeof(long); i += sizeof(long) )
-			  {
-			    __put_user(getreg(child, i),(unsigned long *) data);
-			    data += sizeof(long);
-			  }
-			ret = 0;
-			goto out;
-		  };
+		ubc_set_tracing(child->mm->context & MMU_CONTEXT_ASID_MASK,
+				nextpc1, nextpc2);
 
-		case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-			unsigned long tmp;
-		  	if (!access_ok(VERIFY_READ, (unsigned *)data,
-				       17*sizeof(long)))
-			  {
-			    ret = -EIO;
-			    goto out;
-			  }
-			for ( i = 0; i < 17*sizeof(long); i += sizeof(long) )
-			  {
-			    __get_user(tmp, (unsigned long *) data);
-			    putreg(child, i, tmp);
-			    data += sizeof(long);
-			  }
-			ret = 0;
-			goto out;
-		  };
+		child->exit_code = data;
+		/* give it a chance to run. */
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
 
-		case PTRACE_GETFPREGS: { /* Get the child FPU state. */
-			if (!access_ok(VERIFY_WRITE, (unsigned *)data,
-				       sizeof(struct user_i387_struct)))
-			  {
-			    ret = -EIO;
-			    goto out;
-			  }
-			ret = 0;
-			if ( !child->used_math ) {
-			  /* Simulate an empty FPU. */
-			  child->thread.i387.hard.cwd = 0xffff037f;
-			  child->thread.i387.hard.swd = 0xffff0000;
-			  child->thread.i387.hard.twd = 0xffffffff;
-			}
-				__copy_to_user((void *)data, &child->thread.i387.hard,
-						sizeof(struct user_i387_struct));
-			goto out;
-		  };
+	case PTRACE_DETACH: { /* detach a process that was attached. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+		child->exit_code = data;
+		write_lock_irqsave(&tasklist_lock, flags);
+		REMOVE_LINKS(child);
+		child->p_pptr = child->p_opptr;
+		SET_LINKS(child);
+		write_unlock_irqrestore(&tasklist_lock, flags);
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
 
-		case PTRACE_SETFPREGS: { /* Set the child FPU state. */
-			if (!access_ok(VERIFY_READ, (unsigned *)data,
-				       sizeof(struct user_i387_struct)))
-			  {
-			    ret = -EIO;
-			    goto out;
-			  }
-			child->used_math = 1;
-			  __copy_from_user(&child->thread.i387.hard, (void *)data,
-					   sizeof(struct user_i387_struct));
-			ret = 0;
-			goto out;
-		  };
-#endif
-		default:
-			ret = -EIO;
-			goto out;
+	default:
+		ret = -EIO;
+		break;
 	}
 out:
 	unlock_kernel();
@@ -457,20 +378,22 @@
 
 asmlinkage void syscall_trace(void)
 {
-	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
-			!= (PF_PTRACED|PF_TRACESYS))
+	struct task_struct *tsk = current;
+
+	if ((tsk->flags & (PF_PTRACED|PF_TRACESYS))
+	    != (PF_PTRACED|PF_TRACESYS))
 		return;
-	current->exit_code = SIGTRAP;
-	current->state = TASK_STOPPED;
-	notify_parent(current, SIGCHLD);
+	tsk->exit_code = SIGTRAP;
+	tsk->state = TASK_STOPPED;
+	notify_parent(tsk, SIGCHLD);
 	schedule();
 	/*
 	 * this isn't the same as continuing with a signal, but it will do
 	 * for normal use.  strace only continues with a signal if the
 	 * stopping signal is not SIGTRAP.  -brl
 	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
+	if (tsk->exit_code) {
+		send_sig(tsk->exit_code, tsk, 1);
+		tsk->exit_code = 0;
 	}
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c
--- v2.3.99-pre3/linux/arch/sh/kernel/signal.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/signal.c	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.16 2000/01/29 11:31:31 gniibe Exp gniibe $
+/* $Id: signal.c,v 1.21 2000/03/11 14:06:21 gniibe Exp $
  *
  *  linux/arch/sh/kernel/signal.c
  *
@@ -6,7 +6,7 @@
  *
  *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
  *
- *  SuperH version:  Copyright (C) 1999  Niibe Yutaka
+ *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
  *
  */
 
@@ -125,7 +125,7 @@
 		unsigned long r6, unsigned long r7,
 		struct pt_regs regs)
 {
-	return do_sigaltstack(uss, uoss, regs.sp);
+	return do_sigaltstack(uss, uoss, regs.regs[15]);
 }
 
 
@@ -136,7 +136,6 @@
 struct sigframe
 {
 	struct sigcontext sc;
-	/* FPU data should come here: SH-3 has no FPU */
 	unsigned long extramask[_NSIG_WORDS-1];
 	char retcode[4];
 };
@@ -147,10 +146,38 @@
 	void *puc;
 	struct siginfo info;
 	struct ucontext uc;
-	/* FPU should come here: SH-3 has no FPU */
 	char retcode[4];
 };
 
+#if defined(__SH4__)
+static inline int restore_sigcontext_fpu(struct sigcontext *sc)
+{
+	current->used_math = 1;
+	return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0],
+				sizeof(long)*(NUM_FPU_REGS*2+2));
+}
+
+static inline int save_sigcontext_fpu(struct sigcontext *sc)
+{
+	struct task_struct *tsk = current;
+
+	if (!tsk->used_math) {
+		sc->owend_fp = 0;
+		return 0;
+	}
+
+	sc->owend_fp = 1;
+
+	/* This will cause a "finit" to be triggered by the next
+	   attempted FPU operation by the 'current' process.
+	   */
+	tsk->used_math = 0;
+
+	unlazy_fpu(tsk);
+	return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard,
+			      sizeof(long)*(NUM_FPU_REGS*2+2));
+}
+#endif
 
 static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *r0_p)
@@ -165,15 +192,28 @@
 	COPY(regs[8]);	COPY(regs[9]);
 	COPY(regs[10]);	COPY(regs[11]);
 	COPY(regs[12]);	COPY(regs[13]);
-	COPY(regs[14]);	COPY(sp);
+	COPY(regs[14]);	COPY(regs[15]);
 	COPY(gbr);	COPY(mach);
 	COPY(macl);	COPY(pr);
 	COPY(sr);	COPY(pc);
 #undef COPY
 
+#if defined(__SH4__)
+	{
+		int owned_fp;
+		struct task_struct *tsk = current;
+
+		regs->sr |= SR_FD; /* Release FPU */
+		clear_fpu(tsk);
+		current->used_math = 0;
+		__get_user (owned_fp, &context->sc_ownedfp);
+		if (owned_fp)
+			err |= restore_sigcontext_fpu(sc);
+	}
+#endif
+
 	regs->syscall_nr = -1;		/* disable syscall checks */
 	err |= __get_user(*r0_p, &sc->sc_regs[0]);
-
 	return err;
 }
 
@@ -181,7 +221,7 @@
 			     unsigned long r6, unsigned long r7,
 			     struct pt_regs regs)
 {
-	struct sigframe *frame = (struct sigframe *)regs.sp;
+	struct sigframe *frame = (struct sigframe *)regs.regs[15];
 	sigset_t set;
 	int r0;
 
@@ -214,7 +254,7 @@
 				unsigned long r6, unsigned long r7,
 				struct pt_regs regs)
 {
-	struct rt_sigframe *frame = (struct rt_sigframe *)regs.sp;
+	struct rt_sigframe *frame = (struct rt_sigframe *)regs.regs[15];
 	sigset_t set;
 	stack_t st;
 	int r0;
@@ -238,7 +278,7 @@
 		goto badframe;
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
-	do_sigaltstack(&st, NULL, regs.sp);
+	do_sigaltstack(&st, NULL, regs.regs[15]);
 
 	return r0;
 
@@ -265,12 +305,16 @@
 	COPY(regs[8]);	COPY(regs[9]);
 	COPY(regs[10]);	COPY(regs[11]);
 	COPY(regs[12]);	COPY(regs[13]);
-	COPY(regs[14]);	COPY(sp);
+	COPY(regs[14]);	COPY(regs[15]);
 	COPY(gbr);	COPY(mach);
 	COPY(macl);	COPY(pr);
 	COPY(sr);	COPY(pc);
 #undef COPY
 
+#if defined(__SH4__)
+	err |= save_sigcontext_fpu(sc);
+#endif
+
 	/* non-iBCS2 extensions.. */
 	err |= __put_user(mask, &sc->oldmask);
 
@@ -296,7 +340,7 @@
 	int err = 0;
 	int signal;
 
-	frame = get_sigframe(ka, regs->sp, sizeof(*frame));
+	frame = get_sigframe(ka, regs->regs[15], sizeof(*frame));
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
@@ -334,7 +378,7 @@
 		goto give_sigsegv;
 
 	/* Set up registers for signal handler */
-	regs->sp = (unsigned long) frame;
+	regs->regs[15] = (unsigned long) frame;
 	regs->regs[4] = signal; /* Arg for signal handler */
 	regs->pc = (unsigned long) ka->sa.sa_handler;
 
@@ -361,7 +405,7 @@
 	int err = 0;
 	int signal;
 
-	frame = get_sigframe(ka, regs->sp, sizeof(*frame));
+	frame = get_sigframe(ka, regs->regs[15], sizeof(*frame));
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
@@ -381,7 +425,8 @@
 	err |= __put_user(0, &frame->uc.uc_link);
 	err |= __put_user((void *)current->sas_ss_sp,
 			  &frame->uc.uc_stack.ss_sp);
-	err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(sas_ss_flags(regs->regs[15]),
+			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
 	err |= setup_sigcontext(&frame->uc.uc_mcontext,
 			        regs, set->sig[0]);
@@ -407,7 +452,7 @@
 		goto give_sigsegv;
 
 	/* Set up registers for signal handler */
-	regs->sp = (unsigned long) frame;
+	regs->regs[15] = (unsigned long) frame;
 	regs->regs[4] = signal; /* Arg for signal handler */
 	regs->pc = (unsigned long) ka->sa.sa_handler;
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/lib/Makefile linux/arch/sh/lib/Makefile
--- v2.3.99-pre3/linux/arch/sh/lib/Makefile	Wed Oct 27 16:34:12 1999
+++ linux/arch/sh/lib/Makefile	Thu Mar 30 16:56:04 2000
@@ -3,7 +3,7 @@
 #
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
 
 L_TARGET = lib.a
 L_OBJS  = delay.o memcpy.o memset.o memmove.o memchr.o old-checksum.o \
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c
--- v2.3.99-pre3/linux/arch/sh/mm/cache.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/mm/cache.c	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-/* $Id: cache.c,v 1.9 2000/02/14 12:45:26 gniibe Exp $
+/* $Id: cache.c,v 1.10 2000/03/07 11:58:34 gniibe Exp $
  *
  *  linux/arch/sh/mm/cache.c
  *
@@ -67,36 +67,15 @@
 #define CACHE_IC_NUM_WAYS	  1
 #endif
 
-#define jump_to_p2(__dummy) \
-	asm volatile("mova	1f,%0\n\t" \
-		     "add	%1,%0\n\t" \
-		     "jmp	@r0		! Jump to P2 area\n\t" \
-		     " nop\n\t" \
-		     ".balign 4\n" \
-		     "1:" \
-		     : "=&z" (__dummy) \
-		     : "r" (0x20000000))
-
-#define back_to_p1(__dummy) \
-	asm volatile("nop;nop;nop;nop;nop;nop\n\t" \
-		     "mova	9f,%0\n\t" \
-		     "sub	%1,%0\n\t" \
-		     "jmp	@r0		! Back to P1 area\n\t" \
-		     " nop\n\t" \
-		     ".balign 4\n" \
-		     "9:" \
-		     : "=&z" (__dummy) \
-		     : "r" (0x20000000), "0" (__dummy))
-
 /* Write back caches to memory (if needed) and invalidates the caches */
 void cache_flush_area(unsigned long start, unsigned long end)
 {
-	unsigned long flags, __dummy;
+	unsigned long flags;
 	unsigned long addr, data, v, p;
 
 	start &= ~(L1_CACHE_BYTES-1);
 	save_and_cli(flags);
-	jump_to_p2(__dummy);
+	jump_to_P2();
 
 	for (v = start; v < end; v+=L1_CACHE_BYTES) {
 		p = __pa(v);
@@ -110,7 +89,7 @@
 			     : "m" (__m(v)));
 #endif
 	}
-	back_to_p1(__dummy);
+	back_to_P1();
 	restore_flags(flags);
 }
 
@@ -124,12 +103,12 @@
    the cache line. */
 void cache_purge_area(unsigned long start, unsigned long end)
 {
-	unsigned long flags, __dummy;
+	unsigned long flags;
 	unsigned long addr, data, v, p, j;
 
 	start &= ~(L1_CACHE_BYTES-1);
 	save_and_cli(flags);
-	jump_to_p2(__dummy);
+	jump_to_P2();
 
 	for (v = start; v < end; v+=L1_CACHE_BYTES) {
 		p = __pa(v);
@@ -150,19 +129,19 @@
 			     : "m" (__m(v)));
 #endif
 	}
-	back_to_p1(__dummy);
+	back_to_P1();
 	restore_flags(flags);
 }
 
 /* write back the dirty cache, but not invalidate the cache */
 void cache_wback_area(unsigned long start, unsigned long end)
 {
-	unsigned long flags, __dummy;
+	unsigned long flags;
 	unsigned long v;
 
 	start &= ~(L1_CACHE_BYTES-1);
 	save_and_cli(flags);
-	jump_to_p2(__dummy);
+	jump_to_P2();
 
 	for (v = start; v < end; v+=L1_CACHE_BYTES) {
 #if CACHE_IC_ADDRESS_ARRAY == CACHE_OC_ADDRESS_ARRAY
@@ -187,7 +166,7 @@
 			     : "m" (__m(v)));
 #endif
 	}
-	back_to_p1(__dummy);
+	back_to_P1();
 	restore_flags(flags);
 }
 
@@ -199,11 +178,11 @@
  */
 static void cache_wback_all(void)
 {
-	unsigned long flags, __dummy;
+	unsigned long flags;
 	unsigned long addr, data, i, j;
 
 	save_and_cli(flags);
-	jump_to_p2(__dummy);
+	jump_to_P2();
 
 	for (i=0; i<CACHE_OC_NUM_ENTRIES; i++) {
 		for (j=0; j<CACHE_OC_NUM_WAYS; j++) {
@@ -217,7 +196,7 @@
 		}
 	}
 
-	back_to_p1(__dummy);
+	back_to_P1();
 	restore_flags(flags);
 }
 
@@ -225,9 +204,9 @@
 detect_cpu_and_cache_system(void)
 {
 #if defined(__sh3__)
-	unsigned long __dummy, addr0, addr1, data0, data1, data2, data3;
+	unsigned long addr0, addr1, data0, data1, data2, data3;
 
-	jump_to_p2(__dummy);
+	jump_to_P2();
 	/* Check if the entry shadows or not.
 	 * When shadowed, it's 128-entry system.
 	 * Otherwise, it's 256-entry system.
@@ -245,7 +224,7 @@
 	/* Invaliate them, in case the cache has been enabled already. */
 	ctrl_outl(data0&~0x00000001,addr0);
 	ctrl_outl(data2&~0x00000001,addr1);
-	back_to_p1(__dummy);
+	back_to_P1();
 
 	if (data0 == data1 && data2 == data3) {	/* Shadow */
 		cache_system_info.way_shift = 11;
@@ -265,7 +244,7 @@
 
 void __init cache_init(void)
 {
-	unsigned long __dummy, ccr;
+	unsigned long ccr;
 
 	detect_cpu_and_cache_system();
 
@@ -277,19 +256,19 @@
 		   we only need to flush the half of the caches. */
 		cache_wback_all();
 
-	jump_to_p2(__dummy);
+	jump_to_P2();
 	ctrl_outl(CCR_CACHE_INIT, CCR);
-	back_to_p1(__dummy);
+	back_to_P1();
 }
 
 #if defined(__SH4__)
 void flush_icache_page(struct vm_area_struct *vma, struct page *pg)
 {
-	unsigned long flags, __dummy;
+	unsigned long flags;
 	unsigned long addr, data, v;
 
 	save_and_cli(flags);
-	jump_to_p2(__dummy);
+	jump_to_P2();
 
 	v = page_address(pg);
 
@@ -303,18 +282,18 @@
 	data = (v&0xfffffc00); /* Valid=0 */
 	ctrl_outl(data,addr);
 
-	back_to_p1(__dummy);
+	back_to_P1();
 	restore_flags(flags);
 }
 
 void flush_icache_range(unsigned long start, unsigned long end)
 {
-	unsigned long flags, __dummy;
+	unsigned long flags;
 	unsigned long addr, data, v;
 
 	start &= ~(L1_CACHE_BYTES-1);
 	save_and_cli(flags);
-	jump_to_p2(__dummy);
+	jump_to_P2();
 
 	for (v = start; v < end; v+=L1_CACHE_BYTES) {
 		/* Write back O Cache */
@@ -327,22 +306,22 @@
 		data = (v&0xfffffc00); /* Valid=0 */
 		ctrl_outl(data,addr);
 	}
-	back_to_p1(__dummy);
+	back_to_P1();
 	restore_flags(flags);
 }
 
 void flush_cache_all(void)
 {
-	unsigned long flags,__dummy;
+	unsigned long flags;
 
 	/* Write back Operand Cache */
 	cache_wback_all ();
 
 	/* Then, invalidate Instruction Cache and Operand Cache */
 	save_and_cli(flags);
-	jump_to_p2(__dummy);
+	jump_to_P2();
 	ctrl_outl(CCR_CACHE_INIT, CCR);
-	back_to_p1(__dummy);
+	back_to_P1();
 	restore_flags(flags);
 }
 
@@ -356,12 +335,12 @@
 void flush_cache_range(struct mm_struct *mm, unsigned long start,
 		       unsigned long end)
 {
-	unsigned long flags, __dummy;
+	unsigned long flags;
 	unsigned long addr, data, v;
 
 	start &= ~(L1_CACHE_BYTES-1);
 	save_and_cli(flags);
-	jump_to_p2(__dummy);
+	jump_to_P2();
 
 	for (v = start; v < end; v+=L1_CACHE_BYTES) {
 		addr = CACHE_IC_ADDRESS_ARRAY |
@@ -372,7 +351,7 @@
 			(v&CACHE_OC_ENTRY_MASK) | 0x8 /* A-bit */;
 		ctrl_outl(data,addr);
 	}
-	back_to_p1(__dummy);
+	back_to_P1();
 	restore_flags(flags);
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c
--- v2.3.99-pre3/linux/arch/sh/mm/fault.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/mm/fault.c	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.12 2000/03/01 11:15:27 gniibe Exp $
+/* $Id: fault.c,v 1.13 2000/03/07 12:05:24 gniibe Exp $
  *
  *  linux/arch/sh/mm/fault.c
  *  Copyright (C) 1999  Niibe Yutaka
@@ -283,9 +283,6 @@
 {
 	unsigned long addr, data, asid;
 	unsigned long saved_asid = MMU_NO_ASID;
-#if defined(__SH4__)
-	int i;
-#endif
 
 	if (mm->context == NO_CONTEXT)
 		return;
@@ -305,19 +302,25 @@
 	data = (page & 0xfffe0000) | asid; /* VALID bit is off */
 	ctrl_outl(data, addr);
 #elif defined(__SH4__)
+	jump_to_P2();
 	addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
 	data = page | asid; /* VALID bit is off */
 	ctrl_outl(data, addr);
-
-	for (i=0; i<4; i++) {
-		addr = MMU_ITLB_ADDRESS_ARRAY | (i<<8);
-		data = ctrl_inl(addr);
-		data &= ~0x300;
-		if (data == (page | asid)) {
-			ctrl_outl(data, addr);
-			break;
+#if 0 	/* Not need when using ASSOC. ??? */
+	{
+		int i;
+		for (i=0; i<4; i++) {
+			addr = MMU_ITLB_ADDRESS_ARRAY | (i<<8);
+			data = ctrl_inl(addr);
+			data &= ~0x300;
+			if (data == (page | asid)) {
+				ctrl_outl(data, addr);
+				break;
+			}
 		}
 	}
+#endif
+	back_to_P1();
 #endif
 	if (saved_asid != MMU_NO_ASID)
 		set_asid(saved_asid);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c
--- v2.3.99-pre3/linux/arch/sh/mm/init.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/mm/init.c	Mon Mar 27 10:24:56 2000
@@ -224,7 +224,7 @@
 			zones_size[ZONE_DMA] = max_dma - start_pfn;
 			zones_size[ZONE_NORMAL] = low - max_dma;
 		}
-		free_area_init_node(0, 0, zones_size, __MEMORY_START);
+		free_area_init_node(0, 0, zones_size, __MEMORY_START, 0);
  	}
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.3.99-pre3/linux/arch/sparc/config.in	Mon Mar 27 08:08:22 2000
+++ linux/arch/sparc/config.in	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.90 2000/03/17 05:18:02 anton Exp $
+# $Id: config.in,v 1.92 2000/03/29 11:56:48 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -20,6 +20,8 @@
 bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP
 
 # Global things across all Sun machines.
+define_bool CONFIG_ISA n
+define_bool CONFIG_PCMCIA n
 define_bool CONFIG_SBUS y
 define_bool CONFIG_SBUSCHAR y
 define_bool CONFIG_BUSMOUSE y
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.3.99-pre3/linux/arch/sparc/defconfig	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc/defconfig	Mon Mar 27 09:38:47 2000
@@ -14,6 +14,8 @@
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 # CONFIG_SMP is not set
+# CONFIG_ISA is not set
+# CONFIG_PCMCIA is not set
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
 CONFIG_BUSMOUSE=y
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v2.3.99-pre3/linux/arch/sparc/kernel/Makefile	Wed Dec 29 13:13:13 1999
+++ linux/arch/sparc/kernel/Makefile	Thu Mar 30 16:56:04 2000
@@ -8,10 +8,10 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+	$(CPP) $(AFLAGS) -ansi $< -o $*.s
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+	$(CC) $(AFLAGS) -ansi -c $< -o $*.o
 
 all: kernel.o head.o init_task.o
 
@@ -47,7 +47,7 @@
 endif
 
 head.o: head.S
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
+	$(CC) $(AFLAGS) -ansi -c $*.S -o $*.o
 
 check_asm: dummy
 	@echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
@@ -62,7 +62,7 @@
 	@echo "#undef __SMP__" >> tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CC) $(CPPFLAGS) -E tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
 	@echo "#include <linux/config.h>" >> check_asm.c
 	@echo "#undef __SMP__" >> check_asm.c
@@ -87,7 +87,7 @@
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#define CONFIG_SMP 1" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CC) $(CPPFLAGS) -D__SMP__ -E tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -D__SMP__ tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
 	@echo "#include <linux/config.h>" >> check_asm.c
 	@echo "#undef CONFIG_SMP" >> check_asm.c
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v2.3.99-pre3/linux/arch/sparc/kernel/ioport.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc/kernel/ioport.c	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.36 2000/03/16 08:22:53 anton Exp $
+/* $Id: ioport.c,v 1.37 2000/03/28 06:38:19 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -581,6 +581,7 @@
 {
 	if (direction == PCI_DMA_NONE)
 		BUG();
+	/* IIep is write-through, not flushing. */
 	return virt_to_bus(ptr);
 }
 
@@ -591,11 +592,15 @@
  * After this call, reads by the cpu to the buffer are guarenteed to see
  * whatever the device wrote there.
  */
-void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
+void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size,
+    int direction)
 {
 	if (direction == PCI_DMA_NONE)
 		BUG();
-	/* Nothing to do... */
+	if (direction != PCI_DMA_TODEVICE) {
+		mmu_inval_dma_area((unsigned long)bus_to_virt(ba),
+		    (size + PAGE_SIZE-1) & PAGE_MASK);
+	}
 }
 
 /* Map a set of buffers described by scatterlist in streaming
@@ -613,13 +618,14 @@
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
+int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
+    int direction)
 {
 	int n;
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
-
+	/* IIep is write-through, not flushing. */
 	for (n = 0; n < nents; n++) {
 		sg->dvma_address = virt_to_bus(sg->address);
 		sg->dvma_length = sg->length;
@@ -632,15 +638,24 @@
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction)
+void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
+    int direction)
 {
+	int n;
+
 	if (direction == PCI_DMA_NONE)
 		BUG();
-	/* Nothing to do... */
+	if (direction != PCI_DMA_TODEVICE) {
+		for (n = 0; n < nents; n++) {
+			mmu_inval_dma_area((unsigned long)sg->address,
+			    (sg->length + PAGE_SIZE-1) & PAGE_MASK);
+			sg++;
+		}
+	}
 }
 
 /* Make physical memory consistent for a single
- * streaming mode DMA translation after a transfer.
+ * streaming mode DMA translation before or after a transfer.
  *
  * If you perform a pci_map_single() but wish to interrogate the
  * buffer using the cpu, yet do not wish to teardown the PCI dma
@@ -652,8 +667,10 @@
 {
 	if (direction == PCI_DMA_NONE)
 		BUG();
-	mmu_inval_dma_area((unsigned long)bus_to_virt(ba),
-	    (size + PAGE_SIZE-1) & PAGE_MASK);
+	if (direction != PCI_DMA_TODEVICE) {
+		mmu_inval_dma_area((unsigned long)bus_to_virt(ba),
+		    (size + PAGE_SIZE-1) & PAGE_MASK);
+	}
 }
 
 /* Make physical memory consistent for a set of streaming
@@ -664,13 +681,16 @@
  */
 void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
+	int n;
+
 	if (direction == PCI_DMA_NONE)
 		BUG();
-	while (nents) {
-		--nents;
-		mmu_inval_dma_area((unsigned long)sg->address,
-		    (sg->dvma_length + PAGE_SIZE-1) & PAGE_MASK);
-		sg++;
+	if (direction != PCI_DMA_TODEVICE) {
+		for (n = 0; n < nents; n++) {
+			mmu_inval_dma_area((unsigned long)sg->address,
+			    (sg->length + PAGE_SIZE-1) & PAGE_MASK);
+			sg++;
+		}
 	}
 }
 #endif CONFIG_PCI
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.3.99-pre3/linux/arch/sparc/kernel/setup.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc/kernel/setup.c	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.116 2000/03/15 23:26:22 anton Exp $
+/*  $Id: setup.c,v 1.117 2000/03/27 12:14:54 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -45,6 +45,8 @@
 #include <asm/hardirq.h>
 #include <asm/machines.h>
 
+#undef PROM_DEBUG_CONSOLE
+
 struct screen_info screen_info = {
 	0, 0,			/* orig-x, orig-y */
 	0,			/* unused */
@@ -282,6 +284,7 @@
 
 struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
 
+#ifdef PROM_DEBUG_CONSOLE
 static void prom_cons_write(struct console *con, const char *str, unsigned count)
 {
 	while (count--)
@@ -291,6 +294,7 @@
 static struct console prom_console = {
 	"PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0
 };
+#endif
 
 extern void paging_init(void);
 
@@ -345,6 +349,9 @@
 		printk("UNKNOWN!\n");
 		break;
 	};
+#ifdef PROM_DEBUG_CONSOLE
+	register_console(&prom_console);
+#endif
 
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v2.3.99-pre3/linux/arch/sparc/kernel/signal.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/signal.c	Sun Apr  2 15:53:27 2000
@@ -1096,7 +1096,9 @@
 		if (map->vm_file != NULL) {
 			dev = map->vm_file->f_dentry->d_inode->i_dev;
 			ino = map->vm_file->f_dentry->d_inode->i_ino;
-			line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+			line = d_path(map->vm_file->f_dentry,
+				      map->vm_file->f_vfsmnt,
+				      buffer, PAGE_SIZE);
 		}
 		printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
 			      kdevname(dev), ino);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.99-pre3/linux/arch/sparc/kernel/sys_sunos.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc/kernel/sys_sunos.c	Sun Apr  2 15:53:28 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.117 2000/03/15 02:43:32 davem Exp $
+/* $Id: sys_sunos.c,v 1.118 2000/03/26 11:28:56 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -91,7 +91,7 @@
 	 * of /dev/zero, transform it into an anonymous mapping.
 	 * SunOS is so stupid some times... hmph!
 	 */
-	if(file->f_dentry && file->f_dentry->d_inode) {
+	if (file) {
 		if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
 		   MINOR(file->f_dentry->d_inode->i_rdev) == 5) {
 			flags |= MAP_ANONYMOUS;
@@ -633,10 +633,9 @@
 };
 
 
-extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
 extern dev_t get_unnamed_dev(void);
 extern void put_unnamed_dev(dev_t);
-extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
+extern asmlinkage long do_sys_mount(char *, char *, char *, int, void *);
 extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
 extern asmlinkage int sys_socket(int family, int type, int protocol);
 extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
@@ -660,8 +659,6 @@
 	file = fget(fd);
 	if (!file)
 		goto out;
-	if (!file->f_dentry || !(inode = file->f_dentry->d_inode))
-		goto out_putf;
 
 	socket = &inode->u.socket_i;
 	local.sin_family = AF_INET;
@@ -702,12 +699,12 @@
 	return def_value;
 }
 
-asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
+static int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
 {
 	int  server_fd;
 	char *the_name;
 	struct nfs_mount_data linux_nfs_mount;
-	struct sunos_nfs_mount_args *sunos_mount = data;
+	struct sunos_nfs_mount_args sunos_mount;
 
 	/* Ok, here comes the fun part: Linux's nfs mount needs a
 	 * socket connection to the server, but SunOS mount does not
@@ -715,33 +712,42 @@
 	 * address to create a socket and bind it to a reserved
 	 * port on this system
 	 */
+	if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount))
+		return -EFAULT;
+
 	server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 	if (server_fd < 0)
 		return -ENXIO;
 
-	if (!sunos_nfs_get_server_fd (server_fd, sunos_mount->addr)){
+	if (copy_from_user(&linux_nfs_mount.addr,sunos_mount.addr,
+				sizeof(*sunos_mount.addr)) ||
+	    copy_from_user(&linux_nfs_mount.root,sunos_mount.fh,
+				sizeof(*sunos_mount.fh))) {
+		sys_close (server_fd);
+		return -EFAULT;
+	}
+
+	if (!sunos_nfs_get_server_fd (server_fd, &linux_nfs_mount.addr)){
 		sys_close (server_fd);
 		return -ENXIO;
 	}
 
 	/* Now, bind it to a locally reserved port */
 	linux_nfs_mount.version  = NFS_MOUNT_VERSION;
-	linux_nfs_mount.flags    = sunos_mount->flags;
-	linux_nfs_mount.addr     = *sunos_mount->addr;
-	linux_nfs_mount.root     = *sunos_mount->fh;
+	linux_nfs_mount.flags    = sunos_mount.flags;
 	linux_nfs_mount.fd       = server_fd;
 	
-	linux_nfs_mount.rsize    = get_default (sunos_mount->rsize, 8192);
-	linux_nfs_mount.wsize    = get_default (sunos_mount->wsize, 8192);
-	linux_nfs_mount.timeo    = get_default (sunos_mount->timeo, 10);
-	linux_nfs_mount.retrans  = sunos_mount->retrans;
+	linux_nfs_mount.rsize    = get_default (sunos_mount.rsize, 8192);
+	linux_nfs_mount.wsize    = get_default (sunos_mount.wsize, 8192);
+	linux_nfs_mount.timeo    = get_default (sunos_mount.timeo, 10);
+	linux_nfs_mount.retrans  = sunos_mount.retrans;
 	
-	linux_nfs_mount.acregmin = sunos_mount->acregmin;
-	linux_nfs_mount.acregmax = sunos_mount->acregmax;
-	linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
-	linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
+	linux_nfs_mount.acregmin = sunos_mount.acregmin;
+	linux_nfs_mount.acregmax = sunos_mount.acregmax;
+	linux_nfs_mount.acdirmin = sunos_mount.acdirmin;
+	linux_nfs_mount.acdirmax = sunos_mount.acdirmax;
 
-	the_name = getname(sunos_mount->hostname);
+	the_name = getname(sunos_mount.hostname);
 	if(IS_ERR(the_name))
 		return PTR_ERR(the_name);
 
@@ -749,7 +755,7 @@
 	linux_nfs_mount.hostname [255] = 0;
 	putname (the_name);
 	
-	return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
+	return do_sys_mount ("", dir_name, "nfs", linux_flags, &linux_nfs_mount);
 }
 
 asmlinkage int
@@ -758,6 +764,7 @@
 	int linux_flags = MS_MGC_MSK; /* new semantics */
 	int ret = -EINVAL;
 	char *dev_fname = 0;
+	char *dir_page, *type_page;
 
 	if (!capable (CAP_SYS_ADMIN))
 		return -EPERM;
@@ -777,24 +784,44 @@
 		linux_flags |= MS_RDONLY;
 	if(flags & SMNT_NOSUID)
 		linux_flags |= MS_NOSUID;
-	if(strcmp(type, "ext2") == 0) {
-		dev_fname = (char *) data;
-	} else if(strcmp(type, "iso9660") == 0) {
-		dev_fname = (char *) data;
-	} else if(strcmp(type, "minix") == 0) {
-		dev_fname = (char *) data;
-	} else if(strcmp(type, "nfs") == 0) {
-		ret = sunos_nfs_mount (dir, flags, data);
-		goto out;
-        } else if(strcmp(type, "ufs") == 0) {
+
+	dir_page = getname(dir);
+	ret = PTR_ERR(dir_page);
+	if (IS_ERR(dir_page))
+		goto out;
+
+	type_page = getname(type);
+	ret = PTR_ERR(type_page);
+	if (IS_ERR(type_page))
+		goto out1;
+
+	if(strcmp(type_page, "ext2") == 0) {
+		dev_fname = getname(data);
+	} else if(strcmp(type_page, "iso9660") == 0) {
+		dev_fname = getname(data);
+	} else if(strcmp(type_page, "minix") == 0) {
+		dev_fname = getname(data);
+	} else if(strcmp(type_page, "nfs") == 0) {
+		ret = sunos_nfs_mount (dir_page, flags, data);
+		goto out2
+        } else if(strcmp(type_page, "ufs") == 0) {
 		printk("Warning: UFS filesystem mounts unsupported.\n");
 		ret = -ENODEV;
-		goto out;
-	} else if(strcmp(type, "proc")) {
+		goto out2
+	} else if(strcmp(type_page, "proc")) {
 		ret = -ENODEV;
-		goto out;
+		goto out2
 	}
-	ret = sys_mount(dev_fname, dir, type, linux_flags, NULL);
+	ret = PTR_ERR(dev_fname);
+	if (IS_ERR(dev_fname))
+		goto out2;
+	ret = do_sys_mount(dev_fname, dir_page, type_page, linux_flags, NULL);
+	if (dev_fname)
+		putname(dev_fname);
+out2:
+	putname(type_page);
+out1:
+	putname(dir_page);
 out:
 	unlock_kernel();
 	return ret;
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile
--- v2.3.99-pre3/linux/arch/sparc/lib/Makefile	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc/lib/Makefile	Thu Mar 30 16:56:04 2000
@@ -13,10 +13,10 @@
 	sync
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 $< -o $*.s
+	$(CPP) $(AFLAGS) -ansi -DST_DIV0=0x2 $< -o $*.s
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 -c $< -o $*.o
+	$(CC) $(AFLAGS) -ansi -DST_DIV0=0x2 -c $< -o $*.o
 
 dep:
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/math-emu/Makefile linux/arch/sparc/math-emu/Makefile
--- v2.3.99-pre3/linux/arch/sparc/math-emu/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/sparc/math-emu/Makefile	Thu Mar 30 16:56:04 2000
@@ -11,10 +11,10 @@
 O_OBJS   := math.o ashldi3.o
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+	$(CPP) $(AFLAGS) -ansi $< -o $*.s
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+	$(CC) $(AFLAGS) -ansi -c $< -o $*.o
 
 CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile
--- v2.3.99-pre3/linux/arch/sparc/mm/Makefile	Tue Feb  1 01:35:43 2000
+++ linux/arch/sparc/mm/Makefile	Thu Mar 30 16:56:04 2000
@@ -7,6 +7,9 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
+.S.o:
+	$(CC) $(AFLAGS) -ansi -c -o $*.o $<
+
 O_TARGET := mm.o
 O_OBJS   := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
 ifeq ($(CONFIG_SUN4),y)
@@ -21,15 +24,3 @@
 endif
 
 include $(TOPDIR)/Rules.make
-
-hypersparc.o: hypersparc.S
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o hypersparc.o hypersparc.S
-
-viking.o: viking.S
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o viking.o viking.S
-
-tsunami.o: tsunami.S
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o tsunami.o tsunami.S
-
-swift.o: swift.S
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o swift.o swift.S
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.3.99-pre3/linux/arch/sparc/mm/sun4c.c	Sun Feb 20 21:12:38 2000
+++ linux/arch/sparc/mm/sun4c.c	Sun Apr  2 15:53:28 2000
@@ -2408,20 +2408,16 @@
  */
 static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
-	struct dentry *dentry = NULL;
-	struct inode *inode = NULL;
 	pgd_t *pgdp;
 	pte_t *ptep;
 
-	if (vma->vm_file)
-		dentry = vma->vm_file->f_dentry;
-	if(dentry)
-		inode = dentry->d_inode;
-	if(inode) {
-		struct address_space *mapping = inode->i_mapping;
+	if (vma->vm_file) {
+		struct address_space *mapping;
 		unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
 		struct vm_area_struct *vmaring;
 		int alias_found = 0;
+
+		mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
 		spin_lock(&mapping->i_shared_lock);
 		vmaring = mapping->i_mmap; 
 		do {
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.99-pre3/linux/arch/sparc64/config.in	Mon Mar 27 08:08:22 2000
+++ linux/arch/sparc64/config.in	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.105 2000/03/24 00:34:11 davem Exp $
+# $Id: config.in,v 1.107 2000/03/29 11:56:51 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -18,6 +18,8 @@
 bool 'Symmetric multi-processing support' CONFIG_SMP
 
 # Global things across all Sun machines.
+define_bool CONFIG_ISA n
+define_bool CONFIG_PCMCIA n
 define_bool CONFIG_SBUS y
 define_bool CONFIG_SBUSCHAR y
 define_bool CONFIG_BUSMOUSE y
@@ -29,7 +31,6 @@
 define_bool CONFIG_SUN_CONSOLE y
 define_bool CONFIG_SUN_AUXIO y
 define_bool CONFIG_SUN_IO y
-define_bool CONFIG_ISA n
 bool 'PCI support' CONFIG_PCI
 source drivers/pci/Config.in
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.99-pre3/linux/arch/sparc64/defconfig	Mon Mar 27 08:08:22 2000
+++ linux/arch/sparc64/defconfig	Mon Mar 27 10:35:56 2000
@@ -13,6 +13,8 @@
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 # CONFIG_SMP is not set
+# CONFIG_ISA is not set
+# CONFIG_PCMCIA is not set
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
 CONFIG_BUSMOUSE=y
@@ -24,7 +26,6 @@
 CONFIG_SUN_CONSOLE=y
 CONFIG_SUN_AUXIO=y
 CONFIG_SUN_IO=y
-# CONFIG_ISA is not set
 CONFIG_PCI=y
 CONFIG_PCI_NAMES=y
 CONFIG_SUN_OPENPROMFS=m
@@ -225,6 +226,7 @@
 # CONFIG_BLK_DEV_AEC6210 is not set
 # CONFIG_AEC6210_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
 # CONFIG_AMD7409_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- v2.3.99-pre3/linux/arch/sparc64/kernel/Makefile	Mon Mar 27 08:08:22 2000
+++ linux/arch/sparc64/kernel/Makefile	Thu Mar 30 16:56:04 2000
@@ -8,10 +8,10 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+	$(CPP) $(AFLAGS) -ansi $< -o $*.s
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+	$(CC) $(AFLAGS) -ansi -c $< -o $*.o
 
 all: kernel.o head.o init_task.o
 
@@ -54,7 +54,7 @@
 
 head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \
 	etrap.S rtrap.S winfixup.S entry.S
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
+	$(CC) $(AFLAGS) -ansi -c $*.S -o $*.o
 
 #
 # This is just to get the dependencies...
@@ -84,7 +84,7 @@
 	@echo "#undef __SMP__" >> tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CC) $(CPPFLAGS) -E tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
 	@echo "#include <linux/config.h>" >> check_asm.c
 	@echo "#undef __SMP__" >> check_asm.c
@@ -113,7 +113,7 @@
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#define CONFIG_SMP 1" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CC) $(CPPFLAGS) -D__SMP__ -E tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -D__SMP__ tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
 	@echo "#include <linux/config.h>" >> check_asm.c
 	@echo "#undef CONFIG_SMP" >> check_asm.c
@@ -138,7 +138,7 @@
 	@rm -f check_asm check_asm.c
 	@echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
 	@echo "#include <linux/sched.h>" > tmp.c
-	$(CC) $(CPPFLAGS) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -D__SMP__ -DSPIN_LOCK_DEBUG tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
 	@echo "#include <linux/config.h>" >> check_asm.c
 	@echo "#undef CONFIG_SMP" >> check_asm.c
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/dtlb_base.S linux/arch/sparc64/kernel/dtlb_base.S
--- v2.3.99-pre3/linux/arch/sparc64/kernel/dtlb_base.S	Tue Feb  1 01:35:43 2000
+++ linux/arch/sparc64/kernel/dtlb_base.S	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: dtlb_base.S,v 1.5 2000/01/31 04:59:12 davem Exp $
+/* $Id: dtlb_base.S,v 1.7 2000/03/26 09:13:48 davem Exp $
  * dtlb_base.S:	Front end to DTLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
@@ -56,19 +56,19 @@
 	be,pn		%xcc, 3f			! Yep, special processing
 	 srax		%g4, VPTE_SHIFT, %g6		! Create VPTE offset
 	ldxa		[%g3 + %g6] ASI_S, %g5		! Load VPTE
-1:	brlz,pt		%g5, 2f				! Valid, load into TLB
+1:	brlz,pt		%g5, 9f				! Valid, load into TLB
 	 and		%g5, (_PAGE_PRESENT|_PAGE_READ), %g4	! Mask readable bits
 	ba,a,pt		%xcc, 4f			! Invalid, branch out
 
 /* DTLB ** ICACHE line 2: Quick kernel TLB misses	*/
-3:	brgez,a,pn	%g4, 1b				! Kernel virtual map?
-	 ldxa		[%g3 + %g6] ASI_N, %g5		! Yep, load k-vpte
-	srlx		%g4, 40, %g5			! Else compute phys-kpte
-	andcc		%g5, 1, %g0			! I/O area?
-	be,pt		%xcc, 2f			! Nope, go and load TLB
+3:	brlz,pt		%g4, 9f				! Kernel virtual map?
 	 xor		%g2, %g4, %g5			! Finish bit twiddles
-	ba,pt		%xcc, 2f			! Yes, I/O space, back back
-	 xor		%g5, (KERN_IOBITS), %g5		! After set E, clear CP/CV
+	ldxa		[%g3 + %g6] ASI_N, %g5		! Yep, load k-vpte
+	ba,pt		%xcc, 1b			! Continue tlb reload
+	 nop
+9:	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Reload TLB
+	retry						! Trap return
+	nop
 
 /* DTLB ** ICACHE line 3: winfixups+real_faults		*/
 4:	cmp		%g4, (_PAGE_PRESENT|_PAGE_READ)	! Readable page?
@@ -81,14 +81,14 @@
 	mov		TLB_TAG_ACCESS, %g4		! Prepare for fault processing
 
 /* DTLB ** ICACHE line 4: padding		*/
+	ldxa		[%g4] ASI_DMMU, %g5		! Load faulting VA page
 	be,pt		%xcc, sparc64_realfault_common	! Jump to normal fault handling
-	 ldxa		[%g4] ASI_DMMU, %g5		! And load faulting VA page
+	 mov		FAULT_CODE_DTLB, %g4		! It was read from DTLB
 	ba,a,pt		%xcc, winfix_trampoline		! Call window fixup code
 5:	or		%g5, _PAGE_ACCESSED, %g5	! Indicate reference
 	or		%g5, %g4, %g5			! Set valid
 	stxa		%g5, [%g3 + %g6] ASI_S		! Update PTE table (cant trap)
-2:	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Reload TLB
-	retry						! Trap return
+	ba,a,pt		%xcc, 9b			! Complete tlb miss
 
 #undef TAG_CONTEXT_BITS
 #undef VPTE_SHIFT
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/dtlb_prot.S linux/arch/sparc64/kernel/dtlb_prot.S
--- v2.3.99-pre3/linux/arch/sparc64/kernel/dtlb_prot.S	Tue Feb  1 01:35:43 2000
+++ linux/arch/sparc64/kernel/dtlb_prot.S	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.19 2000/01/31 04:59:12 davem Exp $
+/* $Id: dtlb_prot.S,v 1.20 2000/03/26 09:13:48 davem Exp $
  * dtlb_prot.S: DTLB protection trap strategy.
  *              This is included directly into the trap table.
  *
@@ -40,15 +40,15 @@
 /* PROT ** ICACHE line 3: Real user faults		*/
 1:	rdpr		%pstate, %g5			! Move into alternate globals
 	wrpr		%g5, PSTATE_AG|PSTATE_MG, %pstate
-	rdpr		%tl, %g4			! Need to do a winfixup?
-	cmp		%g4, 1				! Trap level >1?
+	rdpr		%tl, %g1			! Need to do a winfixup?
+	cmp		%g1, 1				! Trap level >1?
 	mov		TLB_TAG_ACCESS, %g4		! Prepare reload of vaddr
 	bgu,pn		%xcc, winfix_trampoline		! Yes, perform winfixup
 	 ldxa		[%g4] ASI_DMMU, %g5		! Put tagaccess in %g5
 	ba,pt		%xcc, sparc64_realfault_common	! Nope, normal fault
 
 /* PROT ** ICACHE line 4: More real fault processing */
-	 mov		1, %g4				! Indicate this was a write
+	 mov		FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4
 	nop
 	nop
 	nop
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/ebus.c	Wed Dec 29 13:13:14 1999
+++ linux/arch/sparc64/kernel/ebus.c	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.46 1999/11/19 05:52:48 davem Exp $
+/* $Id: ebus.c,v 1.47 2000/03/25 05:18:10 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -278,7 +278,6 @@
 	struct linux_ebus *ebus;
 	struct pci_dev *pdev;
 	struct pcidev_cookie *cookie;
-	unsigned short pci_command;
 	int nd, ebusnd;
 	int num_ebus = 0;
 
@@ -327,17 +326,6 @@
 		ebus->prom_node = ebusnd;
 		ebus->self = pdev;
 		ebus->parent = pbm = cookie->pbm;
-
-		/* Enable BUS Master. */
-		pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-		pci_command |= PCI_COMMAND_MASTER;
-		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-
-		/* Set reasonable cache line size and latency timer values. */
-		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
-
-		/* NOTE: Cache line size is in 32-bit word units. */
-		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64/sizeof(u32));
 
 		ebus_ranges_init(ebus);
 		ebus_intmap_init(ebus);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.3.99-pre3/linux/arch/sparc64/kernel/entry.S	Tue Mar  7 14:32:25 2000
+++ linux/arch/sparc64/kernel/entry.S	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.113 2000/03/06 22:33:42 davem Exp $
+/* $Id: entry.S,v 1.115 2000/03/29 09:55:30 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -998,12 +998,12 @@
 
 	mov		%i5, %o5				! IEU1
 	srl		%i2, 0, %o2				! IEU0	Group
-	mov		%i0, %l5				! IEU1
-	andcc		%l0, 0x20, %g0				! IEU1	Group
+	andcc		%l0, 0x20, %g0				! IEU0	Group
 	bne,pn		%icc, linux_syscall_trace32		! CTI
-	 srl		%i3, 0, %o3				! IEU0
+	 mov		%i0, %l5				! IEU1
 	call		%l7					! CTI	Group brk forced
-	 add		%o7, 3f-.-4, %o7			! IEU0
+	 srl		%i3, 0, %o3				! IEU0
+	ba,a,pt		%xcc, 3f
 
 	/* Linux native and SunOS system calls enter here... */
 	.align	32
@@ -1032,30 +1032,31 @@
 	 mov		%i0, %l5				! IEU0
 2:	call		%l7					! CTI	Group brk forced
 	 mov		%i5, %o5				! IEU0
+	nop
+
 3:	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
 ret_sys_call:
 #ifdef SYSCALL_TRACING
 	call		syscall_trace_exit
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
 #endif
-	ldx		[%curptr + AOFF_task_flags], %l6
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
 	sra		%o0, 0, %o0
 	mov		%ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
-	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
 	cmp		%o0, -ENOIOCTLCMD
 	sllx		%g2, 32, %g2
 	bgeu,pn		%xcc, 1f
-	 andcc		%l6, 0x20, %l6	
 
-	/* System call success, clear Carry condition code. */
-	andn		%g3, %g2, %g3
+	 andcc		%l0, 0x20, %l6	
+	andn		%g3, %g2, %g3		/* System call success, clear Carry condition code. */
 	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]	
 	bne,pn		%icc, linux_syscall_trace2
-	 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
-	add		%l1, 0x4, %l2				         !npc = npc+4
+	 add		%l1, 0x4, %l2				         ! npc = npc+4
 	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
-	b,pt		%xcc, rtrap_clr_l6
+	ba,pt		%xcc, rtrap_clr_l6
 	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+
 1:
 	/* System call failure, set Carry condition code.
 	 * Also, get abs(errno) to return to the process.
@@ -1066,15 +1067,14 @@
 	mov		1, %l6
 	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
 	bne,pn		%icc, linux_syscall_trace2
-	 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
-	add		%l1, 0x4, %l2				         !npc = npc+4
-
+	 add		%l1, 0x4, %l2				         !npc = npc+4
 	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+
 	b,pt		%xcc, rtrap
 	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
 linux_syscall_trace2:
 	call		syscall_trace
-	 add		%l1, 0x4, %l2			/* npc = npc+4 */
+	 nop
 	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
 	ba,pt		%xcc, rtrap
 	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
@@ -1082,6 +1082,9 @@
 	.align		32
 	.globl		__flushw_user
 __flushw_user:
+	rdpr		%otherwin, %g1
+	brz,pn		%g1, 2f
+	 clr		%g2
 1:	save		%sp, -128, %sp
 	rdpr		%otherwin, %g1
 	brnz,pt		%g1, 1b
@@ -1090,4 +1093,4 @@
 	brnz,pt		%g2, 1b
 	 restore	%g0, %g0, %g0
 2:	retl
-	 mov		%g3, %o7
+	 nop
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S
--- v2.3.99-pre3/linux/arch/sparc64/kernel/etrap.S	Mon Aug  2 22:07:16 1999
+++ linux/arch/sparc64/kernel/etrap.S	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.42 1999/07/30 09:35:18 davem Exp $
+/* $Id: etrap.S,v 1.43 2000/03/29 09:55:30 davem Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
  * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -13,6 +13,8 @@
 #include <asm/head.h>
 
 #define		TASK_REGOFF		((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ)
+#define		ETRAP_PSTATE1		(PSTATE_RMO | PSTATE_PRIV)
+#define		ETRAP_PSTATE2		(PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE)
 
 /*
  * On entry, %g7 is return address - 0x4.
@@ -20,148 +22,167 @@
  */
 
 		.text		
-		.align			32
-		.globl			etrap, etrap_irq, etraptl1
-		.globl			scetrap
-
-etrap:		rdpr			%pil, %g2						! Single 	Group
-etrap_irq:	rdpr			%tstate, %g1						! Single 	Group
-		sllx			%g2, 20, %g3						! IEU0		Group
-		andcc			%g1, TSTATE_PRIV, %g0					! IEU1
-		or			%g1, %g3, %g1						! IEU0		Group
-		bne,a,pn		%xcc, 1f						! CTI
-		 sub			%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
-		sethi			%hi(TASK_REGOFF), %g2					! IEU0		Group		
-		sethi			%hi(TSTATE_PEF), %g3					! IEU1
-		or			%g2, %lo(TASK_REGOFF), %g2				! IEU0		Group
-		and			%g1, %g3, %g3						! IEU1
-		brnz,pn			%g3, 1f							! CTI+IEU1	Group
-		 add			%g6, %g2, %g2						! IEU0
-		wr			%g0, 0, %fprs						! Single	Group+4bubbles
-1:		rdpr			%tpc, %g3						! Single	Group
-		stx			%g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]			! Store		Group
-		rdpr			%tnpc, %g1						! Single	Group
-		stx			%g3, [%g2 + REGWIN_SZ + PT_V9_TPC]			! Store		Group
-		rd			%y, %g3							! Single	Group+4bubbles
-		stx			%g1, [%g2 + REGWIN_SZ + PT_V9_TNPC]			! Store		Group
-		st			%g3, [%g2 + REGWIN_SZ + PT_V9_Y]			! Store		Group
-		save			%g2, -STACK_BIAS, %sp	! The ordering here is		! Single	Group
-		rdpr			%pstate, %g1		! critical, see winfixup	! Single	Group+9bubbles
-		andn			%g6, 0x1f, %l6						! IEU0		Group
-		bne,pn			%xcc, 3f						! CTI		
-		 mov			PRIMARY_CONTEXT, %l4					! IEU1
-		rdpr			%canrestore, %g3					! Single	Group+4bubbles
-		rdpr			%wstate, %g2						! Single	Group+4bubbles
-		wrpr			%g0, 7, %cleanwin					! Single	Group+4bubbles
-		wrpr			%g0, 0, %canrestore					! Single	Group+4bubbles
-		sll			%g2, 3, %g2						! IEU0		Group
-		mov			1, %l5							! IEU1
-		stb			%l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth]	! Store
-		wrpr			%g3, 0, %otherwin					! Single	Group+4bubbles
-		wrpr			%g2, 0, %wstate						! Single	Group+4bubbles
-		stxa			%g0, [%l4] ASI_DMMU					! Store		Group
-		flush			%l6							! Single	Group+9bubbles
-		wr			%g0, ASI_AIUS, %asi					! Single	Group+4bubbles
-2:		wrpr			%g0, 0x0, %tl						! Single	Group+4bubbles
-		andn			%g1, PSTATE_MM, %l1					! IEU0		Group
-		mov			%g4, %l4						! IEU1
-		mov			%g5, %l5						! IEU0		Group
-		mov			%g7, %l2						! IEU1
-		wrpr			%l1, (PSTATE_AG|PSTATE_RMO), %pstate			! Single	Group+4bubbles
-		stx			%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]		! Store		Group
-		stx			%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]		! Store		Group
-		stx			%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]		! Store		Group
-		stx			%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]		! Store		Group
-		stx			%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]		! Store		Group
-		stx			%g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]		! Store		Group
-		stx			%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]		! Store		Group
-		stx			%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]		! Store		Group
-		stx			%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]		! Store		Group
-		stx			%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]		! Store		Group
-		stx			%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]		! Store		Group
-		stx			%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]		! Store		Group
-		sethi			%uhi(PAGE_OFFSET), %g4					! IEU0
-		stx			%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]		! Store		Group
-		stx			%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]		! Store		Group
-		sllx			%g4, 32, %g4						! IEU0
-		stx			%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]		! Store		Group
-		wrpr			%l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate		! Single	Group+4bubbles
-		jmpl			%l2 + 0x4, %g0						! CTI		Group
-		 mov			%l6, %g6						! IEU0
-
-3:		ldub			[%l6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5	! Load		Group
-		add			%l6, AOFF_task_thread + AOFF_thread_fpsaved + 1, %l4	! IEU0
-		srl			%l5, 1, %l3						! IEU0		Group
-		add			%l5, 2, %l5						! IEU1
-		stb			%l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth]	! Store
-		ba,pt			%xcc, 2b						! CTI
-		 stb			%g0, [%l4 + %l3]					! Store		Group
-
-etraptl1:	rdpr			%tstate, %g1						! Single	Group+4bubbles
-		sub			%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
-		ba,pt			%xcc, 1b						! CTI		Group
-		 andcc			%g1, TSTATE_PRIV, %g0					! IEU0
-
-scetrap:	rdpr			%pil, %g2						! Single 	Group
-		rdpr			%tstate, %g1						! Single 	Group
-		sllx			%g2, 20, %g3						! IEU0		Group
-		andcc			%g1, TSTATE_PRIV, %g0					! IEU1
-		or			%g1, %g3, %g1						! IEU0		Group
-		bne,a,pn		%xcc, 1f						! CTI
-		 sub			%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
-		sethi			%hi(TASK_REGOFF), %g2					! IEU0		Group
-		sethi			%hi(TSTATE_PEF), %g3					! IEU1
-		or			%g2, %lo(TASK_REGOFF), %g2				! IEU0		Group
-		and			%g1, %g3, %g3						! IEU1
-		brnz,pn			%g3, 1f							! CTI+IEU1	Group
-		 add			%g6, %g2, %g2						! IEU0
-		wr			%g0, 0, %fprs						! Single	Group+4bubbles
-1:		rdpr			%tpc, %g3						! Single	Group
-		stx			%g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]			! Store		Group
-		rdpr			%tnpc, %g1						! Single	Group
-		stx			%g3, [%g2 + REGWIN_SZ + PT_V9_TPC]			! Store		Group
-		stx			%g1, [%g2 + REGWIN_SZ + PT_V9_TNPC]			! Store		Group
-		st			%g0, [%g2 + REGWIN_SZ + PT_V9_Y]			! Store		Group
-		save			%g2, -STACK_BIAS, %sp	! The ordering here is		! Single	Group
-		rdpr			%pstate, %g1		! critical, see winfixup	! Single	Group+9bubbles
-		andn			%g6, 0x1f, %l6						! IEU0		Group
-		bne,pn			%xcc, 2f						! CTI		
-		 mov			PRIMARY_CONTEXT, %l4					! IEU1
-		rdpr			%canrestore, %g3					! Single	Group+4bubbles
-		rdpr			%wstate, %g2						! Single	Group+4bubbles
-		wrpr			%g0, 7, %cleanwin					! Single	Group+4bubbles
-		wrpr			%g0, 0, %canrestore					! Single	Group+4bubbles
-		sll			%g2, 3, %g2						! IEU0		Group
-		wrpr			%g3, 0, %otherwin					! Single	Group+4bubbles
-		wrpr			%g2, 0, %wstate						! Single	Group+4bubbles
-		stxa			%g0, [%l4] ASI_DMMU					! Store		Group
-		flush			%l6							! Single	Group+9bubbles
-		wr			%g0, ASI_AIUS, %asi					! Single	Group+4bubbles
-2:		wrpr			%g0, 0x0, %tl						! Single	Group+4bubbles
-		andn			%g1, PSTATE_MM, %l1					! IEU0		Group
-		mov			%g4, %l4						! IEU1
-		mov			%g5, %l5						! IEU0		Group
-		mov			%g7, %l2						! IEU1
-		wrpr			%l1, (PSTATE_AG|PSTATE_RMO), %pstate			! Single	Group+4bubbles
-		stx			%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]		! Store		Group
-		stx			%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]		! Store		Group
-		stx			%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]		! Store		Group
-		stx			%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]		! Store		Group
-		stx			%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]		! Store		Group
-		stx			%g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]		! Store		Group
-		stx			%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]		! Store		Group
-		stx			%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]		! Store		Group
-		stx			%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]		! Store		Group
-		stx			%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]		! Store		Group
-		stx			%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]		! Store		Group
-		stx			%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]		! Store		Group
-		sethi			%uhi(PAGE_OFFSET), %g4					! IEU0
-		stx			%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]		! Store		Group
-		stx			%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]		! Store		Group
-		sllx			%g4, 32, %g4						! IEU0
-		stx			%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]		! Store		Group
-		wrpr			%l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate		! Single	Group+4bubbles
-		jmpl			%l2 + 0x4, %g0						! CTI		Group
-		 mov			%l6, %g6						! IEU0
+		.align	64
+		.globl	etrap, etrap_irq, etraptl1
+
+etrap:		rdpr	%pil, %g2						! Single 	Group
+etrap_irq:	rdpr	%tstate, %g1						! Single 	Group
+		sllx	%g2, 20, %g3						! IEU0		Group
+		andcc	%g1, TSTATE_PRIV, %g0					! IEU1
+		or	%g1, %g3, %g1						! IEU0		Group
+		bne,pn	%xcc, 1f							! CTI
+		 sub	%sp, REGWIN_SZ+TRACEREG_SZ-STACK_BIAS, %g2		! IEU1
+		wrpr	%g0, 7, %cleanwin					! Single	Group+4bubbles
+
+		sethi	%hi(TASK_REGOFF), %g2					! IEU0		Group		
+		sethi	%hi(TSTATE_PEF), %g3					! IEU1
+		or	%g2, %lo(TASK_REGOFF), %g2				! IEU0		Group
+		and	%g1, %g3, %g3						! IEU1
+		brnz,pn	%g3, 1f							! CTI+IEU1	Group
+		 add	%g6, %g2, %g2						! IEU0
+		wr	%g0, 0, %fprs						! Single	Group+4bubbles
+1:		rdpr	%tpc, %g3						! Single	Group
+
+		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]			! Store		Group
+		rdpr	%tnpc, %g1						! Single	Group
+		stx	%g3, [%g2 + REGWIN_SZ + PT_V9_TPC]			! Store		Group
+		rd	%y, %g3							! Single	Group+4bubbles
+		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TNPC]			! Store		Group
+		st	%g3, [%g2 + REGWIN_SZ + PT_V9_Y]			! Store		Group
+		save	%g2, -STACK_BIAS, %sp	! Ordering here is critical	! Single	Group
+		mov	%g6, %l6						! IEU0		Group
+
+		bne,pn	%xcc, 3f						! CTI		
+		 mov	PRIMARY_CONTEXT, %l4					! IEU1
+		rdpr	%canrestore, %g3					! Single	Group+4bubbles
+		rdpr	%wstate, %g2						! Single	Group+4bubbles
+		wrpr	%g0, 0, %canrestore					! Single	Group+4bubbles
+		sll	%g2, 3, %g2						! IEU0		Group
+		mov	1, %l5							! IEU1
+		stb	%l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth]	! Store
+
+		wrpr	%g3, 0, %otherwin					! Single	Group+4bubbles
+		wrpr	%g2, 0, %wstate						! Single	Group+4bubbles
+		stxa	%g0, [%l4] ASI_DMMU					! Store		Group
+		flush	%l6							! Single	Group+9bubbles
+		wr	%g0, ASI_AIUS, %asi					! Single	Group+4bubbles
+2:		wrpr	%g0, 0x0, %tl						! Single	Group+4bubbles
+		mov	%g4, %l4						! IEU1
+		mov	%g5, %l5						! IEU0		Group
+
+		mov	%g7, %l2						! IEU1
+		wrpr	%g0, ETRAP_PSTATE1, %pstate				! Single	Group+4bubbles
+		stx	%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]		! Store		Group
+		stx	%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]		! Store		Group
+		stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]		! Store		Group
+		stx	%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]		! Store		Group
+		stx	%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]		! Store		Group
+		stx	%g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]		! Store		Group
+
+		stx	%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]		! Store		Group
+		stx	%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]		! Store		Group
+		stx	%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]		! Store		Group
+		stx	%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]		! Store		Group
+		stx	%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]		! Store		Group
+		stx	%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]		! Store		Group
+		sethi	%uhi(PAGE_OFFSET), %g4					! IEU0
+		stx	%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]		! Store		Group
+
+		stx	%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]		! Store		Group
+		sllx	%g4, 32, %g4						! IEU0
+		stx	%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]		! Store		Group
+		wrpr	%g0, ETRAP_PSTATE2, %pstate				! Single	Group+4bubbles
+		jmpl	%l2 + 0x4, %g0						! CTI		Group
+		 mov	%l6, %g6						! IEU0
+		nop
+		nop
+
+3:		ldub	[%l6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5	! Load		Group
+		add	%l6, AOFF_task_thread + AOFF_thread_fpsaved + 1, %l4	! IEU0
+		srl	%l5, 1, %l3						! IEU0		Group
+		add	%l5, 2, %l5						! IEU1
+		stb	%l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth]	! Store
+		ba,pt	%xcc, 2b						! CTI
+		 stb	%g0, [%l4 + %l3]					! Store		Group
+		nop
+
+etraptl1:	rdpr	%tstate, %g1						! Single	Group+4bubbles
+		sub	%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
+		ba,pt	%xcc, 1b						! CTI		Group
+		 andcc	%g1, TSTATE_PRIV, %g0					! IEU0
+
+		.align	64
+		.globl	scetrap
+scetrap:	rdpr	%pil, %g2						! Single 	Group
+		rdpr	%tstate, %g1						! Single 	Group
+		sllx	%g2, 20, %g3						! IEU0		Group
+		andcc	%g1, TSTATE_PRIV, %g0					! IEU1
+		or	%g1, %g3, %g1						! IEU0		Group
+		bne,pn	%xcc, 1f						! CTI
+		 sub	%sp, (REGWIN_SZ+TRACEREG_SZ-STACK_BIAS), %g2		! IEU1
+		wrpr	%g0, 7, %cleanwin					! Single	Group+4bubbles
+
+		sllx	%g1, 51, %g3						! IEU0		Group
+		sethi	%hi(TASK_REGOFF), %g2					! IEU1
+		or	%g2, %lo(TASK_REGOFF), %g2				! IEU0		Group
+		brlz,pn	%g3, 1f							! CTI+IEU1
+		 add	%g6, %g2, %g2						! IEU0		Group
+		wr	%g0, 0, %fprs						! Single	Group+4bubbles
+1:		rdpr	%tpc, %g3						! Single	Group
+		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]			! Store		Group
+
+		rdpr	%tnpc, %g1						! Single	Group
+		stx	%g3, [%g2 + REGWIN_SZ + PT_V9_TPC]			! Store		Group
+		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TNPC]			! Store		Group
+		save	%g2, -STACK_BIAS, %sp	! Ordering here is critical	! Single	Group
+		mov	%g6, %l6						! IEU0		Group
+		bne,pn	%xcc, 2f						! CTI		
+		 mov	ASI_P, %l7						! IEU1
+		rdpr	%canrestore, %g3					! Single	Group+4bubbles
+
+		rdpr	%wstate, %g2						! Single	Group+4bubbles
+		wrpr	%g0, 0, %canrestore					! Single	Group+4bubbles
+		sll	%g2, 3, %g2						! IEU0		Group
+		mov	PRIMARY_CONTEXT, %l4					! IEU1
+		wrpr	%g3, 0, %otherwin					! Single	Group+4bubbles
+		wrpr	%g2, 0, %wstate						! Single	Group+4bubbles
+		stxa	%g0, [%l4] ASI_DMMU					! Store
+		flush	%l6							! Single	Group+9bubbles
+
+		mov	ASI_AIUS, %l7						! IEU0		Group
+2:		mov	%g4, %l4						! IEU1
+		mov	%g5, %l5						! IEU0		Group
+		add	%g7, 0x4, %l2						! IEU1
+		wrpr	%g0, ETRAP_PSTATE1, %pstate				! Single	Group+4bubbles
+		stx	%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]		! Store		Group
+		stx	%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]		! Store		Group
+		sllx	%l7, 24, %l7						! IEU0
+
+		stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]		! Store		Group
+		rdpr	%cwp, %l0						! Single	Group
+		stx	%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]		! Store		Group
+		stx	%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]		! Store		Group
+		stx	%g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]		! Store		Group
+		stx	%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]		! Store		Group
+		or	%l7, %l0, %l7						! IEU0
+		sethi	%hi(TSTATE_RMO | TSTATE_PEF), %l0			! IEU1
+
+		or	%l7, %l0, %l7						! IEU0		Group
+		wrpr	%l2, %tnpc						! Single	Group+4bubbles
+		wrpr	%l7, (TSTATE_PRIV | TSTATE_IE), %tstate			! Single	Group+4bubbles
+		stx	%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]		! Store		Group
+		stx	%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]		! Store		Group
+		stx	%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]		! Store		Group
+		stx	%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]		! Store		Group
+		stx	%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]		! Store		Group
+
+		sethi	%uhi(PAGE_OFFSET), %g4					! IEU0
+		stx	%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]		! Store		Group
+		stx	%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]		! Store		Group
+		sllx	%g4, 32, %g4						! IEU0
+		mov	%l6, %g6						! IEU1
+		stx	%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]		! Store		Group
+		done
+		nop
 
 #undef TASK_REGOFF
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/ioctl32.c	Mon Mar 27 08:08:22 2000
+++ linux/arch/sparc64/kernel/ioctl32.c	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.85 2000/03/23 05:25:41 davem Exp $
+/* $Id: ioctl32.c,v 1.87 2000/03/30 02:09:07 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -2716,6 +2716,25 @@
 COMPATIBLE_IOCTL(SG_EMULATED_HOST)
 COMPATIBLE_IOCTL(SG_SET_TRANSFORM)
 COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
+COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
+COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
+COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
+COMPATIBLE_IOCTL(SG_SET_DEBUG)
+COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
+COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
+COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
+COMPATIBLE_IOCTL(SG_SCSI_RESET)
+COMPATIBLE_IOCTL(SG_IO)
+COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
+COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
+COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
 /* PPP stuff */
 COMPATIBLE_IOCTL(PPPIOCGFLAGS)
 COMPATIBLE_IOCTL(PPPIOCSFLAGS)
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/itlb_base.S linux/arch/sparc64/kernel/itlb_base.S
--- v2.3.99-pre3/linux/arch/sparc64/kernel/itlb_base.S	Tue Feb  1 01:35:43 2000
+++ linux/arch/sparc64/kernel/itlb_base.S	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: itlb_base.S,v 1.8 2000/01/31 04:59:12 davem Exp $
+/* $Id: itlb_base.S,v 1.9 2000/03/26 09:13:48 davem Exp $
  * itlb_base.S:	Front end to ITLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
@@ -40,25 +40,25 @@
 
 /* ITLB ** ICACHE line 3: Real faults			*/
 	rdpr		%tpc, %g5			! And load faulting VA
-	clr		%g4				! It was read
+	mov		FAULT_CODE_ITLB, %g4		! It was read from ITLB
 sparc64_realfault_common:				! Called by TL0 dtlb_miss too
-	sethi		%hi(1f), %g7			! Save state
-	ba,pt		%xcc, etrap			! ...
-1:	 or		%g7, %lo(1b), %g7		! ...
-	mov		%l4, %o2			! Read/Write/No idea
-	srlx		%l5, PAGE_SHIFT, %o1		! Page align faulting VA
-	add		%sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg
-
-/* ITLB ** ICACHE line 4: Call fault processing code	 */
+	stb		%g4, [%g6 + AOFF_task_thread + AOFF_thread_fault_code]
+	stx		%g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
+	ba,pt		%xcc, etrap			! Save state
+1:	 rd		%pc, %g7			! ...
 	call		do_sparc64_fault		! Call fault handler
-	 sllx		%o1, PAGE_SHIFT, %o1		! Finish page alignment
-	ba,a,pt		%xcc, rtrap_clr_l6		! Restore cpu state
-	nop
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg
+
+/* ITLB ** ICACHE line 4: Finish faults + window fixups	*/
+	ba,pt		%xcc, rtrap_clr_l6		! Restore cpu state
+	 nop
 winfix_trampoline:
 	rdpr		%tpc, %g3			! Prepare winfixup TNPC
 	or		%g3, 0x7c, %g3			! Compute offset to branch
 	wrpr		%g3, %tnpc			! Write it into TNPC
 	done						! Do it to it
+	nop
+	nop
 
 #undef TAG_CONTEXT_BITS
 #undef VPTE_SHIFT
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/pci_common.c	Fri Jan  7 19:13:21 2000
+++ linux/arch/sparc64/kernel/pci_common.c	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.6 2000/01/06 23:51:49 davem Exp $
+/* $Id: pci_common.c,v 1.7 2000/03/25 05:18:11 davem Exp $
  * pci_common.c: PCI controller common support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -563,6 +563,165 @@
 	walk = &pbus->children;
 	for (walk = walk->next; walk != &pbus->children; walk = walk->next)
 		pci_fixup_irq(pbm, pci_bus_b(walk));
+}
+
+#undef DEBUG_BUSMASTERING
+
+static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz)
+{
+	u16 cmd;
+	u8 hdr_type, min_gnt, ltimer;
+
+#ifdef DEBUG_BUSMASTERING
+	printk("PCI: Checking DEV(%s), ", pdev->name);
+#endif
+
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MASTER;
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+	/* Read it back, if the mastering bit did not
+	 * get set, the device does not support bus
+	 * mastering so we have nothing to do here.
+	 */
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	if ((cmd & PCI_COMMAND_MASTER) == 0) {
+#ifdef DEBUG_BUSMASTERING
+		printk("no bus mastering...\n");
+#endif
+		return;
+	}
+
+	/* Set correct cache line size, 64-byte on all
+	 * Sparc64 PCI systems.  Note that the value is
+	 * measured in 32-bit words.
+	 */
+#ifdef DEBUG_BUSMASTERING
+	printk("set cachelinesize, ");
+#endif
+	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+			      64 / sizeof(u32));
+
+	pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr_type);
+	hdr_type &= ~0x80;
+	if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
+#ifdef DEBUG_BUSMASTERING
+		printk("hdr_type=%x, exit\n", hdr_type);
+#endif
+		return;
+	}
+
+	/* If the latency timer is already programmed with a non-zero
+	 * value, assume whoever set it (OBP or whoever) knows what
+	 * they are doing.
+	 */
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ltimer);
+	if (ltimer != 0) {
+#ifdef DEBUG_BUSMASTERING
+		printk("ltimer was %x, exit\n", ltimer);
+#endif
+		return;
+	}
+
+	/* XXX Since I'm tipping off the min grant value to
+	 * XXX choose a suitable latency timer value, I also
+	 * XXX considered making use of the max latency value
+	 * XXX as well.  Unfortunately I've seen too many bogusly
+	 * XXX low settings for it to the point where it lacks
+	 * XXX any usefulness.  In one case, an ethernet card
+	 * XXX claimed a min grant of 10 and a max latency of 5.
+	 * XXX Now, if I had two such cards on the same bus I
+	 * XXX could not set the desired burst period (calculated
+	 * XXX from min grant) without violating the max latency
+	 * XXX bound.  Duh...
+	 * XXX
+	 * XXX I blame dumb PC bios implementors for stuff like
+	 * XXX this, most of them don't even try to do something
+	 * XXX sensible with latency timer values and just set some
+	 * XXX default value (usually 32) into every device.
+	 */
+
+	pci_read_config_byte(pdev, PCI_MIN_GNT, &min_gnt);
+
+	if (min_gnt == 0) {
+		/* If no min_gnt setting then use a default
+		 * value.
+		 */
+		if (is_66mhz)
+			ltimer = 16;
+		else
+			ltimer = 32;
+	} else {
+		int shift_factor;
+
+		if (is_66mhz)
+			shift_factor = 2;
+		else
+			shift_factor = 3;
+
+		/* Use a default value when the min_gnt value
+		 * is erroneously high.
+		 */
+		if (((unsigned int) min_gnt << shift_factor) > 512 ||
+		    ((min_gnt << shift_factor) & 0xff) == 0) {
+			ltimer = 8 << shift_factor;
+		} else {
+			ltimer = min_gnt << shift_factor;
+		}
+	}
+
+	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ltimer);
+#ifdef DEBUG_BUSMASTERING
+	printk("set ltimer to %x\n", ltimer);
+#endif
+}
+
+void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
+				     struct pci_bus *pbus)
+{
+	struct list_head *walk;
+	int all_are_66mhz;
+	u16 status;
+
+	if (pbm->is_66mhz_capable == 0) {
+		all_are_66mhz = 0;
+		goto out;
+	}
+
+	walk = &pbus->devices;
+	all_are_66mhz = 1;
+	for (walk = walk->next; walk != &pbus->devices; walk = walk->next) {
+		struct pci_dev *pdev = pci_dev_b(walk);
+
+		pci_read_config_word(pdev, PCI_STATUS, &status);
+		if (!(status & PCI_STATUS_66MHZ)) {
+			all_are_66mhz = 0;
+			break;
+		}
+	}
+out:
+	pbm->all_devs_66mhz = all_are_66mhz;
+
+	printk("PCI%d(PBM%c): Bus running at %dMHz\n",
+	       pbm->parent->index,
+	       (pbm == &pbm->parent->pbm_A) ? 'A' : 'B',
+	       (all_are_66mhz ? 66 : 33));
+}
+
+void pci_setup_busmastering(struct pci_pbm_info *pbm,
+			    struct pci_bus *pbus)
+{
+	struct list_head *walk = &pbus->devices;
+	int is_66mhz;
+
+	is_66mhz = pbm->is_66mhz_capable && pbm->all_devs_66mhz;
+
+	for (walk = walk->next; walk != &pbus->devices; walk = walk->next)
+		pdev_setup_busmastering(pci_dev_b(walk), is_66mhz);
+
+	walk = &pbus->children;
+	for (walk = walk->next; walk != &pbus->children; walk = walk->next)
+		pci_setup_busmastering(pbm, pci_bus_b(walk));
 }
 
 /* Generic helper routines for PCI error reporting. */
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/pci_impl.h linux/arch/sparc64/kernel/pci_impl.h
--- v2.3.99-pre3/linux/arch/sparc64/kernel/pci_impl.h	Thu Feb 10 17:11:06 2000
+++ linux/arch/sparc64/kernel/pci_impl.h	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_impl.h,v 1.5 2000/02/08 05:11:32 jj Exp $
+/* $Id: pci_impl.h,v 1.6 2000/03/25 05:18:11 davem Exp $
  * pci_impl.h: Helper definitions for PCI controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -28,6 +28,10 @@
 				  struct pci_bus *pbus);
 extern void pci_fixup_irq(struct pci_pbm_info *pbm,
 			  struct pci_bus *pbus);
+extern void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
+					    struct pci_bus *pbus);
+extern void pci_setup_busmastering(struct pci_pbm_info *pbm,
+				   struct pci_bus *pbus);
 
 /* Error reporting support. */
 extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/pci_psycho.c	Fri Mar 10 16:40:41 2000
+++ linux/arch/sparc64/kernel/pci_psycho.c	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.14 2000/03/10 02:42:15 davem Exp $
+/* $Id: pci_psycho.c,v 1.15 2000/03/25 05:18:11 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1193,6 +1193,23 @@
 	pbm_renumber(&p->pbm_A, 0xff);
 }
 
+static void __init pbm_config_busmastering(struct pci_pbm_info *pbm)
+{
+	u8 *addr;
+
+	/* Set cache-line size to 64 bytes, this is actually
+	 * a nop but I do it for completeness.
+	 */
+	addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+					0, PCI_CACHE_LINE_SIZE);
+	pci_config_write8(addr, 64 / sizeof(u32));
+
+	/* Set PBM latency timer to 64 PCI clocks. */
+	addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+					0, PCI_LATENCY_TIMER);
+	pci_config_write8(addr, 64);
+}
+
 static void __init pbm_scan_bus(struct pci_controller_info *p,
 				struct pci_pbm_info *pbm)
 {
@@ -1203,11 +1220,17 @@
 	pci_record_assignments(pbm, pbm->pci_bus);
 	pci_assign_unassigned(pbm, pbm->pci_bus);
 	pci_fixup_irq(pbm, pbm->pci_bus);
+	pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
+	pci_setup_busmastering(pbm, pbm->pci_bus);
 }
 
 static void __init psycho_scan_bus(struct pci_controller_info *p)
 {
 	pbm_bridge_reconfigure(p);
+	pbm_config_busmastering(&p->pbm_B);
+	p->pbm_B.is_66mhz_capable = 0;
+	pbm_config_busmastering(&p->pbm_A);
+	p->pbm_A.is_66mhz_capable = 1;
 	pbm_scan_bus(p, &p->pbm_B);
 	pbm_scan_bus(p, &p->pbm_A);
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/pci_sabre.c	Fri Mar 10 16:40:41 2000
+++ linux/arch/sparc64/kernel/pci_sabre.c	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.15 2000/03/10 02:42:16 davem Exp $
+/* $Id: pci_sabre.c,v 1.16 2000/03/25 05:18:12 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1060,6 +1060,13 @@
 	struct pci_bus *sabre_bus;
 	struct list_head *walk;
 
+	/* The APB bridge speaks to the Sabre host PCI bridge
+	 * at 66Mhz, but the front side of APB runs at 33Mhz
+	 * for both segments.
+	 */
+	p->pbm_A.is_66mhz_capable = 0;
+	p->pbm_B.is_66mhz_capable = 0;
+
 	/* Unlike for PSYCHO, we can only have one SABRE
 	 * in a system.  Having multiple SABREs is thus
 	 * and error, and as a consequence we do not need
@@ -1079,6 +1086,17 @@
 	sabre_bus = pci_scan_bus(p->pci_first_busno,
 				 p->pci_ops,
 				 &p->pbm_A);
+
+	{
+		unsigned int devfn;
+		u8 *addr;
+
+		devfn = PCI_DEVFN(0, 0);
+		addr = sabre_pci_config_mkaddr(&p->pbm_A, 0,
+					       devfn, PCI_LATENCY_TIMER);
+		pci_config_write8(addr, 32);
+	}
+
 	apb_init(p, sabre_bus);
 
 	walk = &sabre_bus->children;
@@ -1099,6 +1117,8 @@
 		pci_record_assignments(pbm, pbus);
 		pci_assign_unassigned(pbm, pbus);
 		pci_fixup_irq(pbm, pbus);
+		pci_determine_66mhz_disposition(pbm, pbus);
+		pci_setup_busmastering(pbm, pbus);
 	}
 
 	sabre_register_error_handlers(p);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/process.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/sparc64/kernel/process.c	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.104 2000/03/01 02:53:32 davem Exp $
+/*  $Id: process.c,v 1.105 2000/03/26 09:13:48 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -451,7 +451,7 @@
 {
 	unsigned long fp, distance, rval;
 
-	if(!(current->thread.flags & SPARC_FLAG_32BIT)) {
+	if (!(current->thread.flags & SPARC_FLAG_32BIT)) {
 		csp += STACK_BIAS;
 		psp += STACK_BIAS;
 		__get_user(fp, &(((struct reg_window *)psp)->ins[6]));
@@ -466,14 +466,14 @@
 
 	distance = fp - psp;
 	rval = (csp - distance);
-	if(copy_in_user(rval, psp, distance))
+	if (copy_in_user(rval, psp, distance))
 		rval = 0;
-	else if(current->thread.flags & SPARC_FLAG_32BIT) {
-		if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6])))
+	else if (current->thread.flags & SPARC_FLAG_32BIT) {
+		if (put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6])))
 			rval = 0;
 	} else {
-		if(put_user(((u64)csp - STACK_BIAS),
-			    &(((struct reg_window *)rval)->ins[6])))
+		if (put_user(((u64)csp - STACK_BIAS),
+			     &(((struct reg_window *)rval)->ins[6])))
 			rval = 0;
 		else
 			rval = rval - STACK_BIAS;
@@ -488,7 +488,7 @@
 {
 	int i;
 
-	for(i = first_win; i < last_win; i++) {
+	for (i = first_win; i < last_win; i++) {
 		t->rwbuf_stkptrs[i] = t->rwbuf_stkptrs[i+1];
 		memcpy(&t->reg_window[i], &t->reg_window[i+1],
 		       sizeof(struct reg_window));
@@ -501,11 +501,11 @@
 	unsigned long window;
 
 	flush_user_windows();
-	if((window = t->w_saved) != 0) {
+	if ((window = t->w_saved) != 0) {
 		int winsize = REGWIN_SZ;
 		int bias = 0;
 
-		if(t->flags & SPARC_FLAG_32BIT)
+		if (t->flags & SPARC_FLAG_32BIT)
 			winsize = REGWIN32_SZ;
 		else
 			bias = STACK_BIAS;
@@ -515,11 +515,11 @@
 			unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
 			struct reg_window *rwin = &t->reg_window[window];
 
-			if(!copy_to_user((char *)sp, rwin, winsize)) {
+			if (!copy_to_user((char *)sp, rwin, winsize)) {
 				shift_window_buffer(window, t->w_saved - 1, t);
 				t->w_saved--;
 			}
-		} while(window--);
+		} while (window--);
 	}
 }
 
@@ -530,25 +530,29 @@
 	int winsize = REGWIN_SZ;
 	int bias = 0;
 
-	if(t->flags & SPARC_FLAG_32BIT)
+	if (t->flags & SPARC_FLAG_32BIT)
 		winsize = REGWIN32_SZ;
 	else
 		bias = STACK_BIAS;
+
 	flush_user_windows();
 	window = t->w_saved;
-	if(window != 0) {
+
+	if (window != 0) {
 		window -= 1;
 		do {
 			unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
 			struct reg_window *rwin = &t->reg_window[window];
 
-			if(copy_to_user((char *)sp, rwin, winsize))
+			if (copy_to_user((char *)sp, rwin, winsize))
 				goto barf;
-		} while(window--);
+		} while (window--);
 	}
 	t->w_saved = 0;
 	return;
+
 barf:
+	t->w_saved = window + 1;
 	do_exit(SIGILL);
 }
 
@@ -578,7 +582,8 @@
 	t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
 	t->cwp = (regs->tstate + 1) & TSTATE_CWP;
 	t->fpsaved[0] = 0;
-	if(regs->tstate & TSTATE_PRIV) {
+
+	if (regs->tstate & TSTATE_PRIV) {
 		/* Special case, if we are spawning a kernel thread from
 		 * a userspace task (via KMOD, NFS, or similar) we must
 		 * disable performance counters in the child because the
@@ -597,7 +602,7 @@
 		       sizeof(struct reg_window));
 		t->kregs->u_regs[UREG_G6] = (unsigned long) p;
 	} else {
-		if(t->flags & SPARC_FLAG_32BIT) {
+		if (t->flags & SPARC_FLAG_32BIT) {
 			sp &= 0x00000000ffffffffUL;
 			regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
 		}
@@ -607,7 +612,7 @@
 			unsigned long csp;
 
 			csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
-			if(!csp)
+			if (!csp)
 				return -EFAULT;
 			t->kregs->u_regs[UREG_FP] = csp;
 		}
@@ -621,19 +626,7 @@
 
 	/* Set the second return value for the parent. */
 	regs->u_regs[UREG_I1] = 0;
-#if 0
-	printk("\ncopy_thread: c(%p[mm(%p:%p)]) p(%p[mm(%p:%p)])\n",
-	       current, current->mm, current->active_mm,
-	       p, p->mm, p->active_mm);
-	printk("copy_thread: c MM_ctx(%016lx) MM_pgd(%016lx)\n",
-	       (current->mm ? current->mm->context : 0),
-	       (current->mm ? pgd_val(current->mm->pgd[0]) : 0));
-	printk("copy_thread: p MM_ctx(%016lx) MM_pgd(%08x)\n",
-	       (p->mm ? p->mm->context : 0),
-	       (p->mm ? pgd_val(p->mm->pgd[0]) : 0));
-	printk("copy_thread: c->flags(%x) p->flags(%x) ",
-	       current->thread.flags, p->thread.flags);
-#endif
+
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.3.99-pre3/linux/arch/sparc64/kernel/rtrap.S	Thu Feb 10 17:11:06 2000
+++ linux/arch/sparc64/kernel/rtrap.S	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.48 2000/02/09 11:15:07 davem Exp $
+/* $Id: rtrap.S,v 1.49 2000/03/29 09:55:31 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -14,194 +14,207 @@
 #include <asm/processor.h>
 
 #define		PTREGS_OFF		(STACK_BIAS + REGWIN_SZ)
+#define		RTRAP_PSTATE		(PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE)
+#define		RTRAP_PSTATE_IRQOFF	(PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV)
+#define		RTRAP_PSTATE_AG_IRQOFF	(PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
+
+#if 0
+#define		RTRAP_CHECK		call rtrap_check;  add %sp, (STACK_BIAS+REGWIN_SZ), %o0;
+#else
+#define		RTRAP_CHECK
+#endif
 
 		.text
+
 		.align			32
+__handle_softirq:
+		call			do_softirq
+		 nop
+		ba,a,pt			%xcc, __handle_softirq_continue
+		 nop
+__handle_preemption:
+		call			schedule
+		 nop
+		ba,pt			%xcc, __handle_preemption_continue
+		 nop
+__handle_user_windows:
+		wrpr			%g0, RTRAP_PSTATE, %pstate
+		call			fault_in_user_windows
+		 add			%sp, STACK_BIAS + REGWIN_SZ, %g0
+		ba,a,pt			%xcc, __handle_user_windows_continue
+__handle_perfctrs:
+		/* Don't forget to preserve user window invariants. */
+		wrpr			%g0, RTRAP_PSTATE, %pstate
+		call			update_perfctrs
+		 nop
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
+		brz,pt			%o2, __handle_perfctrs_continue
+		 sethi			%hi(TSTATE_PEF), %l6
+		wrpr			%g0, RTRAP_PSTATE, %pstate
+
+		call			fault_in_user_windows
+		 add			%sp, STACK_BIAS + REGWIN_SZ, %o0
+		ba,pt			%xcc, __handle_perfctrs_continue
+		 nop			
+__handle_userfpu:
+		rd			%fprs, %l5
+		andcc			%l5, FPRS_FEF, %g0
+		be,a,pn			%icc, __handle_userfpu_continue
+		 andn			%l1, %l6, %l1
+		ba,a,pt			%xcc, __handle_userfpu_continue
+__handle_signal:
+		clr			%o0
+		mov			%l5, %o2
+		mov			%l6, %o3
+		call			do_signal
+		 add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		ba,pt			%xcc, __handle_signal_continue
+		 clr			%l6
+		nop
+
+		.align			64
 		.globl			rtrap_clr_l6, rtrap
 rtrap_clr_l6:	clr			%l6
-		/* Fall through */
 rtrap:		lduw			[%g6 + AOFF_task_processor], %l0
 		sethi			%hi(softirq_state), %l2
 		or			%l2, %lo(softirq_state), %l2
 		sllx			%l0, 6, %l0
 		ldx			[%l2 + %l0], %l1
 		srlx			%l1, 32, %l2
-
 		andcc			%l1, %l2, %g0
-		be,pt			%icc, 2f
-		 nop
-		call			do_softirq
-		 nop
-2:		ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+
+		bne,pn			%icc, __handle_softirq
+		 ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+__handle_softirq_continue:
 		sethi			%hi(0xf << 20), %l4
 		andcc			%l1, TSTATE_PRIV, %l3
-
 		and			%l1, %l4, %l4
-		rdpr			%pstate, %l7
-		andn			%l1, %l4, %l1
-		be,pt			%icc, to_user
-		 andn			%l7, PSTATE_IE, %l7
+		bne,pn			%icc, to_kernel
+		 andn			%l1, %l4, %l1
+to_user:	ldx			[%g6 + AOFF_task_need_resched], %l0
+
+		brnz,pn			%l0, __handle_preemption
+__handle_preemption_continue:
+		 lduw			[%g6 + AOFF_task_sigpending], %l0
+		brnz,pn			%l0, __handle_signal
+		 nop
+__handle_signal_continue:
+check_user_wins:
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
+		brnz,pn			%o2, __handle_user_windows
+		 sethi			%hi(TSTATE_PEF), %l6
+
+__handle_user_windows_continue:
+		RTRAP_CHECK
+		ldub			[%g6 + AOFF_task_thread + AOFF_thread_flags], %l5
+		andcc			%l5, SPARC_FLAG_PERFCTR, %g0
+		bne,pn			%xcc, __handle_perfctrs
+__handle_perfctrs_continue:
+		 andcc			%l1, %l6, %g0
+		bne,pn			%xcc, __handle_userfpu
+		 stb			%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
+__handle_userfpu_continue:
 
-		ldub			[%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5
-		brz,pt			%l5, rt_continue
-		 srl			%l5, 1, %o0
-		add			%g6, AOFF_task_thread + AOFF_thread_fpsaved, %l6
-		ldub			[%l6 + %o0], %l2
-		sub			%l5, 2, %l5
-		add			%g6, AOFF_task_thread + AOFF_thread_gsr, %o1
-		andcc			%l2, (FPRS_FEF|FPRS_DU), %g0
-		be,pt			%icc, 2f
-		 and			%l2, FPRS_DL, %l6
-		andcc			%l2, FPRS_FEF, %g0
-		be,pn			%icc, 5f
-		 sll			%o0, 3, %o5
-		rd			%fprs, %g5
-		wr			%g5, FPRS_FEF, %fprs
-		ldub			[%o1 + %o0], %g5
-		add			%g6, AOFF_task_thread + AOFF_thread_xfsr, %o1
-		membar			#StoreLoad | #LoadLoad
-		sll			%o0, 8, %o2
-		add			%g6, AOFF_task_fpregs, %o3
-		brz,pn			%l6, 1f
-		 add			%g6, AOFF_task_fpregs+0x40, %o4
-		ldda			[%o3 + %o2] ASI_BLK_P, %f0
-		ldda			[%o4 + %o2] ASI_BLK_P, %f16
-1:		andcc			%l2, FPRS_DU, %g0
-		be,pn			%icc, 1f
-		 wr			%g5, 0, %gsr
-		add			%o2, 0x80, %o2
-		ldda			[%o3 + %o2] ASI_BLK_P, %f32
-		ldda			[%o4 + %o2] ASI_BLK_P, %f48
-1:		membar			#Sync
-		ldx			[%o1 + %o5], %fsr
-2:		stb			%l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
 rt_continue:	ldx			[%sp + PTREGS_OFF + PT_V9_G1], %g1
 		ldx			[%sp + PTREGS_OFF + PT_V9_G2], %g2
+
 		ldx			[%sp + PTREGS_OFF + PT_V9_G3], %g3
-		mov			%g6, %o5
 		ldx			[%sp + PTREGS_OFF + PT_V9_G4], %g4
 		ldx			[%sp + PTREGS_OFF + PT_V9_G5], %g5
 		ldx			[%sp + PTREGS_OFF + PT_V9_G6], %g6
 		ldx			[%sp + PTREGS_OFF + PT_V9_G7], %g7
-
-		wrpr			%l7, PSTATE_AG, %pstate
+		wrpr			%g0, RTRAP_PSTATE_AG_IRQOFF, %pstate
 		ldx			[%sp + PTREGS_OFF + PT_V9_I0], %i0
 		ldx			[%sp + PTREGS_OFF + PT_V9_I1], %i1
+
 		ldx			[%sp + PTREGS_OFF + PT_V9_I2], %i2
 		ldx			[%sp + PTREGS_OFF + PT_V9_I3], %i3
 		ldx			[%sp + PTREGS_OFF + PT_V9_I4], %i4
 		ldx			[%sp + PTREGS_OFF + PT_V9_I5], %i5
 		ldx			[%sp + PTREGS_OFF + PT_V9_I6], %i6
-
 		ldx			[%sp + PTREGS_OFF + PT_V9_I7], %i7
-		ld			[%sp + PTREGS_OFF + PT_V9_Y], %o3
 		ldx			[%sp + PTREGS_OFF + PT_V9_TPC], %l2
 		ldx			[%sp + PTREGS_OFF + PT_V9_TNPC], %o2
+
+		ld			[%sp + PTREGS_OFF + PT_V9_Y], %o3
 		wr			%o3, %g0, %y
 		srl			%l4, 20, %l4
 		wrpr			%l4, 0x0, %pil
 		wrpr			%g0, 0x1, %tl
-
 		wrpr			%l1, %g0, %tstate
 		wrpr			%l2, %g0, %tpc
 		wrpr			%o2, %g0, %tnpc
+
 		brnz,pn			%l3, kern_rtt
 		 mov			PRIMARY_CONTEXT, %l7
 		ldxa			[%l7 + %l7] ASI_DMMU, %l0
 		stxa			%l0, [%l7] ASI_DMMU
-		flush			%o5
-
+		flush			%g6
 		rdpr			%wstate, %l1
 		rdpr			%otherwin, %l2
 		srl			%l1, 3, %l1
+
 		wrpr			%l2, %g0, %canrestore
 		wrpr			%l1, %g0, %wstate
 		wrpr			%g0, %g0, %otherwin
 		restore
 		rdpr			%canrestore, %g1
-
 		wrpr			%g1, 0x0, %cleanwin
 		retry
+		nop
+
 kern_rtt:	restore
 		retry
-to_user:	ldx			[%g6 + AOFF_task_need_resched], %l0
-		wrpr			%l7, PSTATE_IE, %pstate
-		orcc			%g0, %l0, %g0
-		be,a,pt			%xcc, check_signal
-
-		 lduw			[%g6 + AOFF_task_sigpending], %l0
-		call			schedule
-		 nop
-		lduw			[%g6 + AOFF_task_sigpending], %l0
-check_signal:	brz,a,pt		%l0, check_user_wins
-		 nop
-		clr			%o0
-		mov			%l5, %o2  
-		mov			%l6, %o3
-		call			do_signal
-		 add			%sp, STACK_BIAS + REGWIN_SZ, %o1
-		clr			%l6
-
-		/* We must not take any traps between here and the actual
-		 * return to user-space.  If we do we risk having windows
-		 * saved to the thread struct between the test and the
-		 * actual return from trap.  --DaveM
-		 */
-check_user_wins:
-		wrpr			%l7, 0x0, %pstate
-		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
-		brz,pt			%o2, 1f
-		 sethi			%hi(TSTATE_PEF), %l6
+to_kernel:	ldub			[%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5
+		brz,pt			%l5, rt_continue
+		 srl			%l5, 1, %o0
+		add			%g6, AOFF_task_thread + AOFF_thread_fpsaved, %l6
+		ldub			[%l6 + %o0], %l2
+		sub			%l5, 2, %l5
 
-		wrpr			%l7, PSTATE_IE, %pstate
-		call			fault_in_user_windows
-		 add			%sp, STACK_BIAS + REGWIN_SZ, %o0
-		/* It is OK to leave interrupts on now because if
-		 * fault_in_user_windows has returned it has left us
-		 * with a clean user stack state.
-		 */
-1:
-#if 0
-		call			rtrap_check
-		 add			%sp, STACK_BIAS + REGWIN_SZ, %o0
-#endif
-		ldub			[%g6 + AOFF_task_thread + AOFF_thread_flags], %l5
-		andcc			%l5, SPARC_FLAG_PERFCTR, %g0
-		be,pt			%xcc, 1f
-		 nop
+		add			%g6, AOFF_task_thread + AOFF_thread_gsr, %o1
+		andcc			%l2, (FPRS_FEF|FPRS_DU), %g0
+		be,pt			%icc, 2f
+		 and			%l2, FPRS_DL, %l6
+		andcc			%l2, FPRS_FEF, %g0
+		be,pn			%icc, 5f
+		 sll			%o0, 3, %o5
+		rd			%fprs, %g5
 
-		/* Don't forget to preserve user window invariants. */
-		wrpr			%l7, PSTATE_IE, %pstate
-		call			update_perfctrs
-		 nop
-		wrpr			%l7, 0x0, %pstate
-		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
-		brz,pt			%o2, 1f
-		 sethi			%hi(TSTATE_PEF), %l6
-		wrpr			%l7, PSTATE_IE, %pstate
-		call			fault_in_user_windows
-		 add			%sp, STACK_BIAS + REGWIN_SZ, %o0
+		wr			%g5, FPRS_FEF, %fprs
+		ldub			[%o1 + %o0], %g5
+		add			%g6, AOFF_task_thread + AOFF_thread_xfsr, %o1
+		membar			#StoreLoad | #LoadLoad
+		sll			%o0, 8, %o2
+		add			%g6, AOFF_task_fpregs, %o3
+		brz,pn			%l6, 1f
+		 add			%g6, AOFF_task_fpregs+0x40, %o4
 
-1:
-		andcc			%l1, %l6, %g0
-		be,pt			%xcc, rt_continue
-		 stb			%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
+		ldda			[%o3 + %o2] ASI_BLK_P, %f0
+		ldda			[%o4 + %o2] ASI_BLK_P, %f16
+1:		andcc			%l2, FPRS_DU, %g0
+		be,pn			%icc, 1f
+		 wr			%g5, 0, %gsr
+		add			%o2, 0x80, %o2
+		ldda			[%o3 + %o2] ASI_BLK_P, %f32
+		ldda			[%o4 + %o2] ASI_BLK_P, %f48
 
-		rd			%fprs, %l5
-		andcc			%l5, FPRS_FEF, %g0
-		be,a,pn			%icc, rt_continue
-		 andn			%l1, %l6, %l1
+1:		membar			#Sync
+		ldx			[%o1 + %o5], %fsr
+2:		stb			%l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
 		ba,pt			%xcc, rt_continue
 		 nop
-
 5:		wr			%g0, FPRS_FEF, %fprs
 		membar			#StoreLoad | #LoadLoad
 		sll			%o0, 8, %o2
+
 		add			%g6, AOFF_task_fpregs+0x80, %o3
 		add			%g6, AOFF_task_fpregs+0xc0, %o4
 		ldda			[%o3 + %o2] ASI_BLK_P, %f32
 		ldda			[%o4 + %o2] ASI_BLK_P, %f48
-1:		membar			#Sync
+		membar			#Sync
 		wr			%g0, FPRS_DU, %fprs
 		ba,pt			%xcc, rt_continue
 		 stb			%l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/semaphore.c linux/arch/sparc64/kernel/semaphore.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/semaphore.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/sparc64/kernel/semaphore.c	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: semaphore.c,v 1.2 1999/12/23 17:12:03 jj Exp $
+/* $Id: semaphore.c,v 1.3 2000/03/27 10:38:46 davem Exp $
  *  Generic semaphore code. Buyer beware. Do your own
  * specific changes in <asm/semaphore-helper.h>
  */
@@ -203,7 +203,7 @@
 	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
 
 	for (;;) {
-		if (clear_le_bit(0, &sem->granted))
+		if (test_and_clear_le_bit(0, &sem->granted))
 			break;
 		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 		if (!test_le_bit(0, &sem->granted))
@@ -221,7 +221,7 @@
 	add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
 
 	for (;;) {
-		if (clear_le_bit(1, &sem->granted))
+		if (test_and_clear_le_bit(1, &sem->granted))
 			break;
 		set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
 		if (!test_le_bit(1, &sem->granted))
@@ -286,11 +286,11 @@
 void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
 {
 	if (readers) {
-		if (set_le_bit(0, &sem->granted))
+		if (test_and_set_le_bit(0, &sem->granted))
 			BUG();
 		wake_up(&sem->wait);
 	} else {
-		if (set_le_bit(1, &sem->granted))
+		if (test_and_set_le_bit(1, &sem->granted))
 			BUG();
 		wake_up(&sem->write_bias_wait);
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/signal.c	Wed Dec 29 13:13:14 1999
+++ linux/arch/sparc64/kernel/signal.c	Sun Apr  2 15:53:27 2000
@@ -616,7 +616,9 @@
 		if (map->vm_file != NULL) {
 			dev = map->vm_file->f_dentry->d_inode->i_dev;
 			ino = map->vm_file->f_dentry->d_inode->i_ino;
-			line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+			line = d_path(map->vm_file->f_dentry,
+				      map->vm_file->f_vfsmnt,
+				      buffer, PAGE_SIZE);
 		}
 		printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
 			      kdevname(dev), ino);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/signal32.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/sparc64/kernel/signal32.c	Sun Apr  2 15:53:28 2000
@@ -1279,7 +1279,9 @@
 		if (map->vm_file != NULL) {
 			dev = map->vm_file->f_dentry->d_inode->i_dev;
 			ino = map->vm_file->f_dentry->d_inode->i_ino;
-			line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+			line = d_path(map->vm_file->f_dentry,
+				      map->vm_file->f_vfsmnt,
+				      buffer, PAGE_SIZE);
 		}
 		printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
 			      kdevname(dev), ino);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/smp.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/kernel/smp.c	Thu Mar 30 16:54:53 2000
@@ -469,52 +469,83 @@
  */
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
-	u32 ctx = CTX_HWBITS(mm->context);
-
-	if (mm == current->active_mm &&
-	    atomic_read(&mm->mm_users) == 1 &&
-	    (mm->cpu_vm_mask == (1UL << smp_processor_id())))
-		goto local_flush_and_out;
+	if (CTX_VALID(mm->context)) {
+		u32 ctx = CTX_HWBITS(mm->context);
+		int cpu = smp_processor_id();
+
+		if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) {
+			/* See smp_flush_tlb_page for info about this. */
+			mm->cpu_vm_mask = (1UL << cpu);
+			goto local_flush_and_out;
+		}
 
-	smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+		smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
 
-local_flush_and_out:
-	__flush_tlb_mm(ctx, SECONDARY_CONTEXT);
+	local_flush_and_out:
+		__flush_tlb_mm(ctx, SECONDARY_CONTEXT);
+	}
 }
 
 void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
 			 unsigned long end)
 {
-	u32 ctx = CTX_HWBITS(mm->context);
-
-	start &= PAGE_MASK;
-	end   &= PAGE_MASK;
-	if(mm == current->active_mm &&
-	   atomic_read(&mm->mm_users) == 1 &&
-	   (mm->cpu_vm_mask == (1UL << smp_processor_id())))
-		goto local_flush_and_out;
+	if (CTX_VALID(mm->context)) {
+		u32 ctx = CTX_HWBITS(mm->context);
+		int cpu = smp_processor_id();
+
+		start &= PAGE_MASK;
+		end   &= PAGE_MASK;
+
+		if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) {
+			mm->cpu_vm_mask = (1UL << cpu);
+			goto local_flush_and_out;
+		}
 
-	smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+		smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
 
-local_flush_and_out:
-	__flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start));
+	local_flush_and_out:
+		__flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start));
+	}
 }
 
 void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
 {
-	u32 ctx = CTX_HWBITS(mm->context);
-
-	page &= PAGE_MASK;
-	if(mm == current->active_mm &&
-	   atomic_read(&mm->mm_users) == 1 &&
-	   (mm->cpu_vm_mask == (1UL << smp_processor_id()))) {
-		goto local_flush_and_out;
-	}
+	if (CTX_VALID(mm->context)) {
+		u32 ctx = CTX_HWBITS(mm->context);
+		int cpu = smp_processor_id();
+
+		page &= PAGE_MASK;
+		if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) {
+			/* By virtue of being the current address space, and
+			 * having the only reference to it, the following operation
+			 * is safe.
+			 *
+			 * It would not be a win to perform the xcall tlb flush in
+			 * this case, because even if we switch back to one of the
+			 * other processors in cpu_vm_mask it is almost certain that
+			 * all TLB entries for this context will be replaced by the
+			 * time that happens.
+			 */
+			mm->cpu_vm_mask = (1UL << cpu);
+			goto local_flush_and_out;
+		} else {
+			/* By virtue of running under the mm->page_table_lock,
+			 * and mmu_context.h:switch_mm doing the same, the following
+			 * operation is safe.
+			 */
+			if (mm->cpu_vm_mask == (1UL << cpu))
+				goto local_flush_and_out;
+		}
 
-	smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+		/* OK, we have to actually perform the cross call.  Most likely
+		 * this is a cloned mm or kswapd is kicking out pages for a task
+		 * which has run recently on another cpu.
+		 */
+		smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
 
-local_flush_and_out:
-	__flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
+	local_flush_and_out:
+		__flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
+	}
 }
 
 /* CPU capture. */
@@ -603,13 +634,16 @@
 		extern int rwlock_impl_begin, rwlock_impl_end;
 		extern int atomic_impl_begin, atomic_impl_end;
 		extern int __memcpy_begin, __memcpy_end;
+		extern int __bitops_begin, __bitops_end;
 
 		if ((pc >= (unsigned long) &atomic_impl_begin &&
 		     pc < (unsigned long) &atomic_impl_end) ||
 		    (pc >= (unsigned long) &rwlock_impl_begin &&
 		     pc < (unsigned long) &rwlock_impl_end) ||
 		    (pc >= (unsigned long) &__memcpy_begin &&
-		     pc < (unsigned long) &__memcpy_end))
+		     pc < (unsigned long) &__memcpy_end) ||
+		    (pc >= (unsigned long) &__bitops_begin &&
+		     pc < (unsigned long) &__bitops_end))
 			pc = o7;
 
 		pc -= (unsigned long) &_stext;
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/sparc64_ksyms.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.79 2000/03/17 14:41:18 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.80 2000/03/27 10:38:47 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -169,6 +169,13 @@
 /* Atomic counter implementation. */
 EXPORT_SYMBOL_PRIVATE(atomic_add);
 EXPORT_SYMBOL_PRIVATE(atomic_sub);
+
+/* Atomic bit operations. */
+EXPORT_SYMBOL_PRIVATE(test_and_set_bit);
+EXPORT_SYMBOL_PRIVATE(test_and_clear_bit);
+EXPORT_SYMBOL_PRIVATE(test_and_change_bit);
+EXPORT_SYMBOL_PRIVATE(test_and_set_le_bit);
+EXPORT_SYMBOL_PRIVATE(test_and_clear_le_bit);
 
 EXPORT_SYMBOL(ivector_table);
 EXPORT_SYMBOL(enable_irq);
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/sys32.S linux/arch/sparc64/kernel/sys32.S
--- v2.3.99-pre3/linux/arch/sparc64/kernel/sys32.S	Fri Jan 21 18:19:16 2000
+++ linux/arch/sparc64/kernel/sys32.S	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.11 2000/01/11 17:33:29 jj Exp $
+/* $Id: sys32.S,v 1.12 2000/03/24 04:17:37 davem Exp $
  * sys32.S: I-cache tricks for 32-bit compatability layer simple
  *          conversions.
  *
@@ -6,6 +6,8 @@
  * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
+#include <asm/errno.h>
+
 /* NOTE: call as jump breaks return stack, we have to avoid that */
 
 	.text
@@ -69,3 +71,187 @@
 	srl		%o5, 0, %o5
 	jmpl		%g1 + %lo(sys_mmap), %g0
 	 sllx		%o5, 12, %o5
+
+	.align		32
+	.globl		sys32_socketcall
+sys32_socketcall:	/* %o0=call, %o1=args */
+	cmp		%o0, 1
+	bl,pn		%xcc, do_einval
+	 cmp		%o0, 17
+	bg,pn		%xcc, do_einval
+	 sub		%o0, 1, %o0
+	sllx		%o0, 5, %o0
+	sethi		%hi(__socketcall_table_begin), %g2
+	or		%g2, %lo(__socketcall_table_begin), %g2
+	jmpl		%g2 + %o0, %g0
+	 nop
+
+	/* Each entry is exactly 32 bytes. */
+	.align		32
+__socketcall_table_begin:
+do_sys_socket: /* sys_socket(int, int, int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_socket), %g1
+	ldswa		[%o1 + 0x8] %asi, %o2
+	jmpl		%g1 + %lo(sys_socket), %g0
+	 ldswa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+	nop
+do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_bind), %g1
+	ldswa		[%o1 + 0x8] %asi, %o2
+	jmpl		%g1 + %lo(sys_bind), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+	nop
+do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_connect), %g1
+	ldswa		[%o1 + 0x8] %asi, %o2
+	jmpl		%g1 + %lo(sys_connect), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+	nop
+do_sys_listen: /* sys_listen(int, int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_listen), %g1
+	jmpl		%g1 + %lo(sys_listen), %g0
+	 ldswa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+	nop
+	nop
+do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_accept), %g1
+	lduwa		[%o1 + 0x8] %asi, %o2
+	jmpl		%g1 + %lo(sys_accept), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+	nop
+do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_getsockname), %g1
+	lduwa		[%o1 + 0x8] %asi, %o2
+	jmpl		%g1 + %lo(sys_getsockname), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+	nop
+do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_getpeername), %g1
+	lduwa		[%o1 + 0x8] %asi, %o2
+	jmpl		%g1 + %lo(sys_getpeername), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+	nop
+do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_socketpair), %g1
+	ldswa		[%o1 + 0x8] %asi, %o2
+	lduwa		[%o1 + 0xc] %asi, %o3
+	jmpl		%g1 + %lo(sys_socketpair), %g0
+	 ldswa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_send), %g1
+	lduwa		[%o1 + 0x8] %asi, %o2
+	lduwa		[%o1 + 0xc] %asi, %o3
+	jmpl		%g1 + %lo(sys_send), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_recv), %g1
+	lduwa		[%o1 + 0x8] %asi, %o2
+	lduwa		[%o1 + 0xc] %asi, %o3
+	jmpl		%g1 + %lo(sys_recv), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+do_sys_sendto: /* sys32_sendto(int, u32, __kernel_size_t32, unsigned int, u32, int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys32_sendto), %g1
+	lduwa		[%o1 + 0x8] %asi, %o2
+	lduwa		[%o1 + 0xc] %asi, %o3
+	lduwa		[%o1 + 0x10] %asi, %o4
+	ldswa		[%o1 + 0x14] %asi, %o5
+	jmpl		%g1 + %lo(sys32_sendto), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+do_sys_recvfrom: /* sys32_recvfrom(int, u32, __kernel_size_t32, unsigned int, u32, u32) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys32_recvfrom), %g1
+	lduwa		[%o1 + 0x8] %asi, %o2
+	lduwa		[%o1 + 0xc] %asi, %o3
+	lduwa		[%o1 + 0x10] %asi, %o4
+	lduwa		[%o1 + 0x14] %asi, %o5
+	jmpl		%g1 + %lo(sys32_recvfrom), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+do_sys_shutdown: /* sys_shutdown(int, int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys_shutdown), %g1
+	jmpl		%g1 + %lo(sys_shutdown), %g0
+	 ldswa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+	nop
+	nop
+do_sys_setsockopt: /* sys32_setsockopt(int, int, int, char *, int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys32_setsockopt), %g1
+	ldswa		[%o1 + 0x8] %asi, %o2
+	lduwa		[%o1 + 0xc] %asi, %o3
+	ldswa		[%o1 + 0x10] %asi, %o4
+	jmpl		%g1 + %lo(sys32_setsockopt), %g0
+	 ldswa		[%o1 + 0x4] %asi, %o1
+	nop
+do_sys_getsockopt: /* sys32_getsockopt(int, int, int, u32, u32) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys32_getsockopt), %g1
+	ldswa		[%o1 + 0x8] %asi, %o2
+	lduwa		[%o1 + 0xc] %asi, %o3
+	lduwa		[%o1 + 0x10] %asi, %o4
+	jmpl		%g1 + %lo(sys32_getsockopt), %g0
+	 ldswa		[%o1 + 0x4] %asi, %o1
+	nop
+do_sys_sendmsg: /* sys32_sendmsg(int, struct msghdr32 *, unsigned int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys32_sendmsg), %g1
+	lduwa		[%o1 + 0x8] %asi, %o2
+	jmpl		%g1 + %lo(sys32_sendmsg), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+	nop
+do_sys_recvmsg: /* sys32_recvmsg(int, struct msghdr32 *, unsigned int) */
+	ldswa		[%o1 + 0x0] %asi, %o0
+	sethi		%hi(sys32_recvmsg), %g1
+	lduwa		[%o1 + 0x8] %asi, %o2
+	jmpl		%g1 + %lo(sys32_recvmsg), %g0
+	 lduwa		[%o1 + 0x4] %asi, %o1
+	nop
+	nop
+	nop
+__socketcall_table_end:
+
+do_einval:
+	retl
+	 mov		-EINVAL, %o0
+do_efault:
+	retl
+	 mov		-EFAULT, %o0
+
+	.section	__ex_table
+	.align		4
+	.word		__socketcall_table_begin, 0, __socketcall_table_end, do_efault
+	.previous
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/sys_sparc32.c	Mon Mar 27 08:08:22 2000
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Sun Apr  2 15:49:08 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.141 2000/03/24 01:31:30 davem Exp $
+/* $Id: sys_sparc32.c,v 1.142 2000/03/24 04:17:38 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -1746,8 +1746,8 @@
 	return 0;
 }
 
-extern long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page,
-			 unsigned long new_flags, unsigned long data_page);
+extern long do_sys_mount(char * dev_page, char * dir_page, char * type_page,
+			 unsigned long new_flags, char * data_page);
 
 #define SMBFS_NAME	"smbfs"
 #define NCPFS_NAME	"ncpfs"
@@ -1756,6 +1756,8 @@
 {
 	unsigned long type_page = 0;
 	unsigned long data_page = 0;
+	unsigned long dev_page = 0;
+	unsigned long dir_page = 0;
 	int err, is_smb, is_ncp;
 
 	is_smb = is_ncp = 0;
@@ -1777,19 +1779,32 @@
 	if (err)
 		goto type_out;
 
+	err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
+	if (err)
+		goto data_out;
+
+	err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
+	if (err)
+		goto dev_out;
+
 	if (!is_smb && !is_ncp) {
-		err = do_sys_mount(dev_name, dir_name, type_page, new_flags,
-				   data_page);
+		err = do_sys_mount((char*)dev_page, (char*)dir_page,
+				(char*)type_page, new_flags, (char*)data_page);
 	} else {
 		if (is_ncp)
 			do_ncp_super_data_conv((void *)data_page);
 		else
 			do_smb_super_data_conv((void *)data_page);
 
-		err = do_sys_mount(dev_name, dir_name, type_page, new_flags,
-				   data_page);
+		err = do_sys_mount((char*)dev_page, (char*)dir_page,
+				(char*)type_page, new_flags, (char*)data_page);
 	}
+	free_page(dir_page);
+
+dev_out:
+	free_page(dev_page);
 
+data_out:
 	free_page(data_page);
 
 type_out:
@@ -2790,85 +2805,6 @@
 	return sys_setsockopt(fd, level, optname, optval, optlen);
 }
 
-/* Argument list sizes for sys_socketcall */
-#define AL(x) ((x) * sizeof(u32))
-static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
-                                AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
-                                AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
-#undef AL
-
-extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
-extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
-extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen);
-extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
-extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
-extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags);
-extern asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len,
-				   unsigned flags, u32 addr, int addr_len);
-extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
-extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
-				     unsigned flags, u32 addr, u32 addr_len);
-extern asmlinkage int sys32_getsockopt(int fd, int level, int optname,
-				       u32 optval, u32 optlen);
-
-extern asmlinkage int sys_socket(int family, int type, int protocol);
-extern asmlinkage int sys_socketpair(int family, int type, int protocol,
-				     int usockvec[2]);
-extern asmlinkage int sys_shutdown(int fd, int how);
-extern asmlinkage int sys_listen(int fd, int backlog);
-
-asmlinkage int sys32_socketcall(int call, u32 *args)
-{
-	u32 a[6];
-	u32 a0,a1;
-				 
-	if (call<SYS_SOCKET||call>SYS_RECVMSG)
-		return -EINVAL;
-	if (copy_from_user(a, args, nargs[call]))
-		return -EFAULT;
-	a0=a[0];
-	a1=a[1];
-	
-	switch(call) 
-	{
-		case SYS_SOCKET:
-			return sys_socket(a0, a1, a[2]);
-		case SYS_BIND:
-			return sys_bind(a0, (struct sockaddr *)A(a1), a[2]);
-		case SYS_CONNECT:
-			return sys_connect(a0, (struct sockaddr *)A(a1), a[2]);
-		case SYS_LISTEN:
-			return sys_listen(a0, a1);
-		case SYS_ACCEPT:
-			return sys_accept(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
-		case SYS_GETSOCKNAME:
-			return sys_getsockname(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
-		case SYS_GETPEERNAME:
-			return sys_getpeername(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
-		case SYS_SOCKETPAIR:
-			return sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
-		case SYS_SEND:
-			return sys_send(a0, (void *)A(a1), a[2], a[3]);
-		case SYS_SENDTO:
-			return sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]);
-		case SYS_RECV:
-			return sys_recv(a0, (void *)A(a1), a[2], a[3]);
-		case SYS_RECVFROM:
-			return sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
-		case SYS_SHUTDOWN:
-			return sys_shutdown(a0,a1);
-		case SYS_SETSOCKOPT:
-			return sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]);
-		case SYS_GETSOCKOPT:
-			return sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
-		case SYS_SENDMSG:
-			return sys32_sendmsg(a0, (struct msghdr32 *)A(a1), a[2]);
-		case SYS_RECVMSG:
-			return sys32_recvmsg(a0, (struct msghdr32 *)A(a1), a[2]);
-	}
-	return -EINVAL;
-}
-
 extern void check_pending(int signum);
 
 asmlinkage int sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
@@ -4144,7 +4080,7 @@
 		if (fd >= 0) {
 			struct file * f;
 			lock_kernel();
-			f = filp_open(tmp, flags, mode, NULL);
+			f = filp_open(tmp, flags, mode);
 			unlock_kernel();
 			error = PTR_ERR(f);
 			if (IS_ERR(f))
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.99-pre3/linux/arch/sparc64/kernel/sys_sunos32.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Sun Apr  2 15:53:28 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.42 2000/03/15 02:43:35 davem Exp $
+/* $Id: sys_sunos32.c,v 1.43 2000/03/26 11:28:53 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -79,19 +79,17 @@
 	}
 	retval = -EBADF;
 	if(!(flags & MAP_ANONYMOUS)) {
+		struct inode * inode;
 		if(fd >= SUNOS_NR_OPEN)
 			goto out;
  		file = fget(fd);
 		if (!file)
 			goto out;
-		if (file->f_dentry && file->f_dentry->d_inode) {
-			struct inode * inode = file->f_dentry->d_inode;
-			if(MAJOR(inode->i_rdev) == MEM_MAJOR &&
-			   MINOR(inode->i_rdev) == 5) {
-				flags |= MAP_ANONYMOUS;
-				fput(file);
-				file = NULL;
-			}
+		inode = file->f_dentry->d_inode;
+		if(MAJOR(inode->i_rdev)==MEM_MAJOR && MINOR(inode->i_rdev)==5) {
+			flags |= MAP_ANONYMOUS;
+			fput(file);
+			file = NULL;
 		}
 	}
 
@@ -601,7 +599,7 @@
 	char       *netname;   /* server's netname */
 };
 
-extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
+extern long do_sys_mount(const char *, const char *, char *, int, void *);
 extern dev_t get_unnamed_dev(void);
 extern void put_unnamed_dev(dev_t);
 extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
@@ -627,17 +625,12 @@
 	struct inode  *inode;
 	struct file   *file;
 
-	file = fcheck(fd);
+	file = fget(fd);
 	if(!file)
 		return 0;
 
 	dentry = file->f_dentry;
-	if(!dentry)
-		return 0;
-
 	inode = dentry->d_inode;
-	if(!inode)
-		return 0;
 
 	socket = &inode->u.socket_i;
 	local.sin_family = AF_INET;
@@ -651,8 +644,10 @@
 					sizeof(local));
 	} while (ret && try_port > (1024 / 2));
 
-	if (ret)
+	if (ret) {
+		fput(file);
 		return 0;
+	}
 
 	server.sin_family = AF_INET;
 	server.sin_addr = addr->sin_addr;
@@ -661,6 +656,7 @@
 	/* Call sys_connect */
 	ret = socket->ops->connect (socket, (struct sockaddr *) &server,
 				    sizeof (server), file->f_flags);
+	fput(file);
 	if (ret < 0)
 		return 0;
 	return 1;
@@ -676,12 +672,12 @@
 }
 
 /* XXXXXXXXXXXXXXXXXXXX */
-asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
+static int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
 {
 	int  server_fd;
 	char *the_name;
 	struct nfs_mount_data linux_nfs_mount;
-	struct sunos_nfs_mount_args *sunos_mount = data;
+	struct sunos_nfs_mount_args sunos_mount;
 
 	/* Ok, here comes the fun part: Linux's nfs mount needs a
 	 * socket connection to the server, but SunOS mount does not
@@ -689,41 +685,50 @@
 	 * address to create a socket and bind it to a reserved
 	 * port on this system
 	 */
+	if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount))
+		return -EFAULT;
+
 	server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 	if (server_fd < 0)
 		return -ENXIO;
 
-	if (!sunos_nfs_get_server_fd (server_fd, sunos_mount->addr)){
+	if (copy_from_user(&linux_nfs_mount.addr,sunos_mount.addr,
+				sizeof(*sunos_mount.addr)) ||
+	    copy_from_user(&linux_nfs_mount.root,sunos_mount.fh,
+				sizeof(*sunos_mount.fh))) {
+		sys_close (server_fd);
+		return -EFAULT;
+	}
+
+	if (!sunos_nfs_get_server_fd (server_fd, &linux_nfs_mount.addr)){
 		sys_close (server_fd);
 		return -ENXIO;
 	}
 
 	/* Now, bind it to a locally reserved port */
 	linux_nfs_mount.version  = NFS_MOUNT_VERSION;
-	linux_nfs_mount.flags    = sunos_mount->flags;
-	linux_nfs_mount.addr     = *sunos_mount->addr;
-	linux_nfs_mount.root     = *sunos_mount->fh;
+	linux_nfs_mount.flags    = sunos_mount.flags;
 	linux_nfs_mount.fd       = server_fd;
 	
-	linux_nfs_mount.rsize    = get_default (sunos_mount->rsize, 8192);
-	linux_nfs_mount.wsize    = get_default (sunos_mount->wsize, 8192);
-	linux_nfs_mount.timeo    = get_default (sunos_mount->timeo, 10);
-	linux_nfs_mount.retrans  = sunos_mount->retrans;
+	linux_nfs_mount.rsize    = get_default (sunos_mount.rsize, 8192);
+	linux_nfs_mount.wsize    = get_default (sunos_mount.wsize, 8192);
+	linux_nfs_mount.timeo    = get_default (sunos_mount.timeo, 10);
+	linux_nfs_mount.retrans  = sunos_mount.retrans;
 	
-	linux_nfs_mount.acregmin = sunos_mount->acregmin;
-	linux_nfs_mount.acregmax = sunos_mount->acregmax;
-	linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
-	linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
+	linux_nfs_mount.acregmin = sunos_mount.acregmin;
+	linux_nfs_mount.acregmax = sunos_mount.acregmax;
+	linux_nfs_mount.acdirmin = sunos_mount.acdirmin;
+	linux_nfs_mount.acdirmax = sunos_mount.acdirmax;
 
-	the_name = getname(sunos_mount->hostname);
+	the_name = getname(sunos_mount.hostname);
 	if(IS_ERR(the_name))
-		return -EFAULT;
+		return PTR_ERR(the_name);
 
 	strncpy (linux_nfs_mount.hostname, the_name, 254);
 	linux_nfs_mount.hostname [255] = 0;
 	putname (the_name);
-
-	return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
+	
+	return do_sys_mount ("", dir_name, "nfs", linux_flags, &linux_nfs_mount);
 }
 
 /* XXXXXXXXXXXXXXXXXXXX */
@@ -733,6 +738,7 @@
 	int linux_flags = MS_MGC_MSK; /* new semantics */
 	int ret = -EINVAL;
 	char *dev_fname = 0;
+	char *dir_page, *type_page;
 
 	if (!capable (CAP_SYS_ADMIN))
 		return -EPERM;
@@ -751,24 +757,44 @@
 		linux_flags |= MS_RDONLY;
 	if(flags & SMNT_NOSUID)
 		linux_flags |= MS_NOSUID;
-	if(strcmp(type, "ext2") == 0) {
-		dev_fname = (char *) data;
-	} else if(strcmp(type, "iso9660") == 0) {
-		dev_fname = (char *) data;
-	} else if(strcmp(type, "minix") == 0) {
-		dev_fname = (char *) data;
-	} else if(strcmp(type, "nfs") == 0) {
-		ret = sunos_nfs_mount (dir, flags, data);
-		goto out;
-        } else if(strcmp(type, "ufs") == 0) {
+
+	dir_page = getname(dir);
+	ret = PTR_ERR(dir_page);
+	if (IS_ERR(dir_page))
+		goto out;
+
+	type_page = getname(type);
+	ret = PTR_ERR(type_page);
+	if (IS_ERR(type_page))
+		goto out1;
+
+	if(strcmp(type_page, "ext2") == 0) {
+		dev_fname = getname(data);
+	} else if(strcmp(type_page, "iso9660") == 0) {
+		dev_fname = getname(data);
+	} else if(strcmp(type_page, "minix") == 0) {
+		dev_fname = getname(data);
+	} else if(strcmp(type_page, "nfs") == 0) {
+		ret = sunos_nfs_mount (dir_page, flags, data);
+		goto out2
+        } else if(strcmp(type_page, "ufs") == 0) {
 		printk("Warning: UFS filesystem mounts unsupported.\n");
 		ret = -ENODEV;
-		goto out;
-	} else if(strcmp(type, "proc")) {
+		goto out2
+	} else if(strcmp(type_page, "proc")) {
 		ret = -ENODEV;
-		goto out;
+		goto out2
 	}
-	ret = sys_mount(dev_fname, dir, type, linux_flags, NULL);
+	ret = PTR_ERR(dev_fname);
+	if (IS_ERR(dev_fname))
+		goto out2;
+	ret = do_sys_mount(dev_fname, dir_page, type_page, linux_flags, NULL);
+	if (dev_fname)
+		putname(dev_fname);
+out2:
+	putname(type_page);
+out1:
+	putname(dir_page);
 out:
 	unlock_kernel();
 	return ret;
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/kernel/winfixup.S linux/arch/sparc64/kernel/winfixup.S
--- v2.3.99-pre3/linux/arch/sparc64/kernel/winfixup.S	Mon Aug  2 22:07:16 1999
+++ linux/arch/sparc64/kernel/winfixup.S	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.28 1999/07/30 09:35:34 davem Exp $
+/* $Id: winfixup.S,v 1.29 2000/03/26 09:13:48 davem Exp $
  *
  * winfixup.S: Handle cases where user stack pointer is found to be bogus.
  *
@@ -31,7 +31,7 @@
 fill_fixup:
 	rdpr		%tstate, %g1
 	andcc		%g1, TSTATE_PRIV, %g0
-	clr		%g4
+	or		%g4, FAULT_CODE_WINFIXUP, %g4
 	be,pt		%xcc, window_scheisse_from_user_common
 	 and		%g1, TSTATE_CWP, %g1
 
@@ -69,21 +69,20 @@
 	mov		%g6, %o7			! Get current.
 
 	andn		%l1, PSTATE_MM, %l1		! We want to be in RMO
-	srlx		%g5, PAGE_SHIFT, %o1		! Fault address
+	stb		%g4, [%g6 + AOFF_task_thread + AOFF_thread_fault_code]
+	stx		%g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
 	wrpr		%g0, 0x0, %tl			! Out of trap levels.
 	wrpr		%l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
 	sethi		%uhi(PAGE_OFFSET), %g4		! Prepare page_offset global reg
 	mov		%o7, %g6
 	sllx		%g4, 32, %g4			! and finish it...
-	clr		%o2
 
 	/* This is the same as below, except we handle this a bit special
 	 * since we must preserve %l5 and %l6, see comment above.
 	 */
-	sllx		%o1, PAGE_SHIFT, %o1
 	call		do_sparc64_fault
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
-	b,pt		%xcc, rtrap
+	ba,pt		%xcc, rtrap
 	 nop						! yes, nop is correct
 
 	/* Be very careful about usage of the alternate globals here.
@@ -149,22 +148,19 @@
 	andcc		%g1, TSTATE_PRIV, %g0
 	saved
 	and		%g1, TSTATE_CWP, %g1
-	be,a,pn		%xcc, window_scheisse_from_user_common
-	 or		%g4, 0x4, %g4			! we know it was a write
+	be,pn		%xcc, window_scheisse_from_user_common
+	 mov		FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4
 	retry
+
 window_scheisse_from_user_common:
+	stb		%g4, [%g6 + AOFF_task_thread + AOFF_thread_fault_code]
+	stx		%g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
 	wrpr		%g1, %cwp
-	sethi		%hi(109f), %g7
 	ba,pt		%xcc, etrap
-109:	 or		%g7, %lo(109b), %g7
-	srlx		%l5, PAGE_SHIFT, %o1
-
-	and		%l4, 0x4, %o2
-	sllx		%o1, PAGE_SHIFT, %o1
+	 rd		%pc, %g7
 	call		do_sparc64_fault
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
-	ba,pt		%xcc, rtrap
-	 clr		%l6
+	ba,a,pt		%xcc, rtrap_clr_l6
 
 	.globl		winfix_mna, fill_fixup_mna, spill_fixup_mna
 winfix_mna:
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile
--- v2.3.99-pre3/linux/arch/sparc64/lib/Makefile	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/lib/Makefile	Thu Mar 30 16:56:04 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.20 2000/01/19 04:06:03 davem Exp $
+# $Id: Makefile,v 1.21 2000/03/27 10:38:41 davem Exp $
 # Makefile for Sparc library files..
 #
 
@@ -7,7 +7,7 @@
 OBJS  = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \
 	memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
 	VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \
-	VIScsumcopyusr.o VISsave.o atomic.o rwlock.o
+	VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o
 
 lib.a: $(OBJS)
 	$(AR) rcs lib.a $(OBJS)
@@ -17,10 +17,10 @@
 VISbzero.o: VISbzero.S VIS.h
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+	$(CPP) $(AFLAGS) -ansi $< -o $*.s
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+	$(CC) $(AFLAGS) -ansi -c $< -o $*.o
 
 dep:
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/lib/VIScopy.S linux/arch/sparc64/lib/VIScopy.S
--- v2.3.99-pre3/linux/arch/sparc64/lib/VIScopy.S	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/lib/VIScopy.S	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.22 2000/03/16 16:44:38 davem Exp $
+/* $Id: VIScopy.S,v 1.23 2000/03/26 09:13:49 davem Exp $
  * VIScopy.S: High speed copy operations utilizing the UltraSparc
  *            Visual Instruction Set.
  *
@@ -135,11 +135,11 @@
 #define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt)	\
 	EXVIS(LDBLK		[%src] ASIBLK, %fdest);		\
 	ASI_SETDST_BLK						\
+	EXVIS2(STBLK		%fsrc, [%dest] ASIBLK);		\
 	add			%src, 0x40, %src;		\
-	add			%dest, 0x40, %dest;		\
 	subcc			%len, 0x40, %len;		\
 	be,pn			%xcc, jmptgt;			\
-	 EXVIS2(STBLK		%fsrc, [%dest - 0x40] ASIBLK);	\
+	 add			%dest, 0x40, %dest;		\
 	ASI_SETSRC_BLK
 
 #define LOOP_CHUNK1(src, dest, len, branch_dest)		\
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/lib/bitops.S linux/arch/sparc64/lib/bitops.S
--- v2.3.99-pre3/linux/arch/sparc64/lib/bitops.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/lib/bitops.S	Thu Mar 30 16:54:53 2000
@@ -0,0 +1,110 @@
+/* $Id: bitops.S,v 1.1 2000/03/27 10:38:41 davem Exp $
+ * bitops.S: Sparc64 atomic bit operations.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/asi.h>
+
+	.text
+	.align	64
+	.globl	__bitops_begin
+__bitops_begin:
+
+	.globl	__test_and_set_bit
+__test_and_set_bit:	/* %o0=nr, %o1=addr */
+	srlx	%o0, 6, %g1
+	mov	1, %g5
+	sllx	%g1, 3, %g3
+	and	%o0, 63, %g2
+	sllx	%g5, %g2, %g5
+	add	%o1, %g3, %o1
+	ldx	[%o1], %g7
+1:	andcc	%g7, %g5, %o0
+	bne,pn	%xcc, 2f
+	 xor	%g7, %g5, %g1
+	casx	[%o1], %g7, %g1
+	cmp	%g7, %g1
+	bne,a,pn %xcc, 1b
+	 ldx	[%o1], %g7
+2:	retl
+	 nop
+
+	.globl	__test_and_clear_bit
+__test_and_clear_bit:	/* %o0=nr, %o1=addr */
+	srlx	%o0, 6, %g1
+	mov	1, %g5
+	sllx	%g1, 3, %g3
+	and	%o0, 63, %g2
+	sllx	%g5, %g2, %g5
+	add	%o1, %g3, %o1
+	ldx	[%o1], %g7
+1:	andcc	%g7, %g5, %o0
+	be,pn	%xcc, 2f
+	 xor	%g7, %g5, %g1
+	casx	[%o1], %g7, %g1
+	cmp	%g7, %g1
+	bne,a,pn %xcc, 1b
+	 ldx	[%o1], %g7
+2:	retl
+	 nop
+
+	.globl	__test_and_change_bit
+__test_and_change_bit:	/* %o0=nr, %o1=addr */
+	srlx	%o0, 6, %g1
+	mov	1, %g5
+	sllx	%g1, 3, %g3
+	and	%o0, 63, %g2
+	sllx	%g5, %g2, %g5
+	add	%o1, %g3, %o1
+	ldx	[%o1], %g7
+1:	and	%g7, %g5, %o0
+	xor	%g7, %g5, %g1
+	casx	[%o1], %g7, %g1
+	cmp	%g7, %g1
+	bne,a,pn %xcc, 1b
+	 ldx	[%o1], %g7
+2:	retl
+	 nop
+	nop
+
+	.globl	__test_and_set_le_bit
+__test_and_set_le_bit:	/* %o0=nr, %o1=addr */
+	srlx	%o0, 5, %g1
+	mov	1, %g5
+	sllx	%g1, 2, %g3
+	and	%o0, 31, %g2
+	sllx	%g5, %g2, %g5
+	add	%o1, %g3, %o1
+	lduwa	[%o1] ASI_PL, %g7
+1:	andcc	%g7, %g5, %o0
+	bne,pn	%icc, 2f
+	 xor	%g7, %g5, %g1
+	casa	[%o1] ASI_PL, %g7, %g1
+	cmp	%g7, %g1
+	bne,a,pn %icc, 1b
+	 lduwa	[%o1] ASI_PL, %g7
+2:	retl
+	 nop
+
+	.globl	__test_and_clear_le_bit
+__test_and_clear_le_bit:	/* %o0=nr, %o1=addr */
+	srlx	%o0, 5, %g1
+	mov	1, %g5
+	sllx	%g1, 2, %g3
+	and	%o0, 31, %g2
+	sllx	%g5, %g2, %g5
+	add	%o1, %g3, %o1
+	lduwa	[%o1] ASI_PL, %g7
+1:	andcc	%g7, %g5, %o0
+	be,pn	%icc, 2f
+	 xor	%g7, %g5, %g1
+	casa	[%o1] ASI_PL, %g7, %g1
+	cmp	%g7, %g1
+	bne,a,pn %icc, 1b
+	 lduwa	[%o1] ASI_PL, %g7
+2:	retl
+	 nop
+
+	.globl	__bitops_end
+__bitops_end:
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- v2.3.99-pre3/linux/arch/sparc64/lib/blockops.S	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/lib/blockops.S	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.22 2000/03/15 07:18:55 davem Exp $
+/* $Id: blockops.S,v 1.24 2000/03/27 10:38:41 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com)
@@ -38,21 +38,21 @@
 	sethi		%hi(8192), %o2
 1:	TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
 	ldda		[%o1] ASI_BLK_P, %f32
+	stda		%f48, [%o0] ASI_BLK_P
 	add		%o1, 0x40, %o1
 	sub		%o2, 0x40, %o2
-	stda		%f48, [%o0] ASI_BLK_P
 	add		%o0, 0x40, %o0
 	TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
 	ldda		[%o1] ASI_BLK_P, %f0
+	stda		%f48, [%o0] ASI_BLK_P
 	add		%o1, 0x40, %o1
 	sub		%o2, 0x40, %o2
-	stda		%f48, [%o0] ASI_BLK_P
 	add		%o0, 0x40, %o0
 	TOUCH(f32, f34, f36, f38, f40, f42, f44, f46)
 	ldda		[%o1] ASI_BLK_P, %f16
-	add		%o1, 0x40, %o1
-	sub		%o2, 0x40, %o2
 	stda		%f48, [%o0] ASI_BLK_P
+	sub		%o2, 0x40, %o2
+	add		%o1, 0x40, %o1
 	cmp		%o2, 0x80
 	bne,pt		%xcc, 1b
 	 add		%o0, 0x40, %o0
@@ -122,7 +122,11 @@
 	stxa		%g2, [%o3] ASI_DTLB_DATA_ACCESS
 	membar		#Sync
 
-	membar		#LoadStore | #StoreStore | #StoreLoad
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_use_blkcommit], %g2
+	cmp		%g2, 0
+	bne,pn		%xcc, copy_page_using_blkcommit
+	 nop
+
 	ldda		[%o1] ASI_BLK_P, %f0
 	add		%o1, 0x40, %o1
 	ldda		[%o1] ASI_BLK_P, %f16
@@ -130,21 +134,21 @@
 	sethi		%hi(8192), %o2
 1:	TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
 	ldda		[%o1] ASI_BLK_P, %f32
+	stda		%f48, [%o0] ASI_BLK_P
 	add		%o1, 0x40, %o1
 	sub		%o2, 0x40, %o2
-	stda		%f48, [%o0] ASI_BLK_P
 	add		%o0, 0x40, %o0
 	TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
 	ldda		[%o1] ASI_BLK_P, %f0
+	stda		%f48, [%o0] ASI_BLK_P
 	add		%o1, 0x40, %o1
 	sub		%o2, 0x40, %o2
-	stda		%f48, [%o0] ASI_BLK_P
 	add		%o0, 0x40, %o0
 	TOUCH(f32, f34, f36, f38, f40, f42, f44, f46)
 	ldda		[%o1] ASI_BLK_P, %f16
-	add		%o1, 0x40, %o1
-	sub		%o2, 0x40, %o2
 	stda		%f48, [%o0] ASI_BLK_P
+	sub		%o2, 0x40, %o2
+	add		%o1, 0x40, %o1
 	cmp		%o2, 0x80
 	bne,pt		%xcc, 1b
 	 add		%o0, 0x40, %o0
@@ -152,6 +156,7 @@
 	stda		%f0, [%o0] ASI_BLK_P
 	add		%o0, 0x40, %o0
 	stda		%f16, [%o0] ASI_BLK_P
+copy_user_page_continue:
 	membar		#Sync
 	VISExit
 
@@ -166,6 +171,39 @@
 	jmpl		%o7 + 0x8, %g0
 	 wrpr		%g3, 0x0, %pstate
 
+copy_page_using_blkcommit:
+	membar		#LoadStore | #StoreStore | #StoreLoad
+	ldda		[%o1] ASI_BLK_P, %f0
+	add		%o1, 0x40, %o1
+	ldda		[%o1] ASI_BLK_P, %f16
+	add		%o1, 0x40, %o1
+	sethi		%hi(8192), %o2
+1:	TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
+	ldda		[%o1] ASI_BLK_P, %f32
+	stda		%f48, [%o0] ASI_BLK_COMMIT_P
+	add		%o1, 0x40, %o1
+	sub		%o2, 0x40, %o2
+	add		%o0, 0x40, %o0
+	TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
+	ldda		[%o1] ASI_BLK_P, %f0
+	stda		%f48, [%o0] ASI_BLK_COMMIT_P
+	add		%o1, 0x40, %o1
+	sub		%o2, 0x40, %o2
+	add		%o0, 0x40, %o0
+	TOUCH(f32, f34, f36, f38, f40, f42, f44, f46)
+	ldda		[%o1] ASI_BLK_P, %f16
+	stda		%f48, [%o0] ASI_BLK_COMMIT_P
+	sub		%o2, 0x40, %o2
+	add		%o1, 0x40, %o1
+	cmp		%o2, 0x80
+	bne,pt		%xcc, 1b
+	 add		%o0, 0x40, %o0
+	membar		#Sync
+	stda		%f0, [%o0] ASI_BLK_COMMIT_P
+	add		%o0, 0x40, %o0
+	ba,pt		%xcc, copy_user_page_continue
+	 stda		%f16, [%o0] ASI_BLK_COMMIT_P
+
 	.align		32
 	.globl		clear_page
 	.type		clear_page,@function
@@ -213,6 +251,7 @@
 	mov		1, %o4
 
 clear_page_common:
+	membar		#StoreLoad | #StoreStore | #LoadStore	! LSU	Group
 	fzero		%f0				! FPA	Group
 	mov		32, %o1				! IEU0
 	fzero		%f2				! FPA	Group
@@ -223,7 +262,6 @@
 
 	faddd		%f0, %f2, %f12			! FPA	Group
 	fmuld		%f0, %f2, %f14			! FPM
-	membar		#StoreLoad | #StoreStore | #LoadStore	! LSU	Group
 1:	stda		%f0, [%o0 + %g0] ASI_BLK_P	! Store	Group
 	add		%o0, 0x40, %o0			! IEU0
 	stda		%f0, [%o0 + %g0] ASI_BLK_P	! Store	Group
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/mm/Makefile linux/arch/sparc64/mm/Makefile
--- v2.3.99-pre3/linux/arch/sparc64/mm/Makefile	Tue Feb  1 01:35:43 2000
+++ linux/arch/sparc64/mm/Makefile	Thu Mar 30 16:56:04 2000
@@ -8,10 +8,10 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+	$(CPP) $(AFLAGS) -ansi $< -o $*.s
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+	$(CC) $(AFLAGS) -ansi -c $< -o $*.o
 
 O_TARGET := mm.o
 O_OBJS   := ultra.o fault.o init.o generic.o extable.o modutil.o
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.3.99-pre3/linux/arch/sparc64/mm/fault.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/mm/fault.c	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.43 2000/03/14 03:59:46 davem Exp $
+/* $Id: fault.c,v 1.45 2000/03/27 10:38:51 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -92,162 +92,211 @@
 	die_if_kernel("Oops", regs);
 }
 
-/* #define DEBUG_EXCEPTIONS */
-/* #define DEBUG_LOCKUPS */
-
-/* #define INSN_VPTE_LOOKUP */
-
-static inline u32 get_user_insn(unsigned long tpc)
+static unsigned int get_user_insn(unsigned long tpc)
 {
-	u32 insn;
-#ifndef INSN_VPTE_LOOKUP
 	pgd_t *pgdp = pgd_offset(current->mm, tpc);
 	pmd_t *pmdp;
-	pte_t *ptep;
+	pte_t *ptep, pte;
+	unsigned long pa;
+	u32 insn = 0;
 
 	if(pgd_none(*pgdp))
-		return 0;
+		goto out;
 	pmdp = pmd_offset(pgdp, tpc);
 	if(pmd_none(*pmdp))
-		return 0;
+		goto out;
 	ptep = pte_offset(pmdp, tpc);
-	if(!pte_present(*ptep))
-		return 0;
-	insn = *(unsigned int *)
-		((unsigned long)__va(pte_pagenr(*ptep) << PAGE_SHIFT) +
-		 (tpc & ~PAGE_MASK));
-#else
-	register unsigned long pte asm("l1");
-
-	/* So that we don't pollute TLB, we read the instruction
-	 * using PHYS bypass. For that, we of course need
-	 * to know its page table entry. Do this by simulating
-	 * dtlb_miss handler. -jj */
-	pte = ((((long)tpc) >> (PAGE_SHIFT-3)) & ~7);
-	asm volatile ("
-		rdpr    %%pstate, %%l0
-		wrpr    %%l0, %2, %%pstate
-		wrpr    %%g0, 1, %%tl
-		mov	%%l1, %%g6
-		ldxa    [%%g3 + %%l1] %3, %%g5
-		mov     %%g5, %%l1
-		wrpr    %%g0, 0, %%tl
-		wrpr    %%l0, 0, %%pstate
-	" : "=r" (pte) : "0" (pte), "i" (PSTATE_MG|PSTATE_IE), "i" (ASI_S) : "l0");
-			
-	if ((long)pte >= 0) return 0;
-
-	pte = (pte & _PAGE_PADDR) + (tpc & ~PAGE_MASK);
-	asm ("lduwa	[%1] %2, %0" : "=r" (insn) : "r" (pte), "i" (ASI_PHYS_USE_EC));
-#endif
+	pte = *ptep;
+	if(!pte_present(pte))
+		goto out;
+
+	pa = (pte_pagenr(pte) << PAGE_SHIFT) + (tpc & ~PAGE_MASK);
+
+	/* Use phys bypass so we don't pollute dtlb/dcache. */
+	__asm__ __volatile__("lduwa [%1] %2, %0"
+			     : "=r" (insn)
+			     : "r" (pa), "i" (ASI_PHYS_USE_EC));
 
+out:
 	return insn;
 }
 
-asmlinkage void do_sparc64_fault(struct pt_regs *regs, unsigned long address, int write)
+static void do_fault_siginfo(int code, int sig, unsigned long address)
+{
+	siginfo_t info;
+
+	info.si_code = code;
+	info.si_signo = sig;
+	info.si_errno = 0;
+	info.si_addr = (void *) address;
+	info.si_trapno = 0;
+	force_sig_info(sig, &info, current);
+}
+
+extern int handle_ldf_stq(u32, struct pt_regs *);
+extern int handle_ld_nf(u32, struct pt_regs *);
+
+static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
+			    unsigned int insn, unsigned long address)
+{
+	unsigned long g2;
+	unsigned char asi = ASI_P;
+		
+	if (!insn) {
+		if (regs->tstate & TSTATE_PRIV) {
+			if (regs->tpc & 0x3)
+				goto cannot_handle;
+			insn = *(unsigned int *)regs->tpc;
+		} else {
+			insn = get_user_insn(regs->tpc);
+		}
+	}
+
+	/* If user insn could be read (thus insn is zero), that
+	 * is fine.  We will just gun down the process with a signal
+	 * in that case.
+	 */
+
+	if (!(fault_code & FAULT_CODE_WRITE) &&
+	    (insn & 0xc0800000) == 0xc0800000) {
+		if (insn & 0x2000)
+			asi = (regs->tstate >> 24);
+		else
+			asi = (insn >> 5);
+		if ((asi & 0xf2) == 0x82) {
+			if (insn & 0x1000000) {
+				handle_ldf_stq(insn, regs);
+			} else {
+				/* This was a non-faulting load. Just clear the
+				 * destination register(s) and continue with the next
+				 * instruction. -jj
+				 */
+				handle_ld_nf(insn, regs);
+			}
+			return;
+		}
+	}
+		
+	g2 = regs->u_regs[UREG_G2];
+
+	/* Is this in ex_table? */
+	if (regs->tstate & TSTATE_PRIV) {
+		unsigned long fixup;
+
+		if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) {
+			if (insn & 0x2000)
+				asi = (regs->tstate >> 24);
+			else
+				asi = (insn >> 5);
+		}
+	
+		/* Look in asi.h: All _S asis have LS bit set */
+		if ((asi & 0x1) &&
+		    (fixup = search_exception_table (regs->tpc, &g2))) {
+			regs->tpc = fixup;
+			regs->tnpc = regs->tpc + 4;
+			regs->u_regs[UREG_G2] = g2;
+			return;
+		}
+	} else {
+		/* The si_code was set to make clear whether
+		 * this was a SEGV_MAPERR or SEGV_ACCERR fault.
+		 */
+		do_fault_siginfo(si_code, SIGSEGV, address);
+		return;
+	}
+
+cannot_handle:
+	unhandled_fault (address, current, regs);
+}
+
+asmlinkage void do_sparc64_fault(struct pt_regs *regs)
 {
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma;
 	unsigned int insn = 0;
-	siginfo_t info;
-#ifdef DEBUG_LOCKUPS
-	static unsigned long lastaddr, lastpc;
-	static int lastwrite, lockcnt;
-#endif
+	int si_code, fault_code;
+	unsigned long address;
+
+	si_code = SEGV_MAPERR;
+	fault_code = current->thread.fault_code;
+	address = current->thread.fault_address;
+
+	if ((fault_code & FAULT_CODE_ITLB) &&
+	    (fault_code & FAULT_CODE_DTLB))
+		BUG();
 
-	info.si_code = SEGV_MAPERR;
 	/*
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
 	 */
 	if (in_interrupt() || !mm)
-		goto do_kernel_fault;
+		goto handle_kernel_fault;
 
 	down(&mm->mmap_sem);
-#ifdef DEBUG_LOCKUPS
-	if (regs->tpc == lastpc &&
-	    address == lastaddr &&
-	    write == lastwrite) {
-		lockcnt++;
-		if (lockcnt == 100000) {
-			unsigned char tmp;
-			register unsigned long tmp1 asm("o5");
-			register unsigned long tmp2 asm("o4");
-
-			printk("do_sparc64_fault[%s:%d]: possible fault loop for %016lx %s\n",
-			       current->comm, current->pid,
-			       address, write ? "write" : "read");
-			printk("do_sparc64_fault: CHECK[papgd[%016lx],pcac[%016lx]]\n",
-			       __pa(mm->pgd), pgd_val(mm->pgd[0])<<11UL);
-			__asm__ __volatile__(
-				"wrpr	%%g0, 0x494, %%pstate\n\t"
-				"mov	%3, %%g4\n\t"
-				"mov	%%g7, %0\n\t"
-				"ldxa	[%%g4] %2, %1\n\t"
-				"wrpr	%%g0, 0x096, %%pstate"
-				: "=r" (tmp1), "=r" (tmp2)
-				: "i" (ASI_DMMU), "i" (TSB_REG));
-			printk("do_sparc64_fault:    IS[papgd[%016lx],pcac[%016lx]]\n",
-			       tmp1, tmp2);
-			printk("do_sparc64_fault: CHECK[ctx(%016lx)] IS[ctx(%016lx)]\n",
-			       mm->context, spitfire_get_secondary_context());
-			__asm__ __volatile__("rd	%%asi, %0"
-					     : "=r" (tmp));
-			printk("do_sparc64_fault: CHECK[seg(%02x)] IS[seg(%02x)]\n",
-			       current->thread.current_ds.seg, tmp);
-			show_regs(regs);
-			__sti();
-			while(1)
-				barrier();
-		}
-	} else {
-		lastpc = regs->tpc;
-		lastaddr = address;
-		lastwrite = write;
-		lockcnt = 0;
-	}
-#endif
 	vma = find_vma(mm, address);
-	if(!vma)
+	if (!vma)
 		goto bad_area;
-#ifndef INSN_VPTE_LOOKUP
-	write &= 0xf;
-#else
-	if (write & 0x10) {
-		write = 0;
-		if((vma->vm_flags & VM_WRITE)) {
-			if (regs->tstate & TSTATE_PRIV)
-				insn = *(unsigned int *)regs->tpc;
-			else
-				insn = get_user_insn(regs->tpc);
-			if ((insn & 0xc0200000) == 0xc0200000 && (insn & 0x1780000) != 0x1680000)
-				write = 1;
+
+	/* Pure DTLB misses do not tell us whether the fault causing
+	 * load/store/atomic was a write or not, it only says that there
+	 * was no match.  So in such a case we (carefully) read the
+	 * instruction to try and figure this out.  It's an optimization
+	 * so it's ok if we can't do this.
+	 *
+	 * Special hack, window spill/fill knows the exact fault type.
+	 */
+	if (((fault_code &
+	      (FAULT_CODE_DTLB | FAULT_CODE_WRITE | FAULT_CODE_WINFIXUP)) == FAULT_CODE_DTLB) &&
+	    (vma->vm_flags & VM_WRITE) != 0) {
+		unsigned long tpc = regs->tpc;
+
+		if (tpc & 0x3)
+			goto continue_fault;
+
+		if (regs->tstate & TSTATE_PRIV)
+			insn = *(unsigned int *)tpc;
+		else
+			insn = get_user_insn(tpc);
+
+		if ((insn & 0xc0200000) == 0xc0200000 &&
+		    (insn & 0x1780000) != 0x1680000) {
+			/* Don't bother updating thread struct value,
+			 * because update_mmu_cache only cares which tlb
+			 * the access came from.
+			 */
+			fault_code |= FAULT_CODE_WRITE;
 		}
 	}
-#endif
-	if(vma->vm_start <= address)
+continue_fault:
+
+	if (vma->vm_start <= address)
 		goto good_area;
-	if(!(vma->vm_flags & VM_GROWSDOWN))
+	if (!(vma->vm_flags & VM_GROWSDOWN))
 		goto bad_area;
-	if(expand_stack(vma, address))
+	if (expand_stack(vma, address))
 		goto bad_area;
 	/*
 	 * Ok, we have a good vm_area for this memory access, so
 	 * we can handle it..
 	 */
 good_area:
-	info.si_code = SEGV_ACCERR;
-	if(write) {
-		if(!(vma->vm_flags & VM_WRITE))
+	si_code = SEGV_ACCERR;
+	if (fault_code & FAULT_CODE_WRITE) {
+		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
+		if ((vma->vm_flags & VM_EXEC) != 0 &&
+		    vma->vm_file != NULL)
+			current->thread.use_blkcommit = 1;
 	} else {
 		/* Allow reads even for write-only mappings */
-		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
 
 	{
-		int fault = handle_mm_fault(current, vma, address, write);
+		int fault = handle_mm_fault(current, vma,
+					    address, (fault_code & FAULT_CODE_WRITE));
 
 		if (fault < 0)
 			goto out_of_memory;
@@ -255,7 +304,8 @@
 			goto do_sigbus;
 	}
 	up(&mm->mmap_sem);
-	return;
+	goto fault_done;
+
 	/*
 	 * Something tried to access memory that isn't in our memory map..
 	 * Fix it, but check if it's kernel or user first..
@@ -263,89 +313,10 @@
 bad_area:
 	up(&mm->mmap_sem);
 
-do_kernel_fault:
-	{
-		unsigned long g2;
-		unsigned char asi = ASI_P;
-		
-		if (!insn) {
-			if (regs->tstate & TSTATE_PRIV)
-				insn = *(unsigned int *)regs->tpc;
-			else
-				insn = get_user_insn(regs->tpc);
-		}
-		if (write != 1 && (insn & 0xc0800000) == 0xc0800000) {
-			if (insn & 0x2000)
-				asi = (regs->tstate >> 24);
-			else
-				asi = (insn >> 5);
-			if ((asi & 0xf2) == 0x82) {
-				/* This was a non-faulting load. Just clear the
-				   destination register(s) and continue with the next
-				   instruction. -jj */
-				if (insn & 0x1000000) {
-					extern int handle_ldf_stq(u32, struct pt_regs *);
-					
-					handle_ldf_stq(insn, regs);
-				} else {
-					extern int handle_ld_nf(u32, struct pt_regs *);
-					
-					handle_ld_nf(insn, regs);
-				}
-				return;
-			}
-		}
-		
-		g2 = regs->u_regs[UREG_G2];
-
-		/* Is this in ex_table? */
-		if (regs->tstate & TSTATE_PRIV) {
-			unsigned long fixup;
+handle_kernel_fault:
+	do_kernel_fault(regs, si_code, fault_code, insn, address);
 
-			if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) {
-				if (insn & 0x2000)
-					asi = (regs->tstate >> 24);
-				else
-					asi = (insn >> 5);
-			}
-	
-			/* Look in asi.h: All _S asis have LS bit set */
-			if ((asi & 0x1) &&
-			    (fixup = search_exception_table (regs->tpc, &g2))) {
-#ifdef DEBUG_EXCEPTIONS
-				printk("Exception: PC<%016lx> faddr<%016lx>\n",
-				       regs->tpc, address);
-				printk("EX_TABLE: insn<%016lx> fixup<%016lx> "
-				       "g2<%016lx>\n", regs->tpc, fixup, g2);
-#endif
-				regs->tpc = fixup;
-				regs->tnpc = regs->tpc + 4;
-				regs->u_regs[UREG_G2] = g2;
-				return;
-			}
-		} else {
-#if 0
-			extern void __show_regs(struct pt_regs *);
-			printk("SHIT(%s:%d:cpu(%d)): PC[%016lx] ADDR[%016lx]\n",
-			       current->comm, current->pid, smp_processor_id(),
-			       regs->tpc, address);
-			__show_regs(regs);
-			__sti();
-			while(1)
-				barrier();
-#endif
-			info.si_signo = SIGSEGV;
-			info.si_errno = 0;
-			/* info.si_code set above to make clear whether
-			   this was a SEGV_MAPERR or SEGV_ACCERR fault.  */
-			info.si_addr = (void *)address;
-			info.si_trapno = 0;
-			force_sig_info (SIGSEGV, &info, current);
-			return;
-		}
-		unhandled_fault (address, current, regs);
-	}
-	return;
+	goto fault_done;
 
 /*
  * We ran out of memory, or some other thing happened to us that made
@@ -356,7 +327,7 @@
 	printk("VM: killing process %s\n", current->comm);
 	if (!(regs->tstate & TSTATE_PRIV))
 		do_exit(SIGKILL);
-	goto do_kernel_fault;
+	goto handle_kernel_fault;
 
 do_sigbus:
 	up(&mm->mmap_sem);
@@ -365,14 +336,15 @@
 	 * Send a sigbus, regardless of whether we were in kernel
 	 * or user mode.
 	 */
-	info.si_signo = SIGBUS;
-	info.si_errno = 0;
-	info.si_code = BUS_ADRERR;
-	info.si_addr = (void *)address;
-	info.si_trapno = 0;
-	force_sig_info (SIGBUS, &info, current);
+	do_fault_siginfo(BUS_ADRERR, SIGBUS, address);
 
 	/* Kernel mode? Handle exceptions or die */
 	if (regs->tstate & TSTATE_PRIV)
-		goto do_kernel_fault;
+		goto handle_kernel_fault;
+
+fault_done:
+	/* These values are no longer needed, clear them. */
+	current->thread.fault_code = 0;
+	current->thread.use_blkcommit = 0;
+	current->thread.fault_address = 0;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.3.99-pre3/linux/arch/sparc64/mm/ultra.S	Tue Mar  7 14:32:25 2000
+++ linux/arch/sparc64/mm/ultra.S	Thu Mar 30 16:54:53 2000
@@ -1,11 +1,12 @@
-/* $Id: ultra.S,v 1.38 2000/03/03 23:48:44 davem Exp $
+/* $Id: ultra.S,v 1.41 2000/03/27 10:38:51 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
  */
 
 #include <asm/asi.h>
 #include <asm/pgtable.h>
+#include <asm/page.h>
 #include <asm/spitfire.h>
 
 	/* This file is meant to be read efficiently by the CPU, not humans.
@@ -160,34 +161,86 @@
 	srlx		%o0, 5, %o0
 	clr		%o1			! IC_addr
 	sllx		%g1, 36, %g1
+	ldda		[%o1] ASI_IC_TAG, %o4
 	sub		%g1, 1, %g2
 	or		%o0, %g1, %o0		! VALID+phys-addr comparitor
-	sllx		%g2, 1, %g2
 
+	sllx		%g2, 1, %g2
 	andn		%g2, 0xfe, %g2		! IC_tag mask
-1:	ldda		[%o1] ASI_IC_TAG, %o4
-	and		%o5, %g2, %o5
-	cmp		%o5, %o0
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+1:	addx		%g0, %g0, %g0
+	ldda		[%o1 + %o2] ASI_IC_TAG, %g4
+	addx		%g0, %g0, %g0
+	and		%o5, %g2, %g3
+	cmp		%g3, %o0
+	add		%o1, 0x20, %o1
+	ldda		[%o1] ASI_IC_TAG, %o4
 	be,pn		%xcc, iflush1
-	 add		%o1, 0x20, %g3
-2:	ldda		[%o1 + %o2] ASI_IC_TAG, %o4
-	and		%o5, %g2, %o5
 
-	cmp		%o5, %o0
+2:	 nop
+	and		%g5, %g2, %g5
+	cmp		%g5, %o0
 	be,pn		%xcc, iflush2
-	 nop
-3:	cmp		%g3, %o2
+3:	 cmp		%o1, %o2
 	bne,pt		%xcc, 1b
-	 mov		%g3, %o1
+	 addx		%g0, %g0, %g0
+	nop
+
+	sethi		%uhi(PAGE_OFFSET), %g4
 	retl
-	 nop
+	 sllx		%g4, 32, %g4
 
-iflush1:stxa		%g0, [%o1] ASI_IC_TAG
+iflush1:sub		%o1, 0x20, %g3
+	stxa		%g0, [%g3] ASI_IC_TAG
 	flush		%g6
 	ba,a,pt		%xcc, 2b
-iflush2:stxa		%g0, [%o1 + %o2] ASI_IC_TAG
+iflush2:sub		%o1, 0x20, %g3
+	stxa		%g0, [%o1 + %o2] ASI_IC_TAG
 	flush		%g6
 	ba,a,pt		%xcc, 3b
+
+	.align		32
+__prefill_dtlb:
+	rdpr		%pstate, %g7
+	wrpr		%g7, PSTATE_IE, %pstate
+	mov		TLB_TAG_ACCESS, %g1
+	stxa		%o0, [%g1] ASI_DMMU
+	stxa		%o1, [%g0] ASI_DTLB_DATA_IN
+	flush		%g6
+	retl
+	 wrpr		%g7, %pstate
+__prefill_itlb:
+	rdpr		%pstate, %g7
+	wrpr		%g7, PSTATE_IE, %pstate
+	mov		TLB_TAG_ACCESS, %g1
+	stxa		%o0, [%g1] ASI_IMMU
+	stxa		%o1, [%g0] ASI_ITLB_DATA_IN
+	flush		%g6
+	retl
+	 wrpr		%g7, %pstate
+
+	.globl		update_mmu_cache
+update_mmu_cache:	/* %o0=vma, %o1=address, %o2=pte */
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fault_code], %o3
+	srlx		%o1, 13, %o1
+	ldx		[%o0 + 0x0], %o4		/* XXX vma->vm_mm */
+	brz,pn		%o3, 1f
+	 sllx		%o1, 13, %o0
+	ldx		[%o4 + AOFF_mm_context], %o5
+	andcc		%o3, FAULT_CODE_DTLB, %g0
+	mov		%o2, %o1
+	and		%o5, 0x3ff, %o5
+	bne,pt		%xcc, __prefill_dtlb
+	 or		%o0, %o5, %o0
+	ba,a,pt		%xcc, __prefill_itlb
+1:	retl
+	 nop
 
 #ifdef __SMP__
 	/* These are all called by the slaves of a cross call, at
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/prom/Makefile linux/arch/sparc64/prom/Makefile
--- v2.3.99-pre3/linux/arch/sparc64/prom/Makefile	Wed Dec 29 13:13:15 1999
+++ linux/arch/sparc64/prom/Makefile	Thu Mar 30 16:56:04 2000
@@ -18,10 +18,10 @@
 	sync
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+	$(CPP) $(AFLAGS) -ansi $< -o $*.s
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+	$(CC) $(AFLAGS) -ansi -c $< -o $*.o
 
 dep:
 	$(CPP) $(CPPFLAGS) -M *.c > .depend
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/solaris/Makefile linux/arch/sparc64/solaris/Makefile
--- v2.3.99-pre3/linux/arch/sparc64/solaris/Makefile	Mon Nov 16 10:37:28 1998
+++ linux/arch/sparc64/solaris/Makefile	Thu Mar 30 16:56:04 2000
@@ -15,10 +15,10 @@
 endif
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi $< -o $*.s
+	$(CPP) $(AFLAGS) $(CPPFLAGS) -ansi $< -o $*.s
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi -c $< -o $*.o
+	$(CC) $(AFLAGS) $(CPPFLAGS) -ansi -c $< -o $*.o
 
 ifneq ($(CONFIG_SOLARIS_EMUL),y)
 do_it_all:
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c
--- v2.3.99-pre3/linux/arch/sparc64/solaris/fs.c	Fri Mar 10 16:40:41 2000
+++ linux/arch/sparc64/solaris/fs.c	Sun Apr  2 15:53:28 2000
@@ -495,26 +495,18 @@
 
 asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf)
 {
-	struct inode * inode;
-	struct dentry * dentry;
 	struct file * file;
 	int error;
 
-	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
-	if (!file)
-		goto out;
-
-	if (!(dentry = file->f_dentry))
-		error = -ENOENT;
-	else if (!(inode = dentry->d_inode))
-		error = -ENOENT;
-	else
-		error = report_statvfs(inode, buf);
-	fput(file);
+	if (file) {
+		lock_kernel();
+		error = report_statvfs(file->f_dentry->d_inode, buf);
+		unlock_kernel();
+		fput(file);
+	}
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -538,26 +530,17 @@
 
 asmlinkage int solaris_fstatvfs64(unsigned int fd, u32 buf)
 {
-	struct inode * inode;
-	struct dentry * dentry;
 	struct file * file;
 	int error;
 
-	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
-	if (!file)
-		goto out;
-
-	if (!(dentry = file->f_dentry))
-		error = -ENOENT;
-	else if (!(inode = dentry->d_inode))
-		error = -ENOENT;
-	else
-		error = report_statvfs64(inode, buf);
-	fput(file);
-out:
-	unlock_kernel();
+	if (file) {
+		lock_kernel();
+		error = report_statvfs64(file->f_dentry->d_inode, buf);
+		unlock_kernel();
+		fput(file);
+	}
 	return error;
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c
--- v2.3.99-pre3/linux/arch/sparc64/solaris/misc.c	Tue Mar 14 19:10:39 2000
+++ linux/arch/sparc64/solaris/misc.c	Sun Apr  2 15:53:28 2000
@@ -72,7 +72,7 @@
  		file = fget(fd);
 		if (!file)
 			goto out;
-		if (file->f_dentry && file->f_dentry->d_inode) {
+		else {
 			struct inode * inode = file->f_dentry->d_inode;
 			if(MAJOR(inode->i_rdev) == MEM_MAJOR &&
 			   MINOR(inode->i_rdev) == 5) {
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c
--- v2.3.99-pre3/linux/arch/sparc64/solaris/socksys.c	Sun Feb 20 21:12:38 2000
+++ linux/arch/sparc64/solaris/socksys.c	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: socksys.c,v 1.12 2000/02/17 05:50:11 davem Exp $
+/* $Id: socksys.c,v 1.13 2000/03/29 11:56:54 davem Exp $
  * socksys.c: /dev/inet/ stuff for Solaris emulation.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/malloc.h>
+#include <linux/in.h>
 #include <linux/devfs_fs_kernel.h>
 
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c
--- v2.3.99-pre3/linux/arch/sparc64/solaris/timod.c	Wed Dec 29 13:13:15 1999
+++ linux/arch/sparc64/solaris/timod.c	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: timod.c,v 1.5 1999/11/23 08:55:24 davem Exp $
+/* $Id: timod.c,v 1.6 2000/03/25 03:23:21 davem Exp $
  * timod.c: timod emulation.
  *
  * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
@@ -151,7 +151,7 @@
 	SOLD("wakeing socket");
 	sock = &current->files->fd[fd]->f_dentry->d_inode->u.socket_i;
 	wake_up_interruptible(&sock->wait);
-	if (sock->fasync_list && !(sock->flags & SO_WAITDATA))
+	if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
 		kill_fasync(sock->fasync_list, SIGIO, POLL_IN);
 	SOLD("done");
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/char/keyb_ps2.c linux/drivers/acorn/char/keyb_ps2.c
--- v2.3.99-pre3/linux/drivers/acorn/char/keyb_ps2.c	Sun Feb 13 19:29:03 2000
+++ linux/drivers/acorn/char/keyb_ps2.c	Mon Mar 27 10:45:48 2000
@@ -32,8 +32,6 @@
 extern void kbd_reset_kdown(void);
 int kbd_read_mask;
 
-#define IRQ_KEYBOARDRX 15
-
 #define VERSION 100
 
 #define KBD_REPORT_ERR
@@ -330,6 +328,10 @@
 {
 	unsigned long flags;
 
+	/* Reset the keyboard state machine. */
+	outb(0, IOMD_KCTRL);
+	outb(8, IOMD_KCTRL);
+
 	save_flags_cli (flags);
 	if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0)
 		panic("Could not allocate keyboard receive IRQ!");
@@ -342,4 +344,3 @@
 	printk (KERN_INFO "PS/2 keyboard driver v%d.%02d\n", VERSION/100, VERSION%100);
 	return 0;
 }
-
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/acornscsi.h linux/drivers/acorn/scsi/acornscsi.h
--- v2.3.99-pre3/linux/drivers/acorn/scsi/acornscsi.h	Thu Nov 11 20:11:32 1999
+++ linux/drivers/acorn/scsi/acornscsi.h	Sun Apr  2 17:28:21 2000
@@ -1,3 +1,8 @@
+/*
+ * Acorn SCSI driver
+ *
+ * Copyright (C) 1997 Russell King
+ */
 #ifndef ACORNSCSI_H
 #define ACORNSCSI_H
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/arxescsi.c linux/drivers/acorn/scsi/arxescsi.c
--- v2.3.99-pre3/linux/drivers/acorn/scsi/arxescsi.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/acorn/scsi/arxescsi.c	Sun Apr  2 17:28:21 2000
@@ -1,7 +1,7 @@
 /*
- * linux/arch/arm/drivers/scsi/cumana_2.c
+ * linux/arch/arm/drivers/scsi/arxescsi.c
  *
- * Copyright (C) 1997,1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
  *
  * This driver is based on experimentation.  Hence, it may have made
  * assumptions about the particular card that I have available, and
@@ -13,6 +13,7 @@
  *  15-04-1998	RMK	0.0.1	Only do PIO if FAS216 will allow it.
  *  11-06-1998 		0.0.2   Changed to support ARXE 16-bit SCSI card, enabled writing
  *  				by Stefan Hanske
+ *  02-04-2000	RMK	0.0.3	Updated for new error handling code.
  */
 
 #include <linux/module.h>
@@ -54,7 +55,7 @@
  */
 #define VER_MAJOR	0
 #define VER_MINOR	0
-#define VER_PATCH	2
+#define VER_PATCH	3
 
 static struct expansion_card *ecs[MAX_ECARDS];
 
@@ -308,10 +309,9 @@
 	static char string[100], *p;
 
 	p = string;
-	p += sprintf(string, "%s at port %lX irq %d v%d.%d.%d scsi %s",
-		     host->hostt->name, host->io_port, host->irq,
-		     VER_MAJOR, VER_MINOR, VER_PATCH,
-		     info->info.scsi.type);
+	p += sprintf(p, "%s ", host->hostt->name);
+	p += fas216_info(&info->info, p);
+	p += sprintf(p, "v%d.%d.%d", VER_MAJOR, VER_MINOR, VER_PATCH);
 
 	return string;
 }
@@ -354,12 +354,7 @@
 	pos = sprintf(buffer,
 			"ARXE 16-bit SCSI driver version %d.%d.%d\n",
 			VER_MAJOR, VER_MINOR, VER_PATCH);
-	pos += sprintf(buffer + pos,
-			"Address: %08lX          IRQ : %d\n"
-			"FAS    : %s\n\n"
-			"Statistics:\n",
-			host->io_port, host->irq, info->info.scsi.type);
-
+	pos += fas216_print_host(&info->info, buffer + pos);
 	pos += fas216_print_stats(&info->info, buffer + pos);
 
 	pos += sprintf (buffer+pos, "\nAttached devices:\n");
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/arxescsi.h linux/drivers/acorn/scsi/arxescsi.h
--- v2.3.99-pre3/linux/drivers/acorn/scsi/arxescsi.h	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/scsi/arxescsi.h	Sun Apr  2 17:28:21 2000
@@ -1,7 +1,8 @@
 /*
  * ARXE SCSI card driver
  *
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1997-2000 Russell King
+ *
  * Changes to support ARXE 16-bit SCSI card by Stefan Hanske
  */
 #ifndef ARXE_SCSI_H
@@ -44,22 +45,25 @@
 #include "fas216.h"
 #endif
 
-#define ARXEScsi {							\
-proc_info:	arxescsi_proc_info,						\
-name:		"ARXE SCSI card",						\
-detect:		arxescsi_detect,		/* detect		*/	\
-release:	arxescsi_release,		/* release		*/	\
-info:		arxescsi_info,			/* info			*/	\
-command:	fas216_command,			/* command		*/	\
-queuecommand:	fas216_queue_command,		/* queuecommand		*/	\
-abort:		fas216_abort,			/* abort		*/	\
-reset:		fas216_reset,			/* reset		*/	\
-bios_param:	scsicam_bios_param,		/* biosparam		*/	\
-can_queue:	CAN_QUEUE,			/* can queue		*/	\
-this_id:	SCSI_ID,			/* scsi host id		*/	\
-sg_tablesize:	SG_ALL,				/* sg_tablesize		*/	\
-cmd_per_lun:	CMD_PER_LUN,			/* cmd per lun		*/	\
-use_clustering:	DISABLE_CLUSTERING						\
+#define ARXEScsi {					\
+proc_info:			arxescsi_proc_info,	\
+name:				"ARXE SCSI card",	\
+detect:				arxescsi_detect,	\
+release:			arxescsi_release,	\
+info:				arxescsi_info,		\
+bios_param:			scsicam_bios_param,	\
+can_queue:			CAN_QUEUE,		\
+this_id:			SCSI_ID,		\
+sg_tablesize:			SG_ALL,			\
+cmd_per_lun:			CMD_PER_LUN,		\
+use_clustering:			DISABLE_CLUSTERING,	\
+command:			fas216_command,		\
+queuecommand:			fas216_queue_command,	\
+eh_host_reset_handler:		fas216_eh_host_reset,	\
+eh_bus_reset_handler:		fas216_eh_bus_reset,	\
+eh_device_reset_handler:	fas216_eh_device_reset,	\
+eh_abort_handler:		fas216_eh_abort,	\
+use_new_eh_code:		1			\
 	}
 
 #ifndef HOSTS_C
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c
--- v2.3.99-pre3/linux/drivers/acorn/scsi/cumana_2.c	Thu Nov 11 20:11:32 1999
+++ linux/drivers/acorn/scsi/cumana_2.c	Sun Apr  2 17:28:22 2000
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/drivers/scsi/cumana_2.c
  *
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
  *
  * Changelog:
  *  30-08-1997	RMK	0.0.0	Created, READONLY version.
@@ -10,6 +10,7 @@
  *  02-05-1998	RMK	0.0.2	Updated & added DMA support.
  *  27-06-1998	RMK		Changed asm/delay.h to linux/delay.h
  *  18-08-1998	RMK	0.0.3	Fixed synchronous transfer depth.
+ *  02-04-2000	RMK	0.0.4	Updated for new error handling code.
  */
 
 #include <linux/module.h>
@@ -70,7 +71,7 @@
  */
 #define VER_MAJOR	0
 #define VER_MINOR	0
-#define VER_PATCH	3
+#define VER_PATCH	4
 
 static struct expansion_card *ecs[MAX_ECARDS];
 
@@ -433,25 +434,11 @@
 	static char string[100], *p;
 
 	p = string;
-	p += sprintf(string, "%s at port %lX ",
-		     host->hostt->name, host->io_port);
-
-	if (host->irq != NO_IRQ)
-		p += sprintf(p, "irq %d ", host->irq);
-	else
-		p += sprintf(p, "NO IRQ ");
-
-	if (host->dma_channel != NO_DMA)
-		p += sprintf(p, "dma %d ", host->dma_channel);
-	else
-		p += sprintf(p, "NO DMA ");
-
-	p += sprintf(p, "v%d.%d.%d scsi %s",
+	p += sprintf(p, "%s ", host->hostt->name);
+	p += fas216_info(&info->info, p);
+	p += sprintf(p, "v%d.%d.%d terminators o%s",
 		     VER_MAJOR, VER_MINOR, VER_PATCH,
-		     info->info.scsi.type);
-
-	p += sprintf(p, " terminators %s",
-		     info->terms ? "on" : "off");
+		     info->terms ? "n" : "ff");
 
 	return string;
 }
@@ -525,26 +512,14 @@
 	pos = sprintf(buffer,
 			"Cumana SCSI II driver version %d.%d.%d\n",
 			VER_MAJOR, VER_MINOR, VER_PATCH);
-	pos += sprintf(buffer + pos,
-			"Address: %08lX    IRQ : %d     DMA : %d\n"
-			"FAS    : %-10s  TERM: %-3s\n\n"
-			"Statistics:\n",
-			host->io_port, host->irq, host->dma_channel,
-			info->info.scsi.type, info->terms ? "on" : "off");
-
-	pos += sprintf(buffer+pos,
-			"Queued commands: %-10u   Issued commands: %-10u\n"
-			"Done commands  : %-10u   Reads          : %-10u\n"
-			"Writes         : %-10u   Others         : %-10u\n"
-			"Disconnects    : %-10u   Aborts         : %-10u\n"
-			"Resets         : %-10u\n",
-			info->info.stats.queues,      info->info.stats.removes,
-			info->info.stats.fins,        info->info.stats.reads,
-			info->info.stats.writes,      info->info.stats.miscs,
-			info->info.stats.disconnects, info->info.stats.aborts,
-			info->info.stats.resets);
 
-	pos += sprintf(buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none");
+	pos += fas216_print_host(&info->info, buffer + pos);
+	pos += sprintf(buffer + pos, "Term    : o%s\n",
+			info->terms ? "n" : "ff");
+
+	pos += fas216_print_stats(&info->info, buffer + pos);
+
+	pos += sprintf(buffer+pos, "\nAttached devices:\n");
 
 	for (scd = host->host_queue; scd; scd = scd->next) {
 		int len;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/cumana_2.h linux/drivers/acorn/scsi/cumana_2.h
--- v2.3.99-pre3/linux/drivers/acorn/scsi/cumana_2.h	Fri May  8 00:42:39 1998
+++ linux/drivers/acorn/scsi/cumana_2.h	Sun Apr  2 17:28:22 2000
@@ -1,7 +1,7 @@
 /*
  * Cumana SCSI II driver
  *
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
  */
 #ifndef CUMANA_2_H
 #define CUMANA_2_H
@@ -23,6 +23,13 @@
 #define CAN_QUEUE	1
 #endif
 
+#ifndef CMD_PER_LUN
+/*
+ * Default queue size
+ */
+#define CMD_PER_LUN	1
+#endif
+
 #ifndef SCSI_ID
 /*
  * Default SCSI host ID
@@ -36,23 +43,25 @@
 #include "fas216.h"
 #endif
 
-#define CUMANASCSI_2 {							\
-proc_info:		cumanascsi_2_proc_info,				\
-name:			"Cumana SCSI II",				\
-detect:			cumanascsi_2_detect,	/* detect		*/	\
-release:		cumanascsi_2_release,	/* release		*/	\
-info:			cumanascsi_2_info,	/* info			*/	\
-command:		fas216_command,		/* command		*/	\
-queuecommand:		fas216_queue_command,	/* queuecommand		*/	\
-abort:			fas216_abort,		/* abort		*/	\
-reset:			fas216_reset,		/* reset		*/	\
-bios_param:		scsicam_bios_param,	/* biosparam		*/	\
-can_queue:		CAN_QUEUE,		/* can queue		*/	\
-this_id:		SCSI_ID,		/* scsi host id		*/	\
-sg_tablesize:		SG_ALL,			/* sg_tablesize		*/	\
-cmd_per_lun:		CAN_QUEUE,		/* cmd per lun		*/	\
-unchecked_isa_dma:	0,			/* unchecked isa dma	*/	\
-use_clustering:		DISABLE_CLUSTERING					\
+#define CUMANASCSI_2 {					\
+proc_info:			cumanascsi_2_proc_info,	\
+name:				"Cumana SCSI II",	\
+detect:				cumanascsi_2_detect,	\
+release:			cumanascsi_2_release,	\
+info:				cumanascsi_2_info,	\
+bios_param:			scsicam_bios_param,	\
+can_queue:			CAN_QUEUE,		\
+this_id:			SCSI_ID,		\
+sg_tablesize:			SG_ALL,			\
+cmd_per_lun:			CMD_PER_LUN,		\
+use_clustering:			DISABLE_CLUSTERING,	\
+command:			fas216_command,		\
+queuecommand:			fas216_queue_command,	\
+eh_host_reset_handler:		fas216_eh_host_reset,	\
+eh_bus_reset_handler:		fas216_eh_bus_reset,	\
+eh_device_reset_handler:	fas216_eh_device_reset,	\
+eh_abort_handler:		fas216_eh_abort,	\
+use_new_eh_code:		1			\
 	}
 
 #ifndef HOSTS_C
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/eesox.c linux/drivers/acorn/scsi/eesox.c
--- v2.3.99-pre3/linux/drivers/acorn/scsi/eesox.c	Thu Nov 11 20:11:32 1999
+++ linux/drivers/acorn/scsi/eesox.c	Sun Apr  2 17:28:22 2000
@@ -1,20 +1,22 @@
 /*
  * linux/arch/arm/drivers/scsi/eesox.c
  *
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
  *
  * This driver is based on experimentation.  Hence, it may have made
  * assumptions about the particular card that I have available, and
  * may not be reliable!
  *
  * Changelog:
- *  01-10-1997	RMK	Created, READONLY version
- *  15-02-1998	RMK	READ/WRITE version
- *			added DMA support and hardware definitions
- *  14-03-1998	RMK	Updated DMA support
- *			Added terminator control
- *  15-04-1998	RMK	Only do PIO if FAS216 will allow it.
- *  27-06-1998	RMK	Changed asm/delay.h to linux/delay.h
+ *  01-10-1997	RMK		Created, READONLY version
+ *  15-02-1998	RMK		READ/WRITE version
+ *				added DMA support and hardware definitions
+ *  14-03-1998	RMK		Updated DMA support
+ *				Added terminator control
+ *  15-04-1998	RMK		Only do PIO if FAS216 will allow it.
+ *  27-06-1998	RMK		Changed asm/delay.h to linux/delay.h
+ *  02-04-2000	RMK	0.0.3	Fixed NO_IRQ/NO_DMA problem, updated for new
+ *				error handling code.
  */
 
 #include <linux/module.h>
@@ -67,7 +69,7 @@
  */
 #define VER_MAJOR	0
 #define VER_MINOR	0
-#define VER_PATCH	2
+#define VER_PATCH	3
 
 static struct expansion_card *ecs[MAX_ECARDS];
 
@@ -382,14 +384,16 @@
 		request_region(host->io_port + EESOX_FAS216_OFFSET,
 				16 << EESOX_FAS216_SHIFT, "eesox2-fas");
 
-		if (request_irq(host->irq, eesoxscsi_intr,
+		if (host->irq != NO_IRQ &&
+		    request_irq(host->irq, eesoxscsi_intr,
 				SA_INTERRUPT, "eesox", host)) {
 			printk("scsi%d: IRQ%d not free, interrupts disabled\n",
 			       host->host_no, host->irq);
 			host->irq = NO_IRQ;
 		}
 
-		if (request_dma(host->dma_channel, "eesox")) {
+		if (host->dma_channel != NO_DMA &&
+		    request_dma(host->dma_channel, "eesox")) {
 			printk("scsi%d: DMA%d not free, DMA disabled\n",
 			       host->host_no, host->dma_channel);
 			host->dma_channel = NO_DMA;
@@ -435,24 +439,11 @@
 	static char string[100], *p;
 
 	p = string;
-	p += sprintf(string, "%s at port %lX ",
-		     host->hostt->name, host->io_port);
-
-	if (host->irq != NO_IRQ)
-		p += sprintf(p, "irq %d ", host->irq);
-	else
-		p += sprintf(p, "NO IRQ ");
-
-	if (host->dma_channel != NO_DMA)
-		p += sprintf(p, "dma %d ", host->dma_channel);
-	else
-		p += sprintf(p, "NO DMA ");
-
-	p += sprintf(p, "v%d.%d.%d scsi %s", VER_MAJOR, VER_MINOR, VER_PATCH,
-		  info->info.scsi.type);
-
-	p += sprintf(p, " terminators %s",
-		  info->control.control & EESOX_TERM_ENABLE ? "on" : "off");
+	p += sprintf(p, "%s ", host->hostt->name);
+	p += fas216_info(&info->info, p);
+	p += sprintf(p, "v%d.%d.%d terminators o%s",
+		     VER_MAJOR, VER_MINOR, VER_PATCH,
+		     info->control.control & EESOX_TERM_ENABLE ? "n" : "ff");
 
 	return string;
 }
@@ -526,26 +517,13 @@
 	pos = sprintf(buffer,
 			"EESOX SCSI driver version %d.%d.%d\n",
 			VER_MAJOR, VER_MINOR, VER_PATCH);
-	pos += sprintf(buffer + pos,
-			"Address: %08lX    IRQ : %d     DMA : %d\n"
-			"FAS    : %-10s  TERM: %-3s\n\n"
-			"Statistics:\n",
-			host->io_port, host->irq, host->dma_channel,
-			info->info.scsi.type, info->control.control & EESOX_TERM_ENABLE ? "on" : "off");
-
-	pos += sprintf(buffer+pos,
-			"Queued commands: %-10u   Issued commands: %-10u\n"
-			"Done commands  : %-10u   Reads          : %-10u\n"
-			"Writes         : %-10u   Others         : %-10u\n"
-			"Disconnects    : %-10u   Aborts         : %-10u\n"
-			"Resets         : %-10u\n",
-			info->info.stats.queues,      info->info.stats.removes,
-			info->info.stats.fins,        info->info.stats.reads,
-			info->info.stats.writes,      info->info.stats.miscs,
-			info->info.stats.disconnects, info->info.stats.aborts,
-			info->info.stats.resets);
+	pos += fas216_print_host(&info->info, buffer + pos);
+	pos += sprintf(buffer + pos, "Term    : o%s\n",
+			info->control.control & EESOX_TERM_ENABLE ? "n" : "ff");
+
+	pos += fas216_print_stats(&info->info, buffer + pos);
 
-	pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none");
+	pos += sprintf (buffer+pos, "\nAttached devices:\n");
 
 	for (scd = host->host_queue; scd; scd = scd->next) {
 		int len;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/eesox.h linux/drivers/acorn/scsi/eesox.h
--- v2.3.99-pre3/linux/drivers/acorn/scsi/eesox.h	Fri May  8 00:42:39 1998
+++ linux/drivers/acorn/scsi/eesox.h	Sun Apr  2 17:28:22 2000
@@ -1,7 +1,7 @@
 /*
  * EESOX SCSI driver
  *
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
  */
 #ifndef EESOXSCSI_H
 #define EESOXSCSI_H
@@ -38,22 +38,25 @@
 
 #include "fas216.h"
 
-#define EESOXSCSI {							\
-proc_info:	eesoxscsi_proc_info,					\
-name:		"EESOX SCSI",						\
-detect:		eesoxscsi_detect,	/* detect		*/	\
-release:	eesoxscsi_release,	/* release		*/	\
-info:		eesoxscsi_info,		/* info			*/	\
-command:	fas216_command,		/* command		*/	\
-queuecommand:	fas216_queue_command,	/* queuecommand		*/	\
-abort:		fas216_abort,		/* abort		*/	\
-reset:		fas216_reset,		/* reset		*/	\
-bios_param:	scsicam_bios_param,	/* biosparam		*/	\
-can_queue:	CAN_QUEUE,		/* can queue		*/	\
-this_id:	SCSI_ID,		/* scsi host id		*/	\
-sg_tablesize:	SG_ALL,			/* sg_tablesize		*/	\
-cmd_per_lun:	CAN_QUEUE,		/* cmd per lun		*/	\
-use_clustering:	DISABLE_CLUSTERING					\
+#define EESOXSCSI {					\
+proc_info:			eesoxscsi_proc_info,	\
+name:				"EESOX SCSI",		\
+detect:				eesoxscsi_detect,	\
+release:			eesoxscsi_release,	\
+info:				eesoxscsi_info,		\
+bios_param:			scsicam_bios_param,	\
+can_queue:			CAN_QUEUE,		\
+this_id:			SCSI_ID,		\
+sg_tablesize:			SG_ALL,			\
+cmd_per_lun:			CAN_QUEUE,		\
+use_clustering:			DISABLE_CLUSTERING,	\
+command:			fas216_command,		\
+queuecommand:			fas216_queue_command,	\
+eh_host_reset_handler:		fas216_eh_host_reset,	\
+eh_bus_reset_handler:		fas216_eh_bus_reset,	\
+eh_device_reset_handler:	fas216_eh_device_reset,	\
+eh_abort_handler:		fas216_eh_abort,	\
+use_new_eh_code:		1			\
 	}
 
 #ifndef HOSTS_C
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c
--- v2.3.99-pre3/linux/drivers/acorn/scsi/fas216.c	Tue Dec 14 01:27:23 1999
+++ linux/drivers/acorn/scsi/fas216.c	Sun Apr  2 17:28:22 2000
@@ -1,11 +1,12 @@
 /*
  * linux/arch/arm/drivers/scsi/fas216.c
  *
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1997-2000 Russell King
  *
  * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and
  * other sources, including:
  *   the AMD Am53CF94 data sheet
+ *   the AMD Am53C94 data sheet 
  *
  * This is a generic driver.  To use it, have a look at cumana_2.c.  You
  * should define your own structure that overlays FAS216_Info, eg:
@@ -25,6 +26,9 @@
  *  24-05-1998	RMK	Fixed synchronous transfers with period >= 200ns
  *  27-06-1998	RMK	Changed asm/delay.h to linux/delay.h
  *  26-08-1998	RMK	Improved message support wrt MESSAGE_REJECT
+ *  02-04-2000	RMK	Converted to use the new error handling, and
+ *			automatically request sense data upon check
+ *			condition status from targets.
  *
  * Todo:
  *  - allow individual devices to enable sync xfers.
@@ -59,8 +63,6 @@
 #define VER_MINOR	0
 #define VER_PATCH	5
 
-#define SCSI2_TAG
-
 /* NOTE: SCSI2 Synchronous transfers *require* DMA according to
  *  the data sheet.  This restriction is crazy, especially when
  *  you only want to send 16 bytes!  What were the guys who
@@ -85,8 +87,8 @@
  *  I was thinking that this was a good chip until I found this restriction ;(
  */
 #define SCSI2_SYNC
-
-#define SCSI2_WIDE
+#undef  SCSI2_WIDE
+#undef  SCSI2_TAG
 
 #undef DEBUG_CONNECT
 #undef DEBUG_BUSSERVICE
@@ -143,10 +145,11 @@
 		info->scsi.async_stp,
 		info->scsi.disconnectable, info->scsi.aborting);
 	printk("    stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n"
-	       "            disconnects=%X aborts=%X resets=%X }\n",
+	       "            disconnects=%X aborts=%X bus_resets=%X host_resets=%X}\n",
 		info->stats.queues, info->stats.removes, info->stats.fins,
 		info->stats.reads, info->stats.writes, info->stats.miscs,
-		info->stats.disconnects, info->stats.aborts, info->stats.resets);
+		info->stats.disconnects, info->stats.aborts, info->stats.bus_resets,
+		info->stats.host_resets);
 	printk("    ifcfg={ clockrate=%X select_timeout=%X asyncperiod=%X sync_max_depth=%X }\n",
 		info->ifcfg.clockrate, info->ifcfg.select_timeout,
 		info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth);
@@ -164,7 +167,7 @@
 }
 
 #ifdef CHECK_STRUCTURE
-static void fas216_checkmagic(FAS216_Info *info, const char *func)
+static void __fas216_checkmagic(FAS216_Info *info, const char *func)
 {
 	int corruption = 0;
 	if (info->magic_start != MAGIC) {
@@ -180,8 +183,9 @@
 		panic("scsi memory space corrupted in %s", func);
 	}
 }
+#define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__)
 #else
-#define fas216_checkmagic(info,func)
+#define fas216_checkmagic(info)
 #endif
 
 static const char *fas216_bus_phase(int stat)
@@ -312,7 +316,7 @@
 {
 	int value = (info->ifcfg.clockrate * ns) / 1000;
 
-	fas216_checkmagic(info, "fas216_syncperiod");
+	fas216_checkmagic(info);
 
 	if (value < 4)
 		value = 4;
@@ -586,7 +590,7 @@
 	unsigned char *ptr;
 	unsigned int residual;
 
-	fas216_checkmagic(info, "fas216_updateptrs");
+	fas216_checkmagic(info);
 
 	ptr = info->scsi.SCp.ptr;
 	residual = info->scsi.SCp.this_residual;
@@ -629,7 +633,7 @@
 	unsigned int residual;
 	char *ptr;
 
-	fas216_checkmagic(info, "fas216_pio");
+	fas216_checkmagic(info);
 
 	residual = info->scsi.SCp.this_residual;
 	ptr = info->scsi.SCp.ptr;
@@ -668,7 +672,7 @@
 {
 	fasdmatype_t dmatype;
 
-	fas216_checkmagic(info, "fas216_starttransfer");
+	fas216_checkmagic(info);
 
 	info->scsi.phase = (direction == DMA_OUT) ?
 				PHASE_DATAOUT : PHASE_DATAIN;
@@ -763,7 +767,7 @@
 static void
 fas216_stoptransfer(FAS216_Info *info)
 {
-	fas216_checkmagic(info, "fas216_stoptransfer");
+	fas216_checkmagic(info);
 
 	if (info->dma.transfer_type != fasdma_none &&
 	    info->dma.transfer_type != fasdma_pio) {
@@ -797,7 +801,7 @@
 static void
 fas216_disconnect_intr(FAS216_Info *info)
 {
-	fas216_checkmagic(info, "fas216_disconnected_intr");
+	fas216_checkmagic(info);
 
 #ifdef DEBUG_CONNECT
 	printk("scsi%d.%c: disconnect phase=%02X\n", info->host->host_no,
@@ -849,7 +853,7 @@
 {
 	unsigned char target, identify_msg, ok;
 
-	fas216_checkmagic(info, "fas216_reselected_intr");
+	fas216_checkmagic(info);
 
 	if ((info->scsi.phase == PHASE_SELECTION ||
 	     info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) {
@@ -949,6 +953,7 @@
 		msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
 		info->scsi.phase = PHASE_MSGOUT_EXPECT;
 	}
+
 	outb(CMD_MSGACCEPTED, REG_CMD(info));
 }
 
@@ -959,7 +964,7 @@
 static void
 fas216_finish_reconnect(FAS216_Info *info)
 {
-	fas216_checkmagic(info, "fas216_reconnect");
+	fas216_checkmagic(info);
 
 #ifdef DEBUG_CONNECT
 	printk("Connected: %1X %1X %02X, reconnected: %1X %1X %02X\n",
@@ -1087,7 +1092,7 @@
 	unsigned int msglen = 1, i;
 	int msgbyte = 0;
 
-	fas216_checkmagic(info, "fas216_message");
+	fas216_checkmagic(info);
 
 	message[0] = inb(REG_FF(info));
 
@@ -1270,7 +1275,7 @@
 {
 	int i;
 
-	fas216_checkmagic(info, "fas216_send_command");
+	fas216_checkmagic(info);
 
 	outb(CMD_NOP|CMD_WITHDMA, REG_CMD(info));
 	outb(CMD_FLUSHFIFO, REG_CMD(info));
@@ -1293,7 +1298,7 @@
 {
 	unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs);
 
-	fas216_checkmagic(info, "fas216_send_messageout");
+	fas216_checkmagic(info);
 
 	outb(CMD_FLUSHFIFO, REG_CMD(info));
 
@@ -1326,7 +1331,7 @@
  */
 static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
 {
-	fas216_checkmagic(info, "fas216_busservice_intr");
+	fas216_checkmagic(info);
 
 #ifdef DEBUG_BUSSERVICE
 	printk("scsi%d.%c: bus service: stat=%02X ssr=%02X phase=%02X\n",
@@ -1520,7 +1525,7 @@
 {
 	int status, message;
 
-	fas216_checkmagic(info, "fas216_funcdone_intr");
+	fas216_checkmagic(info);
 
 #ifdef DEBUG_FUNCTIONDONE
 	printk("scsi%d.%c: function done: stat=%X ssr=%X phase=%02X\n",
@@ -1562,7 +1567,7 @@
 	FAS216_Info *info = (FAS216_Info *)instance->hostdata;
 	unsigned char isr, ssr, stat;
 
-	fas216_checkmagic(info, "fas216_intr");
+	fas216_checkmagic(info);
 
 	stat = inb(REG_STAT(info));
 	ssr = inb(REG_IS(info));
@@ -1571,9 +1576,10 @@
 	add_debug_list(stat, ssr, isr, info->scsi.phase);
 
 	if (stat & STAT_INT) {
-		if (isr & INST_BUSRESET)
+		if (isr & INST_BUSRESET) {
 			printk(KERN_DEBUG "scsi%d.H: bus reset detected\n", instance->host_no);
-		else if (isr & INST_ILLEGALCMD) {
+			scsi_report_bus_reset(instance, 0);
+		} else if (isr & INST_ILLEGALCMD) {
 			printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no);
 			fas216_dumpstate(info);
 		} else if (isr & INST_DISCONNECT)
@@ -1599,22 +1605,35 @@
  */
 static void fas216_kick(FAS216_Info *info)
 {
-	Scsi_Cmnd *SCpnt;
-	int tot_msglen, from_queue = 0;
+	Scsi_Cmnd *SCpnt = NULL;
+	int tot_msglen, from_queue = 0, disconnect_ok;
 
-	fas216_checkmagic(info, "fas216_kick");
+	fas216_checkmagic(info);
 
-	if (info->origSCpnt) {
-		SCpnt = info->origSCpnt;
-		info->origSCpnt = NULL;
-	} else
-		SCpnt = NULL;
+	/*
+	 * Obtain the next command to process.
+	 */
+	do {
+		if (info->reqSCpnt) {
+			SCpnt = info->reqSCpnt;
+			info->reqSCpnt = NULL;
+			break;
+		}
 
-	/* retrieve next command */
-	if (!SCpnt) {
-		SCpnt = queue_remove_exclude(&info->queues.issue, info->busyluns);
-		from_queue = 1;
-	}
+		if (info->origSCpnt) {
+			SCpnt = info->origSCpnt;
+			info->origSCpnt = NULL;
+			break;
+		}
+
+		/* retrieve next command */
+		if (!SCpnt) {
+			SCpnt = queue_remove_exclude(&info->queues.issue,
+						     info->busyluns);
+			from_queue = 1;
+			break;
+		}
+	} while (0);
 
 	if (!SCpnt) /* no command pending - just exit */
 		return;
@@ -1628,16 +1647,6 @@
 	}
 
 	/*
-	 * tagged queuing - allocate a new tag to this command
-	 */
-	if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) {
-		SCpnt->device->current_tag += 1;
-		if (SCpnt->device->current_tag == 0)
-		    SCpnt->device->current_tag = 1;
-		SCpnt->tag = SCpnt->device->current_tag;
-	}
-
-	/*
 	 * claim host busy
 	 */
 	info->scsi.phase = PHASE_SELECTION;
@@ -1653,6 +1662,9 @@
 
 	if (from_queue) {
 #ifdef SCSI2_TAG
+		/*
+		 * tagged queuing - allocate a new tag to this command
+		 */
 		if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE &&
 		    SCpnt->cmnd[0] != INQUIRY) {
 		    SCpnt->device->current_tag += 1;
@@ -1681,41 +1693,48 @@
 		}
 	}
 
-	/* build outgoing message bytes */
-	msgqueue_flush(&info->scsi.msgs);
+	/*
+	 * Don't allow request sense commands to disconnect.
+	 */
+	disconnect_ok = SCpnt->cmnd[0] != REQUEST_SENSE &&
+			info->device[SCpnt->target].disconnect_ok;
 
-	if (info->device[SCpnt->target].disconnect_ok)
-		msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun));
-	else
-		msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(0, SCpnt->lun));
+	/*
+	 * build outgoing message bytes
+	 */
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(disconnect_ok, SCpnt->lun));
 
-	/* add tag message if required */
+	/*
+	 * add tag message if required
+	 */
 	if (SCpnt->tag)
 		msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);
 
+	do {
 #ifdef SCSI2_WIDE
-	if (info->device[SCpnt->target].wide_state == neg_wait) {
-		info->device[SCpnt->target].wide_state = neg_inprogress;
-		msgqueue_addmsg(&info->scsi.msgs, 4,
-				EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
-				info->ifcfg.wide_max_size);
-	}
-#ifdef SCSI2_SYNC
-	else
-#endif
+		if (info->device[SCpnt->target].wide_state == neg_wait) {
+			info->device[SCpnt->target].wide_state = neg_inprogress;
+			msgqueue_addmsg(&info->scsi.msgs, 4,
+					EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
+					info->ifcfg.wide_max_size);
+			break;
+		}
 #endif
 #ifdef SCSI2_SYNC
-	if ((info->device[SCpnt->target].sync_state == neg_wait ||
-	     info->device[SCpnt->target].sync_state == neg_complete) &&
-	    (SCpnt->cmnd[0] == REQUEST_SENSE ||
-	     SCpnt->cmnd[0] == INQUIRY)) {
-		info->device[SCpnt->target].sync_state = neg_inprogress;
-		msgqueue_addmsg(&info->scsi.msgs, 5,
-				EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
-				1000 / info->ifcfg.clockrate,
-				info->ifcfg.sync_max_depth);
-	}
+		if ((info->device[SCpnt->target].sync_state == neg_wait ||
+		     info->device[SCpnt->target].sync_state == neg_complete) &&
+		    (SCpnt->cmnd[0] == REQUEST_SENSE ||
+		     SCpnt->cmnd[0] == INQUIRY)) {
+			info->device[SCpnt->target].sync_state = neg_inprogress;
+			msgqueue_addmsg(&info->scsi.msgs, 5,
+					EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+					1000 / info->ifcfg.clockrate,
+					info->ifcfg.sync_max_depth);
+			break;
+		}
 #endif
+	} while (0);
 
 	/* following what the ESP driver says */
 	outb(0, REG_STCL(info));
@@ -1780,18 +1799,156 @@
 	/* should now get either DISCONNECT or (FUNCTION DONE with BUS SERVICE) intr */
 }
 
+/* Function: void fas216_rq_sns_done(info, SCpnt, result)
+ * Purpose : Finish processing automatic request sense command
+ * Params  : info   - interface that completed
+ *	     SCpnt  - command that completed
+ *	     result - driver byte of result
+ */
+static void
+fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+#ifdef DEBUG_CONNECT
+	printk("scsi%d.%c: request sense complete, result=%04X%02X%02X\n",
+		info->host->host_no, '0' + SCpnt->target, result,
+		SCpnt->SCp.Message, SCpnt->SCp.Status);
+#endif
+
+	if (result != DID_OK || SCpnt->SCp.Status != GOOD)
+		/*
+		 * Something went wrong.  Make sure that we don't
+		 * have valid data in the sense buffer that could
+		 * confuse the higher levels.
+		 */
+		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+
+	/*
+	 * Note that we don't set SCpnt->result, since that should
+	 * reflect the status of the command that we were asked by
+	 * the upper layers to process.  This would have been set
+	 * correctly by fas216_std_done.
+	 */
+	SCpnt->scsi_done(SCpnt);
+}
+
+/* Function: void fas216_std_done(info, SCpnt, result)
+ * Purpose : Finish processing of standard command
+ * Params  : info   - interface that completed
+ *	     SCpnt  - command that completed
+ *	     result - driver byte of result
+ */
+static void
+fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+	info->stats.fins += 1;
+
+	SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
+			info->scsi.SCp.Status;
+
+#ifdef DEBUG_CONNECT
+	printk("scsi%d.%c: command complete, result=%08X, command=",
+		info->host->host_no, '0' + SCpnt->target, SCpnt->result);
+	print_command(SCpnt->cmnd);
+#endif
+
+	/*
+	 * If the driver detected an error, or the command
+	 * was request sense, then we're all done.
+	 */
+	if (result != DID_OK || SCpnt->cmnd[0] == REQUEST_SENSE)
+		goto done;
+
+	/*
+	 * If the command returned CHECK_CONDITION status,
+	 * request the sense information.
+	 */
+	if (info->scsi.SCp.Status == CHECK_CONDITION)
+		goto request_sense;
+
+	/*
+	 * If the command did not complete with GOOD status,
+	 * we are all done here.
+	 */
+	if (info->scsi.SCp.Status != GOOD)
+		goto done;
+
+	/*
+	 * We have successfully completed a command.  Make sure that
+	 * we do not have any buffers left to transfer.  The world
+	 * is not perfect, and we seem to occasionally hit this.
+	 * It can be indicative of a buggy driver, target or the upper
+	 * levels of the SCSI code.
+	 */
+	if (info->scsi.SCp.ptr) {
+		switch (SCpnt->cmnd[0]) {
+		case INQUIRY:
+		case START_STOP:
+//		case READ_CAPACITY:
+		case MODE_SENSE:
+			break;
+
+		default:
+			printk(KERN_ERR "scsi%d.%c: incomplete data transfer "
+				"detected: res=%08X ptr=%p len=%X command=",
+				info->host->host_no, '0' + SCpnt->target,
+				SCpnt->result, info->scsi.SCp.ptr,
+				info->scsi.SCp.this_residual);
+			print_command(SCpnt->cmnd);
+		}
+	}
+
+done:	SCpnt->scsi_done(SCpnt);
+	return;
+
+request_sense:
+	memset(SCpnt->cmnd, 0, sizeof (SCpnt->cmnd));
+	SCpnt->cmnd[0] = REQUEST_SENSE;
+	SCpnt->cmnd[1] = SCpnt->lun << 5;
+	SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+	SCpnt->SCp.buffer = NULL;
+	SCpnt->SCp.buffers_residual = 0;
+	SCpnt->SCp.ptr = (char *)SCpnt->sense_buffer;
+	SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
+	SCpnt->SCp.Message = 0;
+	SCpnt->SCp.Status = 0;
+	SCpnt->sc_data_direction = SCSI_DATA_READ;
+	SCpnt->use_sg = 0;
+	SCpnt->tag = 0;
+	SCpnt->host_scribble = (void *)fas216_rq_sns_done;
+
+	/*
+	 * Place this command into the high priority "request
+	 * sense" slot.  This will be the very next command
+	 * executed, unless a target connects to us.
+	 */
+	if (info->reqSCpnt)
+		printk(KERN_WARNING "scsi%d.%c: loosing request command\n",
+			info->host->host_no, '0' + SCpnt->target);
+	info->reqSCpnt = SCpnt;
+}
+
 /* Function: void fas216_done(FAS216_Info *info, unsigned int result)
- * Purpose : complete processing for command
+ * Purpose : complete processing for current command
  * Params  : info   - interface that completed
  *	     result - driver byte of result
  */
 static void fas216_done(FAS216_Info *info, unsigned int result)
 {
+	void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int);
 	Scsi_Cmnd *SCpnt;
 
-	fas216_checkmagic(info, "fas216_done");
+	fas216_checkmagic(info);
+
+	if (!info->SCpnt)
+		goto no_command;
 
 	SCpnt = info->SCpnt;
+	info->SCpnt = NULL;
+    	info->scsi.phase = PHASE_IDLE;
+
+	if (!SCpnt->scsi_done)
+		goto no_done;
 
 	if (info->scsi.aborting) {
 		printk("scsi%d.%c: uncaught abort - returning DID_ABORT\n",
@@ -1800,66 +1957,39 @@
 		info->scsi.aborting = 0;
 	}
 
-	info->stats.fins += 1;
-
-	if (SCpnt) {
-	    	info->scsi.phase = PHASE_IDLE;
-		info->SCpnt = NULL;
-
-		SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
-				info->scsi.SCp.Status;
-
-		/*
-		 * In theory, this should not happen, but just in case it does.
-		 */
-		if (info->scsi.SCp.ptr &&
-		    info->scsi.SCp.this_residual &&
-		    result == DID_OK) {
-			switch (SCpnt->cmnd[0]) {
-			case INQUIRY:
-			case START_STOP:
-			case READ_CAPACITY:
-			case TEST_UNIT_READY:
-			case MODE_SENSE:
-			case REQUEST_SENSE:
-				break;
-
-			default:
-				switch (status_byte(SCpnt->result)) {
-				case CHECK_CONDITION:
-				case COMMAND_TERMINATED:
-				case BUSY:
-				case QUEUE_FULL:
-				case RESERVATION_CONFLICT:
-					break;
-
-				default:
-					printk(KERN_ERR "scsi%d.H: incomplete data transfer "
-						"detected: res=%08X ptr=%p len=%X command=",
-						info->host->host_no, SCpnt->result,
-						info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
-					print_command(SCpnt->cmnd);
-				}
-			}
-		}
-#ifdef DEBUG_CONNECT
-		printk("scsi%d.%c: scsi command (%p) complete, result=%08X\n",
-			info->host->host_no, fas216_target(info),
-			SCpnt, SCpnt->result);
-#endif
+	/*
+	 * Sanity check the completion - if we have zero bytes left
+	 * to transfer, we should not have a valid pointer.
+	 */
+	if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) {
+		printk("scsi%d.%c: zero bytes left to transfer, but "
+		       "buffer pointer still valid: ptr=%p len=%08x command=",
+		       info->host->host_no, '0' + SCpnt->target,
+		       info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+		info->scsi.SCp.ptr = NULL;
+		print_command(SCpnt->cmnd);
+	}
 
-		if (!SCpnt->scsi_done)
-			panic("scsi%d.H: null scsi_done function in "
-				"fas216_done", info->host->host_no);
+	/*
+	 * Clear down this command as completed.  If we need to request
+	 * the sense information, fas216_kick will re-assert the busy
+	 * status.
+	 */
+	clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);
 
-		clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);
-
-		SCpnt->scsi_done(SCpnt);
-	} else
-		panic("scsi%d.H: null command in fas216_done", info->host->host_no);
+	fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble;
+	fn(info, SCpnt, result);
 
 	if (info->scsi.irq != NO_IRQ)
 		fas216_kick(info);
+	return;
+
+no_command:
+	panic("scsi%d.H: null command in fas216_done",
+		info->host->host_no);
+no_done:
+	panic("scsi%d.H: null scsi_done function in fas216_done",
+		info->host->host_no);
 }
 
 /* Function: int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
@@ -1867,13 +1997,14 @@
  * Params  : SCpnt - Command to queue
  *	     done  - done function to call once command is complete
  * Returns : 0 - success, else error
+ * Notes   : io_request_lock is held, interrupts are disabled.
  */
 int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
 	FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
-	unsigned long flags;
+	int result;
 
-	fas216_checkmagic(info, "fas216_queue_command");
+	fas216_checkmagic(info);
 
 #ifdef DEBUG_CONNECT
 	printk("scsi%d.%c: received queuable command (%p) %02X\n",
@@ -1882,7 +2013,7 @@
 #endif
 
 	SCpnt->scsi_done = done;
-	SCpnt->host_scribble = NULL;
+	SCpnt->host_scribble = (void *)fas216_std_done;
 	SCpnt->result = 0;
 	SCpnt->SCp.Message = 0;
 	SCpnt->SCp.Status = 0;
@@ -1896,10 +2027,16 @@
 		SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->address;
 		SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
 		/*
-		 * Calculate correct buffer length
+		 * Calculate correct buffer length.  Some commands
+		 * come in with the wrong request_bufflen.
 		 */
 		for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++)
 			len += SCpnt->SCp.buffer[buf].length;
+
+		if (SCpnt->request_bufflen != len)
+			printk(KERN_WARNING "scsi%d.%c: bad request buffer "
+			       "length %d, should be %ld\n", info->host->host_no,
+			       '0' + SCpnt->target, SCpnt->request_bufflen, len);
 		SCpnt->request_bufflen = len;
 	} else {
 		SCpnt->SCp.buffer = NULL;
@@ -1908,22 +2045,36 @@
 		SCpnt->SCp.this_residual = SCpnt->request_bufflen;
 	}
 
+	/*
+	 * If the upper SCSI layers pass a buffer, but zero length,
+	 * we aren't interested in the buffer pointer.
+	 */
+	if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) {
+#if 0
+		printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for "
+		       "command ", info->host->host_no, '0' + SCpnt->target);
+		print_command(SCpnt->cmnd);
+#endif
+		SCpnt->SCp.ptr = NULL;
+	}
+
 	info->stats.queues += 1;
 	SCpnt->tag = 0;
 
-	/* add command into execute queue and let it complete under
+	/*
+	 * Add command into execute queue and let it complete under
 	 * whatever scheme we're using.
 	 */
-	if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) {
-		SCpnt->result = DID_ERROR << 16;
-		done(SCpnt);
-	}
-	save_flags_cli(flags);
-	if (!info->SCpnt || info->scsi.disconnectable)
+	result = !queue_add_cmd_ordered(&info->queues.issue, SCpnt);
+
+	/*
+	 * If we successfully added the command,
+	 * kick the interface to get it moving.
+	 */
+	if (result == 0 && (!info->SCpnt || info->scsi.disconnectable))
 		fas216_kick(info);
-	restore_flags(flags);
 
-	return 0;
+	return result;
 }
 
 /* Function: void fas216_internal_done(Scsi_Cmnd *SCpnt)
@@ -1934,7 +2085,7 @@
 {
 	FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
 
-	fas216_checkmagic(info, "fas216_internal_done");
+	fas216_checkmagic(info);
 
 	info->internal_done = 1;
 }
@@ -1943,13 +2094,20 @@
  * Purpose : queue a command for adapter to process.
  * Params  : SCpnt - Command to queue
  * Returns : scsi result code
+ * Notes   : io_request_lock is held, interrupts are disabled.
  */
 int fas216_command(Scsi_Cmnd *SCpnt)
 {
 	FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
-	unsigned long flags;
 
-	fas216_checkmagic(info, "fas216_command");
+	fas216_checkmagic(info);
+
+	/*
+	 * We should only be using this if we don't have an interrupt.
+	 * Provide some "incentive" to use the queueing code.
+	 */
+	if (info->scsi.irq != NO_IRQ)
+		BUG();
 
 	info->internal_done = 0;
 	fas216_queue_command(SCpnt, fas216_internal_done);
@@ -1960,114 +2118,52 @@
 	 * However, we must re-enable interrupts, or else we'll be
 	 * waiting forever.
 	 */
-	save_flags(flags);
-	sti();
+	spin_unlock_irq(&io_request_lock);
 
 	while (!info->internal_done) {
 		/*
-		 * If we don't have an IRQ, then we must
-		 * poll the card for it's interrupt, and
-		 * use that to call this driver's interrupt
-		 * routine.  That way, we keep the command
-		 * progressing.
-		 */
-		if (info->scsi.irq == NO_IRQ) {
-			sti();
-			while (!(inb(REG_STAT(info)) & STAT_INT));
-			cli();
+		 * If we don't have an IRQ, then we must poll the card for
+		 * it's interrupt, and use that to call this driver's
+		 * interrupt routine.  That way, we keep the command
+		 * progressing.  Maybe we can add some inteligence here
+		 * and go to sleep if we know that the device is going
+		 * to be some time (eg, disconnected).
+		 */
+		if (inb(REG_STAT(info)) & STAT_INT) {
+			spin_lock_irq(&io_request_lock);
 			fas216_intr(info->host);
+			spin_unlock_irq(&io_request_lock);
 		}
 	}
 
-	restore_flags(flags);
+	spin_lock_irq(&io_request_lock);
 
 	return SCpnt->result;
 }
 
-/* Prototype: void fas216_reportstatus(Scsi_Cmnd **SCpntp1,
- *				       Scsi_Cmnd **SCpntp2, int result, int no_report)
- * Purpose  : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
- * Params   : SCpntp1 - pointer to command to return
- *	      SCpntp2 - pointer to command to check
- *	      result  - result to pass back to mid-level done function
- * Returns  : *SCpntp2 = NULL if *SCpntp1 is the same command
- *	      structure as *SCpntp2.
- */
-static void fas216_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2,
-				int result, int no_report)
-{
-	Scsi_Cmnd *SCpnt = *SCpntp1;
-
-	if (SCpnt) {
-		*SCpntp1 = NULL;
-
-		SCpnt->result = result;
-		if (!no_report || SCpnt != *SCpntp2)
-			SCpnt->scsi_done(SCpnt);
-	}
-
-	if (SCpnt == *SCpntp2)
-		*SCpntp2 = NULL;
-}
-
-/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
- * Purpose : abort this command
- * Params  : SCpnt - command to abort
- * Returns : FAILED if unable to abort
- */
-int fas216_eh_abort(Scsi_Cmnd *SCpnt)
-{
-	return FAILED;
-}
-
-/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the device associated with this command
- * Params  : SCpnt - command specifing device to reset
- * Returns : FAILED if unable to reset
- */
-int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
-{
-	return FAILED;
-}
-
-/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the complete bus associated with this command
- * Params  : SCpnt - command specifing bus to reset
- * Returns : FAILED if unable to reset
- */
-int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
-{
-	return FAILED;
-}
-
-/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the host associated with this command
- * Params  : SCpnt - command specifing host to reset
- * Returns : FAILED if unable to reset
- */
-int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
-{
-	return FAILED;
-}
-
-enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
+enum res_abort {
+	res_failed,		/* unable to abort		*/
+	res_success,		/* command on issue queue	*/
+	res_success_clear,	/* command marked tgt/lun busy	*/
+	res_hw_abort		/* command on disconnected dev	*/
+};
 
 /*
  * Prototype: enum res_abort fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
- * Purpose  : abort a command on this host
+ * Purpose  : decide how to abort a command
  * Params   : SCpnt - command to abort
  * Returns  : abort status
  */
 static enum res_abort
 fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
 {
-	enum res_abort res = res_not_running;
+	enum res_abort res = res_failed;
 
 	if (queue_removecmd(&info->queues.issue, SCpnt)) {
 		/*
 		 * The command was on the issue queue, and has not been
 		 * issued yet.  We can remove the command from the queue,
-		 * and acknowledge the abort.  Neither the devices nor the
+		 * and acknowledge the abort.  Neither the device nor the
 		 * interface know about the command.
 		 */
 		printk("on issue queue ");
@@ -2075,54 +2171,32 @@
 		res = res_success;
 	} else if (queue_removecmd(&info->queues.disconnected, SCpnt)) {
 		/*
-		 * The command was on the disconnected queue.  Simply
-		 * acknowledge the abort condition, and when the target
-		 * reconnects, we will give it an ABORT message.  The
-		 * target should then disconnect, and we will clear
-		 * the busylun bit.
+		 * The command was on the disconnected queue.  We must
+		 * reconnect with the device if possible, and send it
+		 * an abort message.
 		 */
 		printk("on disconnected queue ");
 
-		res = res_success;
+		res = res_hw_abort;
 	} else if (info->SCpnt == SCpnt) {
-		unsigned long flags;
-
 		printk("executing ");
 
-		save_flags(flags);
-		cli();
 		switch (info->scsi.phase) {
 		/*
 		 * If the interface is idle, and the command is 'disconnectable',
-		 * then it is the same as on the disconnected queue.  We simply
-		 * remove all traces of the command.  When the target reconnects,
-		 * we will give it an ABORT message since the command could not
-		 * be found.  When the target finally disconnects, we will clear
-		 * the busylun bit.
+		 * then it is the same as on the disconnected queue.
 		 */
 		case PHASE_IDLE:
 			if (info->scsi.disconnectable) {
 				info->scsi.disconnectable = 0;
 				info->SCpnt = NULL;
-				res = res_success;
+				res = res_hw_abort;
 			}
 			break;
 
-		/*
-		 * If the command has connected and done nothing futher,
-		 * simply force a disconnect.  We also need to clear the
-		 * busylun bit.
-		 */
-		case PHASE_SELECTION:
-//			info->SCpnt = NULL;
-//			res = res_success_clear;
-//			break;
-
 		default:
-			res = res_snooze;
 			break;
 		}
-		restore_flags(flags);
 	} else if (info->origSCpnt == SCpnt) {
 		/*
 		 * The command will be executed next, but a command
@@ -2139,17 +2213,18 @@
 	return res;
 }
 
-/* Function: int fas216_abort(Scsi_Cmnd *SCpnt)
- * Purpose : abort a command if something horrible happens.
- * Params  : SCpnt - Command that is believed to be causing a problem.
- * Returns : one of SCSI_ABORT_ macros.
+/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+ * Purpose : abort this command
+ * Params  : SCpnt - command to abort
+ * Returns : FAILED if unable to abort
+ * Notes   : io_request_lock is taken, and irqs are disabled
  */
-int fas216_abort(Scsi_Cmnd *SCpnt)
+int fas216_eh_abort(Scsi_Cmnd *SCpnt)
 {
 	FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
-	int result = SCSI_ABORT_SNOOZE;
+	int result = FAILED;
 
-	fas216_checkmagic(info, "fas216_abort");
+	fas216_checkmagic(info);
 
 	info->stats.aborts += 1;
 
@@ -2176,29 +2251,23 @@
 	 */
 	case res_success:
 		printk("success\n");
-		SCpnt->result = DID_ABORT << 16;
-		SCpnt->scsi_done(SCpnt);
-		result = SCSI_ABORT_SUCCESS;
+		result = SUCCESS;
 		break;
 
 	/*
-	 * We did find the command, but unfortunately we couldn't
-	 * unhook it from ourselves.  Wait some more, and if it
-	 * still doesn't complete, reset the interface.
+	 * We need to reconnect to the target and send it an
+	 * ABORT or ABORT_TAG message.  We can only do this
+	 * if the bus is free.
 	 */
-	case res_snooze:
-		printk("snooze\n");
-		result = SCSI_ABORT_SNOOZE;
-		break;
+	case res_hw_abort:
+		
 
 	/*
-	 * The command could not be found (either because it completed,
-	 * or it got dropped.
+	 * We are unable to abort the command for some reason.
 	 */
 	default:
-	case res_not_running:
-		result = SCSI_ABORT_SNOOZE;
-		printk("not running\n");
+	case res_failed:
+		printk("failed\n");
 		break;
 	}
 
@@ -2214,7 +2283,7 @@
 	neg_t sync_state, wide_state;
 	int i;
 
-	fas216_checkmagic(info, "fas216_reset_state");
+	fas216_checkmagic(info);
 
 	/*
 	 * Clear out all stale info in our state structure
@@ -2257,6 +2326,80 @@
 		info->device[i].sof		= 0;
 		info->device[i].wide_xfer	= 0;
 	}
+
+	/*
+	 * Drain all commands on disconnected queue
+	 */
+	while (queue_remove(&info->queues.disconnected) != NULL);
+
+	/*
+	 * Remove executing commands.
+	 */
+	info->SCpnt     = NULL;
+	info->reqSCpnt  = NULL;
+	info->origSCpnt = NULL;
+}
+
+/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the device associated with this command
+ * Params  : SCpnt - command specifing device to reset
+ * Returns : FAILED if unable to reset
+ */
+int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
+
+	printk("scsi%d.%c: "__FUNCTION__": called\n",
+		info->host->host_no, '0' + SCpnt->target);
+	return FAILED;
+}
+
+/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the bus associated with the command
+ * Params  : SCpnt - command specifing bus to reset
+ * Returns : FAILED if unable to reset
+ * Notes   : io_request_lock is taken, and irqs are disabled
+ */
+int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
+	int result = FAILED;
+
+	fas216_checkmagic(info);
+
+	info->stats.bus_resets += 1;
+
+	printk("scsi%d.%c: "__FUNCTION__": resetting bus\n",
+		info->host->host_no, '0' + SCpnt->target);
+
+	/*
+	 * Attempt to stop all activity on this interface.
+	 */
+	outb(info->scsi.cfg[2], REG_CNTL3(info));
+	fas216_stoptransfer(info);
+
+	/*
+	 * Clear any pending interrupts
+	 */
+	while (inb(REG_STAT(info)) & STAT_INT)
+		inb(REG_INST(info));
+
+	/*
+	 * Reset the SCSI bus
+	 */
+	outb(CMD_RESETSCSI, REG_CMD(info));
+	udelay(5);
+
+	/*
+	 * Clear reset interrupt
+	 */
+	if (inb(REG_STAT(info)) & STAT_INT &&
+	    inb(REG_INST(info)) & INST_BUSRESET)
+		result = SUCCESS;
+
+	fas216_reset_state(info);
+
+	return result;
 }
 
 /* Function: void fas216_init_chip(FAS216_Info *info)
@@ -2265,8 +2408,6 @@
  */
 static void fas216_init_chip(FAS216_Info *info)
 {
-	fas216_checkmagic(info, "fas216_init_chip");
-
 	outb(fas216_clockrate(info->ifcfg.clockrate), REG_CLKF(info));
 	outb(info->scsi.cfg[0], REG_CNTL1(info));
 	outb(info->scsi.cfg[1], REG_CNTL2(info));
@@ -2277,100 +2418,144 @@
 	outb(info->scsi.cfg[0], REG_CNTL1(info));
 }
 
-/* Function: int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
- * Purpose : resets the adapter if something horrible happens.
- * Params  : SCpnt - Command that is believed to be causing a problem.
- *	     reset_flags - flags indicating reset type that is believed
- *           to be required.
- * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET
- *           macros.
+/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the host associated with this command
+ * Params  : SCpnt - command specifing host to reset
+ * Returns : FAILED if unable to reset
+ * Notes   : io_request_lock is taken, and irqs are disabled
  */
-int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
 {
 	FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
-	Scsi_Cmnd *SCptr;
-	int result = 0;
-	int synchronous = reset_flags & SCSI_RESET_SYNCHRONOUS;
 
-	fas216_checkmagic(info, "fas216_reset");
+	fas216_checkmagic(info);
+
+	printk("scsi%d.%c: "__FUNCTION__": resetting host\n",
+		info->host->host_no, '0' + SCpnt->target);
 
 	/*
-	 * Validate that command is actually on one of our queues if we're doing
-	 * an asynchronous reset
+	 * Reset the SCSI chip.
 	 */
-	if (reset_flags & SCSI_RESET_ASYNCHRONOUS &&
-	    SCpnt &&
-	    info->SCpnt != SCpnt &&
-	    info->origSCpnt != SCpnt &&
-	    !queue_cmdonqueue(&info->queues.disconnected, SCpnt) &&
-	    !queue_cmdonqueue(&info->queues.issue, SCpnt)) {
-		printk("scsi%d: fas216_reset: asynchronous reset for unknown command\n",
-		       info->host->host_no);
-		return SCSI_RESET_NOT_RUNNING;
-	}
+	outb(CMD_RESETCHIP, REG_CMD(info));
 
-	info->stats.resets += 1;
+	/*
+	 * Ugly ugly ugly!
+	 * We need to release the io_request_lock and enable
+	 * IRQs if we sleep, but we must relock and disable
+	 * IRQs after the sleep.
+	 */
+	spin_unlock_irq(&io_request_lock);
+	scsi_sleep(5);
+	spin_lock_irq(&io_request_lock);
 
-	print_debug_list();
-	printk(KERN_WARNING "scsi%d: reset ", info->host->host_no);
-	if (SCpnt)
-		printk("for target %d ", SCpnt->target);
+	/*
+	 * Release the SCSI reset.
+	 */
+	outb(CMD_NOP, REG_CMD(info));
 
-	printk("\n");
+	fas216_init_chip(info);
 
-	outb(info->scsi.cfg[3], REG_CNTL3(info));
+	return SUCCESS;
+}
 
-	fas216_stoptransfer(info);
+#define TYPE_UNKNOWN	0
+#define TYPE_NCR53C90	1
+#define TYPE_NCR53C90A	2
+#define TYPE_NCR53C9x	3
+#define TYPE_Am53CF94	4
+#define TYPE_EmFAS216	5
+#define TYPE_QLFAS216	6
+
+static char *chip_types[] = {
+	"unknown",
+	"NS NCR53C90",
+	"NS NCR53C90A",
+	"NS NCR53C9x",
+	"AMD Am53CF94",
+	"Emulex FAS216",
+	"QLogic FAS216"
+};
 
-	switch (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) {
-	case SCSI_RESET_SUGGEST_BUS_RESET:
-		outb(CMD_RESETSCSI, REG_CMD(info));
-		outb(CMD_NOP, REG_CMD(info));
-		result |= SCSI_RESET_BUS_RESET;
-		break;
+static int fas216_detect_type(FAS216_Info *info)
+{
+	int family, rev;
 
-	case SCSI_RESET_SUGGEST_HOST_RESET:
-		outb(CMD_RESETCHIP, REG_CMD(info));
-		outb(CMD_NOP, REG_CMD(info));
-		result |= SCSI_RESET_HOST_RESET;
-		break;
+	/*
+	 * Reset the chip.
+	 */
+	outb(CMD_RESETCHIP, REG_CMD(info));
+	udelay(50);
+	outb(CMD_NOP, REG_CMD(info));
 
-	default:
-		outb(CMD_RESETCHIP, REG_CMD(info));
-		outb(CMD_NOP, REG_CMD(info));
-		outb(CMD_RESETSCSI, REG_CMD(info));
-		result |= SCSI_RESET_HOST_RESET | SCSI_RESET_BUS_RESET;
-		break;
-	}
+	/*
+	 * Check to see if control reg 2 is present.
+	 */
+	outb(0, REG_CNTL3(info));
+	outb(CNTL2_S2FE, REG_CNTL2(info));
 
-	udelay(300);
-	fas216_reset_state(info);
-	fas216_init_chip(info);
+	/*
+	 * If we are unable to read back control reg 2
+	 * correctly, it is not present, and we have a
+	 * NCR53C90.
+	 */
+	if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE)
+		return TYPE_NCR53C90;
 
 	/*
-	 * Signal all commands in progress have been reset
+	 * Now, check control register 3
 	 */
-	fas216_reportstatus(&info->SCpnt, &SCpnt, DID_RESET << 16, synchronous);
+	outb(0, REG_CNTL2(info));
+	outb(0, REG_CNTL3(info));
+	outb(5, REG_CNTL3(info));
 
-	while ((SCptr = queue_remove(&info->queues.disconnected)) != NULL)
-		fas216_reportstatus(&SCptr, &SCpnt, DID_RESET << 16, synchronous);
+	/*
+	 * If we are unable to read the register back
+	 * correctly, we have a NCR53C90A
+	 */
+	if (inb(REG_CNTL3(info)) != 5)
+		return TYPE_NCR53C90A;
 
-	if (SCpnt) {
-		/*
-		 * Command not found on disconnected queue, nor currently
-		 * executing command - check pending commands
-		 */
-		if (info->origSCpnt == SCpnt)
-			info->origSCpnt = NULL;
+	/*
+	 * Now read the ID from the chip.
+	 */
+	outb(0, REG_CNTL3(info));
 
-		queue_removecmd(&info->queues.issue, SCpnt);
+	outb(CNTL3_ADIDCHK, REG_CNTL3(info));
+	outb(0, REG_CNTL3(info));
 
-		SCpnt->result = DID_RESET << 16;
-		if (!synchronous)
-			SCpnt->scsi_done(SCpnt);
-	}
+	outb(CMD_RESETCHIP, REG_CMD(info));
+	udelay(5);
+	outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info));
+
+	outb(CNTL2_ENF, REG_CNTL2(info));
+	outb(CMD_RESETCHIP, REG_CMD(info));
+	udelay(5);
+	outb(CMD_NOP, REG_CMD(info));
+
+	rev     = inb(REG1_ID(info));
+	family  = rev >> 3;
+	rev    &= 7;
+
+	switch (family) {
+	case 0x01:
+		if (rev == 4)
+			return TYPE_Am53CF94;
+		break;
+
+	case 0x02:
+		switch (rev) {
+		case 2:
+			return TYPE_EmFAS216;
+		case 3:
+			return TYPE_QLFAS216;
+		}
+		break;
 
-	return result | SCSI_RESET_SUCCESS;
+	default:
+		break;
+	}
+	printk("family %x rev %x\n", family, rev);
+	return TYPE_NCR53C9x;
 }
 
 /* Function: int fas216_init(struct Scsi_Host *instance)
@@ -2381,19 +2566,14 @@
 int fas216_init(struct Scsi_Host *instance)
 {
 	FAS216_Info *info = (FAS216_Info *)instance->hostdata;
-	unsigned long flags;
-	int target_jiffies;
+	int type;
 
 	info->magic_start = MAGIC;
-	info->magic_end = MAGIC;
-
-	info->host = instance;
+	info->magic_end   = MAGIC;
+	info->host        = instance;
 	info->scsi.cfg[0] = instance->this_id;
 	info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE;
 	info->scsi.cfg[2] = info->ifcfg.cntl3 | CNTL3_ADIDCHK | CNTL3_G2CB;
-	info->scsi.type = "unknown";
-	info->SCpnt = NULL;
-	fas216_reset_state(info);
 
 	memset(&info->stats, 0, sizeof(info->stats));
 
@@ -2407,64 +2587,36 @@
 		return 1;
 	}
 
-	outb(CMD_RESETCHIP, REG_CMD(info));
-
-	outb(0, REG_CNTL3(info));
-	outb(CNTL2_S2FE, REG_CNTL2(info));
-
-	if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE) {
-		info->scsi.type = "NCR53C90";
-	} else {
-		outb(0, REG_CNTL2(info));
-		outb(0, REG_CNTL3(info));
-		outb(5, REG_CNTL3(info));
-		if (inb(REG_CNTL3(info)) != 5) {
-			info->scsi.type = "NCR53C90A";
-		} else {
-			outb(0, REG_CNTL3(info));
-			info->scsi.type = "NCR53C9x";
-		}
-	}
-
-
-	outb(CNTL3_ADIDCHK, REG_CNTL3(info));
-	outb(0, REG_CNTL3(info));
-
-	outb(CMD_RESETCHIP, REG_CMD(info));
-	outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info));
-	outb(CNTL2_ENF, REG_CNTL2(info));
-	outb(CMD_RESETCHIP, REG_CMD(info));
-	switch (inb(REG1_ID(info))) {
-	case 12:
-		info->scsi.type = "Am53CF94";
-		break;
-	default:
-		break;
-	}
+	fas216_reset_state(info);
+	type = fas216_detect_type(info);
+	info->scsi.type = chip_types[type];
 
 	udelay(300);
-	/* now for the real initialisation */
+
+	/*
+	 * Initialise the chip correctly.
+	 */
 	fas216_init_chip(info);
 
+	/*
+	 * Reset the SCSI bus.  We don't want to see
+	 * the resulting reset interrupt, so mask it
+	 * out.
+	 */
 	outb(info->scsi.cfg[0] | CNTL1_DISR, REG_CNTL1(info));
 	outb(CMD_RESETSCSI, REG_CMD(info));
 
-	/* scsi standard says 250ms */
-	target_jiffies = jiffies + (25 * HZ) / 100;
-	save_flags(flags);
-	sti();
-
-	while (time_before(jiffies, target_jiffies)) barrier();
-
-	restore_flags(flags);
+	/*
+	 * scsi standard says wait 250ms
+	 */
+	spin_unlock_irq(&io_request_lock);
+	scsi_sleep(5);
+	spin_lock_irq(&io_request_lock);
 
 	outb(info->scsi.cfg[0], REG_CNTL1(info));
 	inb(REG_INST(info));
 
-	/* now for the real initialisation */
-	fas216_init_chip(info);
-
-	fas216_checkmagic(info, "fas216_init");
+	fas216_checkmagic(info);
 
 	return 0;
 }
@@ -2479,7 +2631,7 @@
 {
 	FAS216_Info *info = (FAS216_Info *)instance->hostdata;
 
-	fas216_checkmagic(info, "fas216_release");
+	fas216_checkmagic(info);
 
 	outb(CMD_RESETCHIP, REG_CMD(info));
 	queue_free(&info->queues.disconnected);
@@ -2488,19 +2640,67 @@
 	return 0;
 }
 
+/*
+ * Function: int fas216_info(FAS216_Info *info, char *buffer)
+ * Purpose : generate a string containing information about this
+ *	     host.
+ * Params  : info   - FAS216 host information
+ *	     buffer - string buffer to build string
+ * Returns : size of built string
+ */
+int fas216_info(FAS216_Info *info, char *buffer)
+{
+	char *p = buffer;
+
+	p += sprintf(p, "(%s) at port 0x%08lX ",
+		     info->scsi.type, info->host->io_port);
+
+	if (info->host->irq != NO_IRQ)
+		p += sprintf(p, "irq %d ", info->host->irq);
+	else
+		p += sprintf(p, "no irq ");
+
+	if (info->host->dma_channel != NO_DMA)
+		p += sprintf(p, "dma %d ", info->host->dma_channel);
+	else
+		p += sprintf(p, "no dma ");
+
+	return p - buffer;
+}
+
+int fas216_print_host(FAS216_Info *info, char *buffer)
+{
+	
+	return sprintf(buffer,
+			"\n"
+			"Chip    : %s\n"
+			" Address: 0x%08lX\n"
+			" IRQ    : %d\n"
+			" DMA    : %d\n",
+			info->scsi.type, info->host->io_port,
+			info->host->irq, info->host->dma_channel);
+}
+
 int fas216_print_stats(FAS216_Info *info, char *buffer)
 {
 	return sprintf(buffer,
-			"Queued commands: %-10u   Issued commands: %-10u\n"
-			"Done commands  : %-10u   Reads          : %-10u\n"
-			"Writes         : %-10u   Others         : %-10u\n"
-			"Disconnects    : %-10u   Aborts         : %-10u\n"
-			"Resets         : %-10u\n",
+			"\n"
+			"Command Statistics:\n"
+			" Queued     : %u\n"
+			" Issued     : %u\n"
+			" Completed  : %u\n"
+			" Reads      : %u\n"
+			" Writes     : %u\n"
+			" Others     : %u\n"
+			" Disconnects: %u\n"
+			" Aborts     : %u\n"
+			" Bus resets : %u\n"
+			" Host resets: %u\n",
 			info->stats.queues,	 info->stats.removes,
 			info->stats.fins,	 info->stats.reads,
 			info->stats.writes,	 info->stats.miscs,
 			info->stats.disconnects, info->stats.aborts,
-			info->stats.resets);
+			info->stats.bus_resets,	 info->stats.host_resets);
 }
 
 int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer)
@@ -2531,9 +2731,8 @@
 	return p - buffer;
 }
 
+EXPORT_SYMBOL(fas216_info);
 EXPORT_SYMBOL(fas216_init);
-EXPORT_SYMBOL(fas216_abort);
-EXPORT_SYMBOL(fas216_reset);
 EXPORT_SYMBOL(fas216_queue_command);
 EXPORT_SYMBOL(fas216_command);
 EXPORT_SYMBOL(fas216_intr);
@@ -2542,6 +2741,7 @@
 EXPORT_SYMBOL(fas216_eh_device_reset);
 EXPORT_SYMBOL(fas216_eh_bus_reset);
 EXPORT_SYMBOL(fas216_eh_host_reset);
+EXPORT_SYMBOL(fas216_print_host);
 EXPORT_SYMBOL(fas216_print_stats);
 EXPORT_SYMBOL(fas216_print_device);
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/fas216.h linux/drivers/acorn/scsi/fas216.h
--- v2.3.99-pre3/linux/drivers/acorn/scsi/fas216.h	Mon Aug  2 10:19:52 1999
+++ linux/drivers/acorn/scsi/fas216.h	Sun Apr  2 17:28:22 2000
@@ -1,11 +1,7 @@
 /*
  * FAS216 generic driver
  *
- * Copyright (C) 1997-1998 Russell King
- *
- * NOTE! This file should be viewed using a console with
- * >100 character width (since it uses 8-space tabs)
- * (it used to fit in 80-columns with 4 space)
+ * Copyright (C) 1997-2000 Russell King
  */
 #ifndef FAS216_H
 #define FAS216_H
@@ -215,6 +211,7 @@
 	struct Scsi_Host	*host;			/* host					*/
 	Scsi_Cmnd		*SCpnt;			/* currently processing command		*/
 	Scsi_Cmnd		*origSCpnt;		/* original connecting command		*/
+	Scsi_Cmnd		*reqSCpnt;		/* request sense command		*/
 
 	/* driver information */
 	struct {
@@ -254,7 +251,8 @@
 		unsigned int	miscs;
 		unsigned int	disconnects;
 		unsigned int	aborts;
-		unsigned int	resets;
+		unsigned int	bus_resets;
+		unsigned int	host_resets;
 	} stats;
 
 	/* configuration information */
@@ -350,6 +348,8 @@
  */
 extern int fas216_release (struct Scsi_Host *instance);
 
+extern int fas216_info(FAS216_Info *info, char *buffer);
+extern int fas216_print_host(FAS216_Info *info, char *buffer);
 extern int fas216_print_stats(FAS216_Info *info, char *buffer);
 extern int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer);
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/msgqueue.h linux/drivers/acorn/scsi/msgqueue.h
--- v2.3.99-pre3/linux/drivers/acorn/scsi/msgqueue.h	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/scsi/msgqueue.h	Sun Apr  2 17:28:22 2000
@@ -1,7 +1,7 @@
 /*
  * msgqueue.h: message queue handling
  *
- * (c) 1997 Russell King
+ * Copyright (C) 1997 Russell King
  */
 #ifndef MSGQUEUE_H
 #define MSGQUEUE_H
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/powertec.c linux/drivers/acorn/scsi/powertec.c
--- v2.3.99-pre3/linux/drivers/acorn/scsi/powertec.c	Tue Dec 14 01:27:23 1999
+++ linux/drivers/acorn/scsi/powertec.c	Sun Apr  2 17:28:22 2000
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/drivers/scsi/powertec.c
  *
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
  *
  * This driver is based on experimentation.  Hence, it may have made
  * assumptions about the particular card that I have available, and
@@ -13,6 +13,7 @@
  *  15-04-1998	RMK	Only do PIO if FAS216 will allow it.
  *  02-05-1998	RMK	Moved DMA sg list into per-interface structure.
  *  27-06-1998	RMK	Changed asm/delay.h to linux/delay.h
+ *  02-04-2000	RMK	Updated for new error handling code.
  */
 
 #include <linux/module.h>
@@ -67,7 +68,7 @@
  */
 #define VER_MAJOR	0
 #define VER_MINOR	0
-#define VER_PATCH	2
+#define VER_PATCH	5
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("Powertec SCSI driver");
@@ -345,25 +346,11 @@
 	static char string[100], *p;
 
 	p = string;
-	p += sprintf(string, "%s at port %lX ",
-		     host->hostt->name, host->io_port);
-
-	if (host->irq != NO_IRQ)
-		p += sprintf(p, "irq %d ", host->irq);
-	else
-		p += sprintf(p, "NO IRQ ");
-
-	if (host->dma_channel != NO_DMA)
-		p += sprintf(p, "dma %d ", host->dma_channel);
-	else
-		p += sprintf(p, "NO DMA ");
-
-	p += sprintf(p, "v%d.%d.%d scsi %s",
+	p += sprintf(p, "%s ", host->hostt->name);
+	p += fas216_info(&info->info, p);
+	p += sprintf(p, "v%d.%d.%d terminators o%s",
 		     VER_MAJOR, VER_MINOR, VER_PATCH,
-		     info->info.scsi.type);
-
-	p += sprintf(p, " terminators %s",
-		     info->control.terms ? "on" : "off");
+		     info->control.terms ? "n" : "ff");
 
 	return string;
 }
@@ -403,13 +390,13 @@
  *					int length, int host_no, int inout)
  * Purpose  : Return information about the driver to a user process accessing
  *	      the /proc filesystem.
- * Params   : buffer - a buffer to write information to
- *	      start  - a pointer into this buffer set by this routine to the start
- *		       of the required information.
- *	      offset - offset into information that we have read upto.
- *	      length - length of buffer
+ * Params   : buffer  - a buffer to write information to
+ *	      start   - a pointer into this buffer set by this routine to the start
+ *		        of the required information.
+ *	      offset  - offset into information that we have read upto.
+ *	      length  - length of buffer
  *	      host_no - host number to return information for
- *	      inout  - 0 for reading, 1 for writing.
+ *	      inout   - 0 for reading, 1 for writing.
  * Returns  : length of data written to buffer.
  */
 int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
@@ -437,16 +424,14 @@
 	pos = sprintf(buffer,
 			"PowerTec SCSI driver version %d.%d.%d\n",
 			VER_MAJOR, VER_MINOR, VER_PATCH);
-	pos += sprintf(buffer + pos,
-			"Address: %08lX    IRQ : %d     DMA : %d\n"
-			"FAS    : %-10s  TERM: %-3s\n\n"
-			"Statistics:\n",
-			host->io_port, host->irq, host->dma_channel,
-			info->info.scsi.type, info->control.terms ? "on" : "off");
+
+	pos += fas216_print_host(&info->info, buffer + pos);
+	pos += sprintf(buffer + pos, "Term    : o%s\n",
+			info->control.terms ? "n" : "ff");
 
 	pos += fas216_print_stats(&info->info, buffer + pos);
 
-	pos += sprintf (buffer+pos, "\nAttached devices:\n");
+	pos += sprintf(buffer+pos, "\nAttached devices:\n");
 
 	for (scd = host->host_queue; scd; scd = scd->next) {
 		pos += fas216_print_device(&info->info, scd, buffer + pos);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/powertec.h linux/drivers/acorn/scsi/powertec.h
--- v2.3.99-pre3/linux/drivers/acorn/scsi/powertec.h	Fri May  8 00:42:39 1998
+++ linux/drivers/acorn/scsi/powertec.h	Sun Apr  2 17:28:22 2000
@@ -1,7 +1,7 @@
 /*
  * PowerTec SCSI driver
  *
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
  */
 #ifndef POWERTECSCSI_H
 #define POWERTECSCSI_H
@@ -38,28 +38,25 @@
 
 #include "fas216.h"
 
-#define POWERTECSCSI {							\
-proc_info:	powertecscsi_proc_info,					\
-name:		"PowerTec SCSI",					\
-detect:		powertecscsi_detect,	/* detect		*/	\
-release:	powertecscsi_release,	/* release		*/	\
-info:		powertecscsi_info,	/* info			*/	\
-command:	fas216_command,		/* command		*/	\
-queuecommand:	fas216_queue_command,	/* queuecommand		*/	\
-abort:		fas216_abort,		/* abort		*/	\
-reset:		fas216_reset,		/* reset		*/	\
-bios_param:	scsicam_bios_param,	/* biosparam		*/	\
-can_queue:	CAN_QUEUE,		/* can queue		*/	\
-this_id:	SCSI_ID,		/* scsi host id		*/	\
-sg_tablesize:	SG_ALL,			/* sg_tablesize		*/	\
-cmd_per_lun:	CMD_PER_LUN,		/* cmd per lun		*/	\
-use_clustering:	ENABLE_CLUSTERING,					\
-eh_strategy_handler:		NULL,					\
-eh_host_reset_handler:		fas216_eh_host_reset,			\
-eh_bus_reset_handler:		fas216_eh_bus_reset,			\
-eh_device_reset_handler:	fas216_eh_device_reset,			\
-eh_abort_handler:		fas216_eh_abort,			\
-use_new_eh_code:		0					\
+#define POWERTECSCSI {					\
+proc_info:			powertecscsi_proc_info,	\
+name:				"PowerTec SCSI",	\
+detect:				powertecscsi_detect,	\
+release:			powertecscsi_release,	\
+info:				powertecscsi_info,	\
+bios_param:			scsicam_bios_param,	\
+can_queue:			CAN_QUEUE,		\
+this_id:			SCSI_ID,		\
+sg_tablesize:			SG_ALL,			\
+cmd_per_lun:			CMD_PER_LUN,		\
+use_clustering:			ENABLE_CLUSTERING,	\
+command:			fas216_command,		\
+queuecommand:			fas216_queue_command,	\
+eh_host_reset_handler:		fas216_eh_host_reset,	\
+eh_bus_reset_handler:		fas216_eh_bus_reset,	\
+eh_device_reset_handler:	fas216_eh_device_reset,	\
+eh_abort_handler:		fas216_eh_abort,	\
+use_new_eh_code:		1			\
 	}
 
 #ifndef HOSTS_C
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/acorn/scsi/queue.h linux/drivers/acorn/scsi/queue.h
--- v2.3.99-pre3/linux/drivers/acorn/scsi/queue.h	Thu Sep 25 14:35:09 1997
+++ linux/drivers/acorn/scsi/queue.h	Sun Apr  2 17:28:22 2000
@@ -1,7 +1,7 @@
 /*
  * queue.h: queue handling
  *
- * (c) 1997 Russell King
+ * Copyright (C) 1997 Russell King
  */
 #ifndef QUEUE_H
 #define QUEUE_H
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c
--- v2.3.99-pre3/linux/drivers/atm/fore200e.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/fore200e.c	Mon Mar 27 09:44:58 2000
@@ -45,10 +45,7 @@
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
-
-#ifdef CONFIG_ATM_FORE200E_PCA
 #include <linux/pci.h>
-#endif
 
 #ifdef CONFIG_ATM_FORE200E_SBA
 #include <asm/idprom.h>
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.3.99-pre3/linux/drivers/block/Config.in	Sun Mar 19 18:35:30 2000
+++ linux/drivers/block/Config.in	Mon Apr 10 23:04:49 2000
@@ -12,9 +12,7 @@
    tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP
-   fi
+   dep_bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP $CONFIG_EXPERIMENTAL
 fi
 if [ "$CONFIG_MCA" = "y" ]; then
    tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
@@ -30,36 +28,28 @@
       tristate '  Atari SLM laser printer support' CONFIG_ATARI_SLM
    fi
 fi
-tristate 'XT hard disk support' CONFIG_BLK_DEV_XD
+dep_tristate 'XT hard disk support' CONFIG_BLK_DEV_XD $CONFIG_ISA
 dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARPORT
 if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
    source drivers/block/paride/Config.in
 fi
-
-if [ "$CONFIG_PCI" = "y" ]; then
-   tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
-   tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960
-fi
+dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI
+dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI
 
 comment 'Additional Block Devices'
 
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-if [ "$CONFIG_NET" = "y" ]; then
-   tristate 'Network block device support' CONFIG_BLK_DEV_NBD
-fi
+dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
+
 bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
-if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
-   tristate '  Linear (append) mode' CONFIG_MD_LINEAR
-   tristate '  RAID-0 (striping) mode' CONFIG_MD_STRIPED
-#   tristate '  RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
-#   tristate '  RAID-4/RAID-5 mode' CONFIG_MD_RAID5
-fi
-#if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
-#   bool '    Boot support (linear, striped)' CONFIG_MD_BOOT
-#fi
-tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
-if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
-   bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+dep_tristate '  Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD
+dep_tristate '  RAID-0 (striping) mode' CONFIG_MD_STRIPED $CONFIG_BLK_DEV_MD
+#dep_tristate '  RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING $CONFIG_BLK_DEV_MD
+#dep_tristate '  RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD
+if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
+   bool '    Boot support (linear, striped)' CONFIG_MD_BOOT
 fi
+tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
 
 endmenu
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.99-pre3/linux/drivers/block/ll_rw_blk.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/block/ll_rw_blk.c	Tue Apr  4 19:25:14 2000
@@ -481,7 +481,7 @@
 	elevator_merge_requests(&q->elevator, req, next);
 	req->bhtail->b_reqnext = next->bh;
 	req->bhtail = next->bhtail;
-	req->nr_sectors += next->nr_sectors;
+	req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors;
 	next->rq_status = RQ_INACTIVE;
 	list_del(&next->queue);
 	wake_up (&wait_for_request);
@@ -685,7 +685,7 @@
 				break;
 			req->bhtail->b_reqnext = bh;
 			req->bhtail = bh;
-		    	req->nr_sectors += count;
+		    	req->nr_sectors = req->hard_nr_sectors += count;
 			drive_stat_acct(req, count, 0);
 
 			elevator_merge_after(elevator, req, latency);
@@ -714,8 +714,8 @@
 		    	req->bh = bh;
 		    	req->buffer = bh->b_data;
 		    	req->current_nr_sectors = count;
-		    	req->sector = sector;
-		    	req->nr_sectors += count;
+		    	req->sector = req->hard_sector = sector;
+		    	req->nr_sectors = req->hard_nr_sectors += count;
 			drive_stat_acct(req, count, 0);
 
 			elevator_merge_before(elevator, req, latency);
@@ -754,8 +754,8 @@
 /* fill up the request-info, and add it to the queue */
 	req->cmd = rw;
 	req->errors = 0;
-	req->sector = sector;
-	req->nr_sectors = count;
+	req->hard_sector = req->sector = sector;
+	req->hard_nr_sectors = req->nr_sectors = count;
 	req->current_nr_sectors = count;
 	req->nr_segments = 1; /* Always 1 for a new request. */
 	req->nr_hw_segments = 1; /* Always 1 for a new request. */
@@ -920,23 +920,21 @@
 	int nsect;
 
 	req->errors = 0;
-	if (!uptodate) {
+	if (!uptodate)
 		printk("end_request: I/O error, dev %s (%s), sector %lu\n",
 			kdevname(req->rq_dev), name, req->sector);
-		if ((bh = req->bh) != NULL) {
-			nsect = bh->b_size >> 9;
-			req->nr_sectors--;
-			req->nr_sectors &= ~(nsect - 1);
-			req->sector += nsect;
-			req->sector &= ~(nsect - 1);
-		}
-	}
 
 	if ((bh = req->bh) != NULL) {
+		nsect = bh->b_size >> 9;
 		req->bh = bh->b_reqnext;
 		bh->b_reqnext = NULL;
 		bh->b_end_io(bh, uptodate);
 		if ((bh = req->bh) != NULL) {
+			req->hard_sector += nsect;
+			req->hard_nr_sectors -= nsect;
+			req->sector = req->hard_sector;
+			req->nr_sectors = req->hard_nr_sectors;
+
 			req->current_nr_sectors = bh->b_size >> 9;
 			if (req->nr_sectors < req->current_nr_sectors) {
 				req->nr_sectors = req->current_nr_sectors;
@@ -1072,6 +1070,12 @@
 #endif
 #ifdef CONFIG_BLK_DEV_NBD
 	nbd_init();
+#endif
+#ifdef CONFIG_MDISK
+	mdisk_init();
+#endif
+#ifdef CONFIG_DASD
+	dasd_init();
 #endif
 	return 0;
 };
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/block/lvm.c linux/drivers/block/lvm.c
--- v2.3.99-pre3/linux/drivers/block/lvm.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/block/lvm.c	Mon Mar 27 09:44:58 2000
@@ -931,7 +931,7 @@
 		printk(KERN_DEBUG
 		       "%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name);
 #endif
-		if (put_user(lv->lv_read_ahead, (long *)arg))
+		if (put_user(lv_ptr->lv_read_ahead, (long *)arg))
 			return -EFAULT;
 		break;
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.3.99-pre3/linux/drivers/block/md.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/block/md.c	Mon Apr 10 23:04:49 2000
@@ -1805,6 +1805,136 @@
 
 #undef OUT
 
+/* support old ioctls/init - cold add only */
+int do_md_add(mddev_t *mddev, kdev_t dev)
+{
+	int err;
+	mdk_rdev_t *rdev;
+	
+	if (mddev->sb || mddev->pers)
+		return -EBUSY;
+	err = md_import_device(dev, 0);
+	if (err) return err;
+	rdev = find_rdev_all(dev);
+	if (!rdev) {
+		MD_BUG();
+		return -EINVAL;
+	}
+	rdev->old_dev = dev;
+	rdev->desc_nr = mddev->nb_dev;
+	bind_rdev_to_array(rdev, mddev);
+	return 0;
+}
+
+#define SET_SB(x,v) mddev->sb->x = v
+#define SET_RSB(x,y) mddev->sb->disks[nr].x = y
+static void autorun_array (mddev_t *mddev);
+int do_md_start(mddev_t *mddev, int info)
+{
+	int pers = (info & 0xFF0000UL)>>16;
+//	int fault= (info & 0x00FF00UL)>>8;
+	int factor=(info & 0x0000FFUL);
+
+	struct md_list_head *tmp;
+	mdk_rdev_t *rdev, *rdev0=NULL;
+	int err = 0;
+
+	if (mddev->sb) {
+		printk("array md%d already has superbloc!!\n",
+		       mdidx(mddev));
+		return -EBUSY;
+	}
+	if (pers==1 || pers==2) {
+		/* non-persistant super block */
+		int devs = mddev->nb_dev;
+		if (alloc_array_sb(mddev))
+			return -ENOMEM;
+		mddev->sb->major_version = MD_MAJOR_VERSION;
+		mddev->sb->minor_version = MD_MINOR_VERSION;
+		mddev->sb->patch_version = MD_PATCHLEVEL_VERSION;
+		mddev->sb->ctime = CURRENT_TIME;
+
+		SET_SB(level,pers_to_level(pers));
+		SET_SB(size,0);
+		SET_SB(nr_disks, devs);
+		SET_SB(raid_disks, devs);
+		SET_SB(md_minor,mdidx(mddev));
+		SET_SB(not_persistent, 1);
+
+		
+		SET_SB(state, 1<<MD_SB_CLEAN);
+		SET_SB(active_disks, devs);
+		SET_SB(working_disks, devs);
+		SET_SB(failed_disks, 0);
+		SET_SB(spare_disks, 0);
+
+		SET_SB(layout,0);
+		SET_SB(chunk_size, 1<<(factor+PAGE_SHIFT));
+
+		mddev->sb->md_magic = MD_SB_MAGIC;
+
+		/*
+		 * Generate a 128 bit UUID
+		 */
+		get_random_bytes(&mddev->sb->set_uuid0, 4);
+		get_random_bytes(&mddev->sb->set_uuid1, 4);
+		get_random_bytes(&mddev->sb->set_uuid2, 4);
+		get_random_bytes(&mddev->sb->set_uuid3, 4);
+
+		/* add each disc */
+		ITERATE_RDEV(mddev,rdev,tmp) {
+			int nr, size;
+			nr = rdev->desc_nr;
+			SET_RSB(number,nr);
+			SET_RSB(major,MAJOR(rdev->dev));
+			SET_RSB(minor,MINOR(rdev->dev));
+			SET_RSB(raid_disk,nr);
+			SET_RSB(state,6); /* ACTIVE|SYNC */
+			size = calc_dev_size(rdev->dev, mddev, 0);
+			rdev->sb_offset = calc_dev_sboffset(rdev->dev, mddev, 0);
+
+			if (!mddev->sb->size || (mddev->sb->size > size))
+				mddev->sb->size = size;			
+		}
+		sync_sbs(mddev);
+		err = do_md_run(mddev);
+		if (err)
+			do_md_stop(mddev, 0);
+	} else {
+		/* persistant super block - ignore the info and read the superblocks */
+		ITERATE_RDEV(mddev,rdev,tmp) {
+			if ((err = read_disk_sb(rdev))) {
+				printk("md: could not read %s's sb, not importing!\n",
+				       partition_name(rdev->dev));
+				break;
+			}
+			if ((err = check_disk_sb(rdev))) {
+				printk("md: %s has invalid sb, not importing!\n",
+				       partition_name(rdev->dev));
+				break;
+			}
+			rdev->desc_nr = rdev->sb->this_disk.number;
+			if (!rdev0) rdev0=rdev;
+			if (!uuid_equal(rdev0, rdev)) {
+				printk("%s has different UUID to %s .. dropping\n",
+				       partition_name(rdev->dev),
+				       partition_name(rdev0->dev));
+				err = -EINVAL;
+				break;
+			}
+			if (!sb_equal(rdev0->sb, rdev->sb)) {
+				printk("%s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev));
+				err = -EINVAL;
+				break;
+			}
+		}
+		if (!err)
+			autorun_array(mddev);
+	}
+	return err;
+}
+#undef SET_SB
+#undef SET_RSB
 /*
  * We have to safely support old arrays too.
  */
@@ -2573,6 +2703,58 @@
 			}
 		default:
 	}
+	/* handle "old style" ioctls */
+	switch (cmd)
+	{
+	case START_MD:
+		if (!mddev)
+			return -ENODEV;
+		err = lock_mddev(mddev);
+		if (err) {
+			printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd);
+			goto abort;
+		}
+		err = do_md_start(mddev, (int) arg);
+		if (err) {
+			printk("couldn't mdstart\n");
+			goto abort_unlock;
+		}
+		goto done_unlock;
+	case STOP_MD:
+		if (!mddev)
+			return -ENODEV;
+		err = lock_mddev(mddev);
+		if (err) {
+			printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd);
+			goto abort_unlock;
+		}
+		err =  do_md_stop(mddev, 0);
+		if (err) {
+			printk("couldn't mdstop\n");
+			goto abort_unlock;
+		}
+		goto done_unlock;
+	case REGISTER_DEV:
+		/* add this device to an unstarted array,
+		 * create the array if needed */
+		if (!mddev)
+			mddev = alloc_mddev(dev);
+		if (!mddev) {
+			err = -ENOMEM;
+			goto abort;
+		}
+		err = lock_mddev(mddev);
+		if (err) {
+			printk("ioctl, reason %d, cmd %d\n", err, cmd);
+			goto abort;
+		}
+		err = do_md_add(mddev, to_kdev_t((dev_t) arg));
+		if (err) {
+			printk("do_md_add failed %d\n", err);
+			goto abort_unlock;
+		}
+		goto done_unlock;
+	}
 
 	switch (cmd)
 	{
@@ -2593,7 +2775,7 @@
 			err = set_array_info(mddev, (void *)arg);
 			if (err) {
 				printk("couldnt set array info. %d\n", err);
-				goto abort;
+				goto abort_unlock;
 			}
 			goto done_unlock;
 
@@ -3188,10 +3370,11 @@
 }
 
 #ifdef CONFIG_MD_BOOT
+#define MAX_MD_BOOT_DEVS	16
 struct {
 	unsigned long set;
-	int pers[MAX_MD_DEVS];
-	kdev_t devices[MAX_MD_DEVS][MAX_REAL];
+	int pers[MAX_MD_BOOT_DEVS];
+	kdev_t devices[MAX_MD_BOOT_DEVS][MAX_REAL];
 } md_setup_args md__initdata = {
 	0,{0},{{0}}
 };
@@ -3219,7 +3402,7 @@
 	   get_option(&str, &fault) != 2) {
 		printk("md: Too few arguments supplied to md=.\n");
 		return 0;
-	} else if (minor >= MAX_MD_DEVS) {
+	} else if (minor >= MAX_MD_BOOT_DEVS) {
  		printk ("md: Minor device number too high.\n");
 		return 0;
 	} else if (md_setup_args.set & (1 << minor)) {
@@ -3229,13 +3412,13 @@
 	switch(level) {
 #ifdef CONFIG_MD_LINEAR
 	case -1:
-		level = LINEAR;
+		level = LINEAR<<16;
 		pername = "linear";
  		break;
 #endif
 #ifdef CONFIG_MD_STRIPED
 	case 0:
-		level = STRIPED;
+		level = STRIPED<<16;
 		pername = "striped";
  		break;
 #endif
@@ -3263,9 +3446,9 @@
 	printk ("md: Will configure md%d (%s) from %s, below.\n",
 		minor, pername, devnames);
 	md_setup_args.devices[minor][i] = (kdev_t) 0;
-	md_setup_args.pers[minor] = level | factor | (fault << FAULT_SHIFT);
+	md_setup_args.pers[minor] = level | factor | (fault << 8);
 	md_setup_args.set |= (1 << minor);
-	return 0;
+	return 1;
 }
 #endif
 
@@ -3273,7 +3456,7 @@
 {
 	int i;
 
-	for(i = 0; i < MAX_MD_DEVS; i++) {
+	for(i = 0; i < MAX_MD_BOOT_DEVS; i++) {
 		md_blocksizes[i] = 1024;
 		md_size[i] = 0;
 		md_maxreadahead[i] = MD_READAHEAD;
@@ -3344,20 +3527,20 @@
 }
 
 #ifdef CONFIG_MD_BOOT
-static void __init md_setup_drive(void)
+void __init md_setup_drive(void)
 {
-	if(md_setup_args.set)
-		do_md_setup(md_setup_args.str, md_setup_args.ints);
 	int minor, i;
 	kdev_t dev;
+	mddev_t*mddev;
 
-	for (minor = 0; minor < MAX_MD_DEVS; minor++) {
+	for (minor = 0; minor < MAX_MD_BOOT_DEVS; minor++) {
 		if ((md_setup_args.set & (1 << minor)) == 0)
 			continue;
 		printk("md: Loading md%d.\n", minor);
+		mddev = alloc_mddev(MKDEV(MD_MAJOR,minor));
 		for (i = 0; (dev = md_setup_args.devices[minor][i]); i++)
-			do_md_add (minor, dev);
-		do_md_run (minor, md_setup_args.pers[minor]);
+			do_md_add (mddev, dev);
+		do_md_start (mddev, md_setup_args.pers[minor]);
 	}
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/block/nbd.c linux/drivers/block/nbd.c
--- v2.3.99-pre3/linux/drivers/block/nbd.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/block/nbd.c	Tue Apr 11 06:59:13 2000
@@ -350,6 +350,7 @@
 {
 	struct nbd_device *lo;
 	int dev, error, temp;
+	struct request sreq ;
 
 	/* Anyone capable of this syscall can do *real bad* things */
 
@@ -363,6 +364,13 @@
 
 	lo = &nbd_dev[dev];
 	switch (cmd) {
+	case NBD_DISCONNECT:
+	        printk("NBD_DISCONNECT\n") ;
+                sreq.cmd=2 ; /* shutdown command */
+                if (!lo->sock) return -EINVAL ;
+                nbd_send_req(lo->sock,&sreq) ;
+                return 0 ;
+ 
 	case NBD_CLEAR_SOCK:
 		down(&lo->queue_lock);
 		nbd_clear_que(lo);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c
--- v2.3.99-pre3/linux/drivers/block/paride/pcd.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/paride/pcd.c	Tue Apr  4 19:25:14 2000
@@ -765,7 +765,7 @@
 			pcd_unit = unit;
 		}
 	        pcd_sector = CURRENT->sector;
-	        pcd_count = CURRENT->nr_sectors;
+	        pcd_count = CURRENT->current_nr_sectors;
 	        pcd_buf = CURRENT->buffer;
 		pcd_busy = 1;
 	        ps_set_intr(do_pcd_read,0,0,nice); 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c
--- v2.3.99-pre3/linux/drivers/block/paride/pd.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/paride/pd.c	Tue Apr  4 19:25:14 2000
@@ -385,9 +385,62 @@
 	}
 }
 
+static inline int pd_new_segment(request_queue_t *q, struct request *req, int max_segments)
+{
+	if (max_segments > cluster)
+		max_segments = cluster;
+
+	if (req->nr_segments < max_segments) {
+		req->nr_segments++;
+		q->elevator.nr_segments++;
+		return 1;
+	}
+	return 0;
+}
+
+static int pd_back_merge_fn(request_queue_t *q, struct request *req, 
+			    struct buffer_head *bh, int max_segments)
+{
+	if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
+		return 1;
+	return pd_new_segment(q, req, max_segments);
+}
+
+static int pd_front_merge_fn(request_queue_t *q, struct request *req, 
+			     struct buffer_head *bh, int max_segments)
+{
+	if (bh->b_data + bh->b_size == req->bh->b_data)
+		return 1;
+	return pd_new_segment(q, req, max_segments);
+}
+
+static int pd_merge_requests_fn(request_queue_t *q, struct request *req,
+				struct request *next, int max_segments)
+{
+	int total_segments = req->nr_segments + next->nr_segments;
+	int same_segment;
+
+	if (max_segments > cluster)
+		max_segments = cluster;
+
+	same_segment = 0;
+	if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) {
+		total_segments--;
+		same_segment = 1;
+	}
+    
+	if (total_segments > max_segments)
+		return 0;
+
+	q->elevator.nr_segments -= same_segment;
+	req->nr_segments = total_segments;
+	return 1;
+}
+
 int pd_init (void)
 
 {       int i;
+	request_queue_t * q; 
 
 	if (disable) return -1;
         if (devfs_register_blkdev(MAJOR_NR,name,&pd_fops)) {
@@ -395,7 +448,11 @@
                         name,major);
                 return -1;
         }
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+	q = BLK_DEFAULT_QUEUE(MAJOR_NR);
+	blk_init_queue(q, DEVICE_REQUEST);
+	q->back_merge_fn = pd_back_merge_fn;
+	q->front_merge_fn = pd_front_merge_fn;
+	q->merge_requests_fn = pd_merge_requests_fn;
         read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
         
 	pd_gendisk.major = major;
@@ -865,7 +922,6 @@
 static void do_pd_request (request_queue_t * q)
 
 {       struct buffer_head * bh;
-	struct request * req;
 	int	unit;
 
         if (pd_busy) return;
@@ -876,12 +932,10 @@
         pd_dev = MINOR(CURRENT->rq_dev);
 	pd_unit = unit = DEVICE_NR(CURRENT->rq_dev);
         pd_block = CURRENT->sector;
-        pd_count = CURRENT->nr_sectors;
+        pd_run = CURRENT->nr_sectors;
+        pd_count = CURRENT->current_nr_sectors;
 
 	bh = CURRENT->bh;
-	req = CURRENT;
-	if (bh->b_reqnext)
-		printk("%s: OUCH: b_reqnext != NULL\n",PD.name);
 
         if ((pd_dev >= PD_DEVS) || 
 	    ((pd_block+pd_count) > pd_hd[pd_dev].nr_sects)) {
@@ -890,14 +944,6 @@
         }
 
 	pd_cmd = CURRENT->cmd;
-	pd_run = pd_count;
-        while ((pd_run <= cluster) &&
-	       (req = blkdev_next_request(req)) && 
-	       (pd_block+pd_run == req->sector) &&
-	       (pd_cmd == req->cmd) &&
-	       (pd_dev == MINOR(req->rq_dev)))
-			pd_run += req->nr_sectors;
-
 	pd_poffs = pd_hd[pd_dev].start_sect;
         pd_block += pd_poffs;
         pd_buf = CURRENT->buffer;
@@ -932,7 +978,7 @@
 		printk("%s: OUCH: request list changed unexpectedly\n",
 			PD.name);
 
-	pd_count = CURRENT->nr_sectors;
+	pd_count = CURRENT->current_nr_sectors;
 	pd_buf = CURRENT->buffer;
 	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c
--- v2.3.99-pre3/linux/drivers/block/paride/pf.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/paride/pf.c	Tue Apr  4 19:25:14 2000
@@ -339,9 +339,62 @@
         }
 } 
 
+static inline int pf_new_segment(request_queue_t *q, struct request *req, int max_segments)
+{
+	if (max_segments > cluster)
+		max_segments = cluster;
+
+	if (req->nr_segments < max_segments) {
+		req->nr_segments++;
+		q->elevator.nr_segments++;
+		return 1;
+	}
+	return 0;
+}
+
+static int pf_back_merge_fn(request_queue_t *q, struct request *req, 
+			    struct buffer_head *bh, int max_segments)
+{
+	if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
+		return 1;
+	return pf_new_segment(q, req, max_segments);
+}
+
+static int pf_front_merge_fn(request_queue_t *q, struct request *req, 
+			     struct buffer_head *bh, int max_segments)
+{
+	if (bh->b_data + bh->b_size == req->bh->b_data)
+		return 1;
+	return pf_new_segment(q, req, max_segments);
+}
+
+static int pf_merge_requests_fn(request_queue_t *q, struct request *req,
+				struct request *next, int max_segments)
+{
+	int total_segments = req->nr_segments + next->nr_segments;
+	int same_segment;
+
+	if (max_segments > cluster)
+		max_segments = cluster;
+
+	same_segment = 0;
+	if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) {
+		total_segments--;
+		same_segment = 1;
+	}
+    
+	if (total_segments > max_segments)
+		return 0;
+
+	q->elevator.nr_segments -= same_segment;
+	req->nr_segments = total_segments;
+	return 1;
+}
+
 int pf_init (void)      /* preliminary initialisation */
 
 {       int i;
+	request_queue_t * q; 
 
 	if (disable) return -1;
 
@@ -355,7 +408,11 @@
                         major);
                 return -1;
         }
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+	q = BLK_DEFAULT_QUEUE(MAJOR_NR);
+	blk_init_queue(q, DEVICE_REQUEST);
+	q->back_merge_fn = pf_back_merge_fn;
+	q->front_merge_fn = pf_front_merge_fn;
+	q->merge_requests_fn = pf_merge_requests_fn;
         read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
         
 	for (i=0;i<PF_UNITS;i++) pf_blocksizes[i] = 1024;
@@ -849,7 +906,6 @@
 static void do_pf_request (request_queue_t * q)
 
 {       struct buffer_head * bh;
-	struct request * req;
 	int unit;
 
         if (pf_busy) return;
@@ -859,12 +915,10 @@
 
         pf_unit = unit = DEVICE_NR(CURRENT->rq_dev);
         pf_block = CURRENT->sector;
-        pf_count = CURRENT->nr_sectors;
+        pf_run = CURRENT->nr_sectors;
+        pf_count = CURRENT->current_nr_sectors;
 
 	bh = CURRENT->bh;
-	req = CURRENT;
-	if (bh->b_reqnext)
-		printk("%s: OUCH: b_reqnext != NULL\n",PF.name);
 
         if ((pf_unit >= PF_UNITS) || (pf_block+pf_count > PF.capacity)) {
                 end_request(0);
@@ -872,14 +926,6 @@
         }
 
 	pf_cmd = CURRENT->cmd;
-	pf_run = pf_count;
-        while ((pf_run <= cluster) &&
-	       (req = blkdev_next_request(req)) && 
-	       (pf_block+pf_run == req->sector) &&
-	       (pf_cmd == req->cmd) &&
-	       (pf_unit == DEVICE_NR(req->rq_dev)))
-			pf_run += req->nr_sectors;
-
         pf_buf = CURRENT->buffer;
         pf_retries = 0;
 
@@ -912,7 +958,7 @@
 		printk("%s: OUCH: request list changed unexpectedly\n",
 			PF.name);
 
-	pf_count = CURRENT->nr_sectors;
+	pf_count = CURRENT->current_nr_sectors;
 	pf_buf = CURRENT->buffer;
 	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.3.99-pre3/linux/drivers/block/rd.c	Fri Mar 10 16:40:42 2000
+++ linux/drivers/block/rd.c	Sun Apr  9 08:12:56 2000
@@ -333,7 +333,8 @@
 	 * Immunize device against invalidate_buffers() and prune_icache().
 	 */
 	if (rd_inode[DEVICE_NR(inode->i_rdev)] == NULL) {
-		if((rd_inode[DEVICE_NR(inode->i_rdev)] = igrab(inode)) != NULL)
+		if (!inode->i_bdev) return -ENXIO;
+		if ((rd_inode[DEVICE_NR(inode->i_rdev)] = igrab(inode)) != NULL)
 			atomic_inc(&rd_inode[DEVICE_NR(inode->i_rdev)]->i_bdev->bd_openers);
 	}
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.3.99-pre3/linux/drivers/block/xd.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/xd.c	Sun Apr  2 15:38:53 2000
@@ -1059,7 +1059,7 @@
 }
 
 /* xd_setup: initialise controler from command line parameters */
-void __init xd_setup (char *command,int *integers)
+void __init do_xd_setup (int *integers)
 {
 	switch (integers[0]) {
 		case 4: if (integers[4] < 0)
@@ -1079,21 +1079,6 @@
 	xd_maxsectors = 0x01;
 }
 
-#ifndef MODULE
-/* xd_manual_geo_init: initialise drive geometry from command line parameters
-   (used only for WD drives) */
-void __init xd_manual_geo_init (char *command,int *integers)
-{
-	int i;
-	if (integers[0]%3 != 0) {
-		printk("xd: incorrect number of parameters for xd_geo\n");
-		return;
-	}
-	for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
-		xd_geo[i] = integers[i+1];
-}
-#endif /* MODULE */
-
 /* xd_setparam: set the drive characteristics */
 static void __init xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
 {
@@ -1149,7 +1134,7 @@
 		if(((xd[i] = xd[i-1]) >= 0) && !count)
 			count = i;
 	if((xd[0] = count))
-		xd_setup(NULL, xd);
+		do_xd_setup(xd);
 
 	if (error = xd_init())
 		return error;
@@ -1190,6 +1175,30 @@
 	}
 }
 #else
+
+static int __init xd_setup (char *str)
+{
+	int ints[5];
+	get_options (str, ARRAY_SIZE (ints), ints);
+	do_xd_setup (ints);
+	return 1;
+}
+
+/* xd_manual_geo_init: initialise drive geometry from command line parameters
+   (used only for WD drives) */
+static int __init xd_manual_geo_init (char *str)
+{
+	int i, integers[1 + 3*XD_MAXDRIVES];
+
+	get_options (str, ARRAY_SIZE (ints), ints);
+	if (integers[0]%3 != 0) {
+		printk("xd: incorrect number of parameters for xd_geo\n");
+		return 1;
+	}
+	for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
+		xd_geo[i] = integers[i+1];
+	return 1;
+}
 
 __setup ("xd=", xd_setup);
 __setup ("xd_geo=", xd_manual_geo_init);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.3.99-pre3/linux/drivers/char/Config.in	Tue Mar 14 19:10:39 2000
+++ linux/drivers/char/Config.in	Sun Apr  2 15:38:53 2000
@@ -110,6 +110,7 @@
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
    bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
    tristate '  WDT Watchdog timer' CONFIG_WDT
+   tristate '  WDT PCI Watchdog timer' CONFIG_WDTPCI
    if [ "$CONFIG_WDT" != "n" ]; then
       bool '    WDT501 features' CONFIG_WDT_501
       if [ "$CONFIG_WDT_501" = "y" ]; then
@@ -152,7 +153,7 @@
 
 tristate 'Video For Linux' CONFIG_VIDEO_DEV
 if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
-   dep_tristate '  I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT
+   dep_tristate '  I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT $CONFIG_I2C
    comment 'Radio Adapters'
    dep_tristate '  ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
    dep_tristate '  AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
@@ -208,6 +209,15 @@
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	 dep_tristate '  QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
       fi
+   fi
+   dep_tristate 'CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then
+     if [ "CONFIG_PARPORT_1284" != "n" ]; then
+       dep_tristate 'CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT
+     fi
+     if [ "$CONFIG_USB" != "n" ]; then
+       dep_tristate 'CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB
+     fi
    fi
    dep_tristate '  SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV $CONFIG_I2C
    dep_tristate '  SAB3036 tuner' CONFIG_TUNER_3036 $CONFIG_VIDEO_DEV $CONFIG_I2C
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.3.99-pre3/linux/drivers/char/Makefile	Tue Mar  7 14:32:25 2000
+++ linux/drivers/char/Makefile	Sun Apr  2 15:38:53 2000
@@ -38,7 +38,7 @@
 
 export-objs     :=	busmouse.o console.o i2c-old.o keyboard.o sysrq.o \
 			misc.o pty.o random.o selection.o serial.o videodev.o \
-			tty_io.o bttv.o
+			tty_io.o bttv.o cpia.o
 
 KEYMAP   =defkeymap.o
 KEYBD    =pc_keyb.o
@@ -171,6 +171,7 @@
 obj-$(CONFIG_ADBMOUSE) += adbmouse.o busmouse.o
 obj-$(CONFIG_PC110_PAD) += pc110pad.o
 obj-$(CONFIG_WDT) += wdt.o
+obj-$(CONFIG_WDTPCI) += wdt_pci.o
 obj-$(CONFIG_RTC) += rtc.o
 obj-$(CONFIG_EFI_RTC) += efirtc.o
 ifeq ($(CONFIG_PPC),)
@@ -179,7 +180,7 @@
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o
 
-obj-$(CONFIG_21825_WATCHDOG) += wdt285.o
+obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
 obj-$(CONFIG_DS1620) += ds1620.o
 
@@ -252,6 +253,9 @@
 obj-$(CONFIG_VIDEO_PLANB) += planb.o
 obj-$(CONFIG_VIDEO_VINO) += vino.o
 obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
+obj-$(CONFIG_VIDEO_CPIA) += cpia.o
+obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
+obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
 obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c
--- v2.3.99-pre3/linux/drivers/char/agp/agpgart_be.c	Tue Mar  7 14:32:25 2000
+++ linux/drivers/char/agp/agpgart_be.c	Mon Apr 10 22:41:19 2000
@@ -1764,6 +1764,30 @@
 #endif /* CONFIG_AGP_INTEL */
 
 #ifdef CONFIG_AGP_SIS
+	{ PCI_DEVICE_ID_SI_630,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"Generic",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_540,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"Generic",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_620,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"Generic",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_530,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"Generic",
+		sis_generic_setup },
 	{ 0,
 		PCI_VENDOR_ID_SI,
 		SIS_GENERIC,
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/applicom.c linux/drivers/char/applicom.c
--- v2.3.99-pre3/linux/drivers/char/applicom.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/char/applicom.c	Mon Mar 27 09:44:58 2000
@@ -1,7 +1,7 @@
 /* Derived from Applicom driver ac.c for SCO Unix                            */
 /* Ported by David Woodhouse, Axiom (Cambridge) Ltd.                         */
 /* Dave@mvhi.com  30/8/98                                                    */
-/* $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $			     */
+/* $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $			     */
 /* This module is for Linux 2.1 and 2.2 series kernels.                      */
 /*****************************************************************************/
 /* J PAGET 18/02/94 passage V2.4.2 ioctl avec code 2 reset to les interrupt  */
@@ -22,6 +22,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/malloc.h>
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -29,15 +30,29 @@
 #include <linux/pci.h>
 #include <linux/wait.h>
 #include <linux/init.h>
+#include <linux/compatmac.h>
+
 #include "applicom.h"
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < 0x20300 
+/* These probably want adding to <linux/compatmac.h> */
+#define init_waitqueue_head(x) do { *(x) = NULL; } while (0);
+#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
+#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x
+#define __setup(x,y) /* */
+#else
+#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
 #endif
 
+/* NOTE: We use for loops with {write,read}b() instead of 
+   memcpy_{from,to}io throughout this driver. This is because
+   the board doesn't correctly handle word accesses - only
+   bytes. 
+*/
+
+
 #undef DEBUG
-#define DEVPRIO PZERO+8
-#define FALSE 0
-#define TRUE  ~FALSE
+
 #define MAX_BOARD 8		/* maximum of pc board possible */
 #define MAX_ISA_BOARD 4
 #define LEN_RAM_IO 0x800
@@ -52,7 +67,9 @@
 #endif
 
 static char *applicom_pci_devnames[] = {
-	"PCI board", "PCI2000IBS / PCI2000CAN", "PCI2000PFB"
+	"PCI board",
+	"PCI2000IBS / PCI2000CAN",
+	"PCI2000PFB"
 };
 
 MODULE_AUTHOR("David Woodhouse & Applicom International");
@@ -68,12 +85,9 @@
 struct applicom_board {
 	unsigned long PhysIO;
 	unsigned long RamIO;
-#if LINUX_VERSION_CODE > 0x20300
 	wait_queue_head_t FlagSleepSend;
-#else
-	struct wait_queue *FlagSleepSend;
-#endif
 	long irq;
+	spinlock_t mutex;
 } apbs[MAX_BOARD];
 
 static unsigned int irq = 0;	/* interrupt number IRQ       */
@@ -81,22 +95,19 @@
 
 static unsigned int numboards;	/* number of installed boards */
 static volatile unsigned char Dummy;
-#if LINUX_VERSION_CODE > 0x20300
 static DECLARE_WAIT_QUEUE_HEAD(FlagSleepRec);
-#else
-static struct wait_queue *FlagSleepRec;
-#endif
 static unsigned int WriteErrorCount;	/* number of write error      */
 static unsigned int ReadErrorCount;	/* number of read error       */
 static unsigned int DeviceErrorCount;	/* number of device error     */
 
-static loff_t ac_llseek(struct file *file, loff_t offset, int origin);
-static int ac_open(struct inode *inode, struct file *filp);
-static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr);
-static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t * ppos);
-static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int ac_release(struct inode *inode, struct file *file);
-static void ac_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static loff_t ac_llseek(struct file *, loff_t, int);
+static int ac_open(struct inode *, struct file *);
+static ssize_t ac_read (struct file *, char *, size_t, loff_t *);
+static ssize_t ac_write (struct file *, const char *, size_t, loff_t *);
+static int ac_ioctl(struct inode *, struct file *, unsigned int,
+		    unsigned long);
+static int ac_release(struct inode *, struct file *);
+static void ac_interrupt(int, void *, struct pt_regs *);
 
 struct file_operations ac_fops = {
 	llseek:ac_llseek,
@@ -113,24 +124,29 @@
 	&ac_fops
 };
 
-int ac_register_board(unsigned long physloc, unsigned long loc, unsigned char boardno)
+int ac_register_board(unsigned long physloc, unsigned long loc, 
+		      unsigned char boardno)
 {
 	volatile unsigned char byte_reset_it;
 
-	if ((readb(loc + CONF_END_TEST) != 0x00) || (readb(loc + CONF_END_TEST + 1) != 0x55) || (readb(loc + CONF_END_TEST + 2) != 0xAA) || (readb(loc + CONF_END_TEST + 3) != 0xFF))
+	if((readb(loc + CONF_END_TEST)     != 0x00) ||
+	   (readb(loc + CONF_END_TEST + 1) != 0x55) ||
+	   (readb(loc + CONF_END_TEST + 2) != 0xAA) ||
+	   (readb(loc + CONF_END_TEST + 3) != 0xFF))
 		return 0;
 
-
 	if (!boardno)
 		boardno = readb(loc + NUMCARD_OWNER_TO_PC);
 
 	if (!boardno && boardno > MAX_BOARD) {
-		printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n", boardno, physloc, MAX_BOARD);
+		printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n",
+		       boardno, physloc, MAX_BOARD);
 		return 0;
 	}
 
 	if (apbs[boardno - 1].RamIO) {
-		printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", boardno, physloc, boardno, apbs[boardno - 1].PhysIO);
+		printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", 
+		       boardno, physloc, boardno, apbs[boardno-1].PhysIO);
 		return 0;
 	}
 
@@ -138,11 +154,8 @@
 
 	apbs[boardno].PhysIO = physloc;
 	apbs[boardno].RamIO = loc;
-#if LINUX_VERSION_CODE > 0x20300
 	init_waitqueue_head(&apbs[boardno].FlagSleepSend);
-#else
-	apbs[boardno].FlagSleepSend = NULL;
-#endif
+	spin_lock_init(&apbs[boardno].mutex);
 	byte_reset_it = readb(loc + RAM_IT_TO_PC);
 
 	numboards++;
@@ -158,14 +171,17 @@
 	int i;
 
 	misc_deregister(&ac_miscdev);
+
 	for (i = 0; i < MAX_BOARD; i++) {
+
 		if (!apbs[i].RamIO)
 			continue;
+		
 		iounmap((void *) apbs[i].RamIO);
+
 		if (apbs[i].irq)
 			free_irq(apbs[i].irq, &ac_open);
 	}
-	//      printk("Removing Applicom module\n");
 }
 
 #endif				/* MODULE */
@@ -176,20 +192,19 @@
 	struct pci_dev *dev = NULL;
 	void *RamIO;
 	int boardno;
-#if LINUX_VERSION_CODE > 0x20300
-#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
-#else
-#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
-#endif
 
-	printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $\n");
+	printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n");
 
 	/* No mem and irq given - check for a PCI card */
 
-	while ((dev = pci_find_device(PCI_VENDOR_ID_APPLICOM, 1, dev))) {
-		//      mem = dev->base_address[0];
-		// irq = dev->irq;
+	while ( (dev = pci_find_class(PCI_CLASS_OTHERS << 16, dev))) {
 
+		if (dev->vendor != PCI_VENDOR_ID_APPLICOM)
+			continue;
+		
+		if (dev->device  > MAX_PCI_DEVICE_NUM || dev->device == 0)
+			continue;
+		
 		RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO);
 
 		if (!RamIO) {
@@ -197,9 +212,12 @@
 			return -EIO;
 		}
 
-		printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n", applicom_pci_devnames[dev->device - 1], PCI_BASE_ADDRESS(dev), dev->irq);
+		printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n",
+		       applicom_pci_devnames[dev->device-1], PCI_BASE_ADDRESS(dev), 
+		       dev->irq);
 
-		if (!(boardno = ac_register_board(PCI_BASE_ADDRESS(dev), (unsigned long) RamIO, 0))) {
+		if (!(boardno = ac_register_board(PCI_BASE_ADDRESS(dev),
+						  (unsigned long)RamIO,0))) {
 			printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n");
 			iounmap(RamIO);
 			continue;
@@ -236,9 +254,8 @@
 
 	RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD);
 
-	if (!RamIO) {
+	if (!RamIO) 
 		printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n", mem);
-	}
 
 	for (i = 0; i < MAX_ISA_BOARD; i++) {
 		RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
@@ -248,39 +265,38 @@
 			continue;
 		}
 
-		if (!(boardno = ac_register_board((unsigned long) mem + (LEN_RAM_IO * i), (unsigned long) RamIO, i + 1))) {
+		if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i),
+						  (unsigned long)RamIO,i+1))) {
 			iounmap(RamIO);
 			continue;
 		}
 
-		printk("Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO * i), irq);
+		printk(KERN_NOTICE "Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq);
 
 		if (!numisa) {
 			if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &ac_open)) {
-				printk("Could not allocate IRQ %d for ISA Applicom device.\n", irq);
+				printk(KERN_WARNING "Could not allocate IRQ %d for ISA Applicom device.\n", irq);
 				iounmap((void *) RamIO);
 				apbs[boardno - 1].RamIO = 0;
 			}
 			apbs[boardno - 1].irq = irq;
-		} else
+		}
+		else
 			apbs[boardno - 1].irq = 0;
 
 		numisa++;
 	}
 
 	if (!numisa)
-		printk("ac.o: No valid ISA Applicom boards found at mem 0x%lx\n", mem);
+		printk(KERN_WARNING"ac.o: No valid ISA Applicom boards found at mem 0x%lx\n",mem);
 
-#if LINUX_VERSION_CODE > 0x20300
+ fin:
 	init_waitqueue_head(&FlagSleepRec);
-#else
-	FlagSleepRec = NULL;
-#endif
+
 	WriteErrorCount = 0;
 	ReadErrorCount = 0;
 	DeviceErrorCount = 0;
 
-      fin:
 	if (numboards) {
 		misc_register(&ac_miscdev);
 		for (i = 0; i < MAX_BOARD; i++) {
@@ -292,12 +308,18 @@
 
 			for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
 				boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
-			boardname[serial] = 0;
 
+			boardname[serial] = 0;
 
-			printk(KERN_INFO "Applicom board %d: %s, PROM V%d.%d", i + 1, boardname, (int) (readb(apbs[i].RamIO + VERS) >> 4), (int) (readb(apbs[i].RamIO + VERS) & 0xF));
 
-			serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2));
+			printk(KERN_INFO "Applicom board %d: %s, PROM V%d.%d",
+			       i+1, boardname,
+			       (int)(readb(apbs[i].RamIO + VERS) >> 4),
+			       (int)(readb(apbs[i].RamIO + VERS) & 0xF));
+			
+			serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + 
+				(readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + 
+				(readb(apbs[i].RamIO + SERIAL_NUMBER + 2) );
 
 			if (serial != 0)
 				printk(" S/N %d\n", serial);
@@ -342,35 +364,41 @@
 	unsigned long flags;	/* Current priority              */
 	struct st_ram_io st_loc;
 	struct mailbox tmpmailbox;
+#ifdef DEBUG
+	int c;
+#endif
+	DECLARE_WAITQUEUE(wait, current);
 
 	if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
-		printk("Hmmm. write() of Applicom card, length %d != expected %d\n", count, sizeof(struct st_ram_io) + sizeof(struct mailbox));
+		static int warncount = 5;
+		if (warncount) {
+			printk(KERN_INFO "Hmmm. write() of Applicom card, length %d != expected %d\n",
+			       count, sizeof(struct st_ram_io) + sizeof(struct mailbox));
+			warncount--;
+		}
 		return -EINVAL;
 	}
 
-	if (copy_from_user(&st_loc, buf, sizeof(struct st_ram_io))) {
+	if(copy_from_user(&st_loc, buf, sizeof(struct st_ram_io))) 
 		return -EFAULT;
-	}
-	if (copy_from_user(&tmpmailbox, &buf[sizeof(struct st_ram_io)], sizeof(struct mailbox))) {
+	
+	if(copy_from_user(&tmpmailbox, &buf[sizeof(struct st_ram_io)],
+			  sizeof(struct mailbox))) 
 		return -EFAULT;
-	}
 
 	NumCard = st_loc.num_card;	/* board number to send          */
 	TicCard = st_loc.tic_des_from_pc;	/* tic number to send            */
 	IndexCard = NumCard - 1;
-	if ((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO) {	/* User board number not OK      */
-		// printk("Write to invalid Applicom board %d\n", NumCard);
-		return -EINVAL;	/* Return error code user buffer */
-	}
-#ifdef DEBUG
-	{
-		int c;
-
-		printk("Write to applicom card #%d. struct st_ram_io follows:", NumCard);
 
+	if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO)
+		return -EINVAL;
 
+#ifdef DEBUG
+	printk("Write to applicom card #%d. struct st_ram_io follows:",
+	       IndexCard+1);
 
 		for (c = 0; c < sizeof(struct st_ram_io);) {
+		
 			printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]);
 
 			for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) {
@@ -389,36 +417,48 @@
 		}
 
 		printk("\n");
-	}
-
 #endif
 
-	save_flags(flags);
-	cli();			/* disable interrupt             */
+	spin_lock_irqsave(&apbs[IndexCard].mutex, flags);
 
-	if (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) {	/* Test octet ready correct */
+	/* Test octet ready correct */
+	if(readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) { 
 		Dummy = readb(apbs[IndexCard].RamIO + VERS);
-		restore_flags(flags);
-		printk("APPLICOM driver write error board %d, DataFromPcReady = %d\n", IndexCard, (int) readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY));
+		spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags);
+		printk(KERN_WARNING "APPLICOM driver write error board %d, DataFromPcReady = %d\n",
+		       IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY));
 		DeviceErrorCount++;
 		return -EIO;
 	}
+	
+	/* Place ourselves on the wait queue */
+	current->state = TASK_INTERRUPTIBLE;
+	add_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait);
+
+	/* Check whether the card is ready for us */
 	while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0) {
 		Dummy = readb(apbs[IndexCard].RamIO + VERS);
-		restore_flags(flags);
-		/*
-		 *	FIXME: Race on wakeup. Race on re-entering write
-		 *	in another thread.
-		 */
-		interruptible_sleep_on(&apbs[IndexCard].FlagSleepSend);
-		if (signal_pending(current))
+		/* It's busy. Sleep. */
+
+		spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags);
+		schedule();
+		if (signal_pending(current)) {
+			remove_wait_queue(&apbs[IndexCard].FlagSleepSend,
+					  &wait);
 			return -EINTR;
-		save_flags(flags);
-		cli();
 	}
+		spin_lock_irqsave(&apbs[IndexCard].mutex, flags);
+	}
+
+	/* We may not have actually slept */
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait);
+
 	writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
 
-	//  memcpy_toio ((void *)apbs[IndexCard].PtrRamFromPc, (void *)&tmpmailbox, sizeof(struct mailbox));
+	/* Which is best - lock down the pages with rawio and then
+	   copy directly, or use bounce buffers? For now we do the latter 
+	   because it works with 2.2 still */
 	{
 		unsigned char *from = (unsigned char *) &tmpmailbox;
 		unsigned long to = (unsigned long) apbs[IndexCard].RamIO + RAM_FROM_PC;
@@ -427,6 +467,7 @@
 		for (c = 0; c < sizeof(struct mailbox); c++)
 			writeb(*(from++), to++);
 	}
+
 	writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC);
 	writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC);
 	writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC);
@@ -434,75 +475,25 @@
 	writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
 	writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
 	Dummy = readb(apbs[IndexCard].RamIO + VERS);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags);
 	return 0;
 }
 
-static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr)
+static int do_ac_read(int IndexCard, char *buf)
 {
-	unsigned int NumCard;	/* board number 1 -> 8         */
-	unsigned int IndexCard;	/* index board number 0 -> 7   */
-	unsigned long flags;
-	unsigned int i;
-	unsigned char tmp = 0;
 	struct st_ram_io st_loc;
 	struct mailbox tmpmailbox;	/* bounce buffer - can't copy to user space with cli() */
+	unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC;
+	unsigned char *to = (unsigned char *)&tmpmailbox;
+#ifdef DEBUG
+	int c;
+#endif
 
-
-	if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
-		printk("Hmmm. read() of Applicom card, length %d != expected %d\n", count, sizeof(struct st_ram_io) + sizeof(struct mailbox));
-		return -EINVAL;
-	}
-
-	save_flags(flags);
-	cli();
-
-	i = 0;
-
-	while (tmp != 2) {
-		for (i = 0; i < MAX_BOARD; i++) {
-			if (!apbs[i].RamIO)
-				continue;
-
-			tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY);
-
-			if (tmp == 2)
-				break;
-
-			if (tmp > 2) {	/* Test octet ready correct */
-				Dummy = readb(apbs[i].RamIO + VERS);
-				restore_flags(flags);
-				printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n", i, (int) readb(apbs[i].RamIO + DATA_TO_PC_READY));
-				DeviceErrorCount++;
-				return -EIO;
-			}
-			Dummy = readb(apbs[i].RamIO + VERS);
-
-		}
-		if (tmp != 2) {
-			/*
-			 *	FIXME: race on wakeup. O_NDELAY not implemented
-			 *	Parallel read threads race.
-			 */
-			restore_flags(flags);
-			interruptible_sleep_on(&FlagSleepRec);
-			if (signal_pending(current))
-				return -EINTR;
-			save_flags(flags);
-			cli();
-		}
-	}
-
-	IndexCard = i;
-	NumCard = i + 1;
 	st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC);
 	st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
 
 
-	//  memcpy_fromio(&tmpmailbox, apbs[IndexCard].PtrRamToPc, sizeof(struct mailbox));
 	{
-		unsigned long from = (unsigned long) apbs[IndexCard].RamIO + RAM_TO_PC;
-		unsigned char *to = (unsigned char *) &tmpmailbox;
 		int c;
 
 		for (c = 0; c < sizeof(struct mailbox); c++)
@@ -510,18 +501,15 @@
 	}
 	writeb(1, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
 	writeb(1, apbs[IndexCard].RamIO + TYP_ACK_FROM_PC);
-	writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
-	writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC), apbs[IndexCard].RamIO + TIC_ACK_FROM_PC);
+	writeb(IndexCard+1, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
+	writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC), 
+	       apbs[IndexCard].RamIO + TIC_ACK_FROM_PC);
 	writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
 	writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY);
 	writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
 	Dummy = readb(apbs[IndexCard].RamIO + VERS);
-	restore_flags(flags);
 
 #ifdef DEBUG
-	{
-		int c;
-
 		printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard);
 
 		for (c = 0; c < sizeof(struct st_ram_io);) {
@@ -542,11 +530,8 @@
 			}
 		}
 		printk("\n");
-
-	}
 #endif
 
-
 	/* Je suis stupide. DW. */
 
 	if (copy_to_user(buf, &st_loc, sizeof(struct st_ram_io)))
@@ -554,7 +539,82 @@
 	if (copy_to_user(&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox)))
 		return -EFAULT;
 
-	return 0;
+	return (sizeof(struct st_ram_io) + sizeof(struct mailbox));
+}
+
+static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr)
+{
+	unsigned long flags;
+	unsigned int i;
+	unsigned char tmp;
+	int ret = 0;
+	DECLARE_WAITQUEUE(wait, current);
+#ifdef DEBUG
+	int loopcount=0;
+#endif
+	/* No need to ratelimit this. Only root can trigger it anyway */
+	if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
+		printk( KERN_WARNING "Hmmm. read() of Applicom card, length %d != expected %d\n",
+			count,sizeof(struct st_ram_io) + sizeof(struct mailbox));
+		return -EINVAL;
+	}
+	
+	while(1) {
+		/* Stick ourself on the wait queue */
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(&FlagSleepRec, &wait);
+		
+		/* Scan each board, looking for one which has a packet for us */
+		for (i=0; i < MAX_BOARD; i++) {
+			if (!apbs[i].RamIO)
+				continue;
+			spin_lock_irqsave(&apbs[i].mutex, flags);
+			
+			tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY);
+			
+			if (tmp == 2) {
+				/* Got a packet for us */
+				ret = do_ac_read(i, buf);
+				spin_unlock_irqrestore(&apbs[i].mutex, flags);
+				current->state = TASK_RUNNING;
+				remove_wait_queue(&FlagSleepRec, &wait);
+				return tmp;
+			}
+			
+			if (tmp > 2) {
+				/* Got an error */
+				Dummy = readb(apbs[i].RamIO + VERS);
+				
+				spin_unlock_irqrestore(&apbs[i].mutex, flags);
+				current->state = TASK_RUNNING;
+				remove_wait_queue(&FlagSleepRec, &wait);
+				
+				printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n",
+				       i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY));
+				DeviceErrorCount++;
+				return -EIO;
+			}
+			
+			/* Nothing for us. Try the next board */
+			Dummy = readb(apbs[i].RamIO + VERS);
+			spin_unlock_irqrestore(&apbs[i].mutex, flags);
+			
+		} /* per board */
+
+		/* OK - No boards had data for us. Sleep now */
+
+		schedule();
+		remove_wait_queue(&FlagSleepRec, &wait);
+
+		if (signal_pending(current))
+			return -EINTR;
+
+#ifdef DEBUG
+		if (loopcount++ > 2) {
+			printk("Looping in ac_read. loopcount %d\n", loopcount);
+		}
+#endif
+	} 
 }
 
 static void ac_interrupt(int vec, void *dev_instance, struct pt_regs *regs)
@@ -562,36 +622,50 @@
 	unsigned int i;
 	unsigned int FlagInt;
 	unsigned int LoopCount;
-	//  volatile unsigned char ResetIntBoard;
 
 	//    printk("Applicom interrupt on IRQ %d occurred\n", vec);
 
 	LoopCount = 0;
-	// for(i=boardno;i<MAX_BOARD;i++)         /* loop for not configured board   */
-	//  if (apbs[i].RamIO)
-	//    ResetIntBoard = *apbs[i].PtrRamItToPc;    /* reset interrupt of unused boards */
 
 	do {
-		FlagInt = FALSE;
+		FlagInt = 0;
 		for (i = 0; i < MAX_BOARD; i++) {
+			
+			/* Skip if this board doesn't exist */
 			if (!apbs[i].RamIO)
 				continue;
 
-			if (readb(apbs[i].RamIO + RAM_IT_TO_PC) != 0)
-				FlagInt = TRUE;
+			spin_lock(&apbs[i].mutex);
+
+			/* Skip if this board doesn't want attention */
+			if(readb(apbs[i].RamIO + RAM_IT_TO_PC) == 0) {
+				spin_unlock(&apbs[i].mutex);
+				continue;
+			}
+
+			FlagInt = 1;
 			writeb(0, apbs[i].RamIO + RAM_IT_TO_PC);
 
 			if (readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2) {
-				printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataToPcReady = %d\n", i + 1, (int) readb(apbs[i].RamIO + DATA_TO_PC_READY));
+				printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataToPcReady = %d\n",
+				       i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY));
 				DeviceErrorCount++;
 			}
-			if ((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) {
-				printk("APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n", i + 1, (int) readb(apbs[i].RamIO + DATA_FROM_PC_READY));
+
+			if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && 
+			   (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) {
+				
+				printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n",
+				       i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY));
 				DeviceErrorCount++;
 			}
+
 			if (readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) {	/* mailbox sent by the card ?   */
+				if (waitqueue_active(&FlagSleepRec)) {
 				wake_up_interruptible(&FlagSleepRec);
 			}
+			}
+
 			if (readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) {	/* ram i/o free for write by pc ? */
 				if (waitqueue_active(&apbs[i].FlagSleepSend)) {	/* process sleep during read ?    */
 					wake_up_interruptible(&apbs[i].FlagSleepSend);
@@ -599,120 +673,123 @@
 			}
 			Dummy = readb(apbs[i].RamIO + VERS);
 
-			if (readb(apbs[i].RamIO + RAM_IT_TO_PC))
-				i--;	/* There's another int waiting on this card */
+			if(readb(apbs[i].RamIO + RAM_IT_TO_PC)) {
+				/* There's another int waiting on this card */
+				spin_unlock(&apbs[i].mutex);
+				i--;
+			} else {
+				spin_unlock(&apbs[i].mutex);
+			}
 		}
 		if (FlagInt)
 			LoopCount = 0;
 		else
 			LoopCount++;
-	}
-	while (LoopCount < 2);
+	} while(LoopCount < 2);
 }
 
 
+
 static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+     
 {				/* @ ADG ou ATO selon le cas */
 	int i;
 	unsigned char IndexCard;
 	unsigned long pmem;
+	int ret = 0;
 	volatile unsigned char byte_reset_it;
-	struct st_ram_io adgl;
-	unsigned char TmpRamIo[sizeof(struct st_ram_io)];
+	struct st_ram_io *adgl;
 
+	/* In general, the device is only openable by root anyway, so we're not
+	   particularly concerned that bogus ioctls can flood the console. */
 
-	if (copy_from_user(&adgl, (void *) arg, sizeof(struct st_ram_io)))
-		return -EFAULT;
+	adgl = kmalloc(sizeof(struct st_ram_io), GFP_KERNEL);
+	if (!adgl)
+		return -ENOMEM;
 
-	IndexCard = adgl.num_card - 1;
+	if (copy_from_user(adgl, (void *)arg,sizeof(struct st_ram_io))) {
+		kfree(adgl);
+		return -EFAULT;
+	}
 	
-	/*
-	 *	FIXME: user can flood the console using bogus ioctls
-	 */
+	IndexCard = adgl->num_card-1;
 	 
-	if (cmd != 0 && cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
-		printk("APPLICOM driver IOCTL, bad board number %d\n", (int) IndexCard + 1);
-		printk("apbs[%d].RamIO = %lx\n", IndexCard, apbs[IndexCard].RamIO);
+	if(cmd != 0 && cmd != 6 &&
+	   ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
+		static int warncount = 10;
+		if (warncount) {
+			printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
+			warncount--;
+		}
+		kfree(adgl);
 		return -EINVAL;
 	}
 
-	/*
-	 *	FIXME races between ioctls with multiple clients
-	 */
-	 
 	switch (cmd) {
+		
 	case 0:
 		pmem = apbs[IndexCard].RamIO;
 		for (i = 0; i < sizeof(struct st_ram_io); i++)
-			TmpRamIo[i] = readb(pmem++);
-		if (copy_to_user((void *) arg, TmpRamIo, sizeof(struct st_ram_io)))
-			return -EFAULT;
+			((unsigned char *)adgl)[i]=readb(pmem++);
+		if (copy_to_user((void *)arg, adgl, sizeof(struct st_ram_io)))
+			ret = -EFAULT;
 		break;
 	case 1:
 		pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
 		for (i = 0; i < 4; i++)
-			adgl.conf_end_test[i] = readb(pmem++);
+			adgl->conf_end_test[i] = readb(pmem++);
 		for (i = 0; i < 2; i++)
-			adgl.error_code[i] = readb(pmem++);
+			adgl->error_code[i] = readb(pmem++);
 		for (i = 0; i < 4; i++)
-			adgl.parameter_error[i] = readb(pmem++);
+			adgl->parameter_error[i] = readb(pmem++);
 		pmem = apbs[IndexCard].RamIO + VERS;
-		adgl.vers = readb(pmem);
+		adgl->vers = readb(pmem);
 		pmem = apbs[IndexCard].RamIO + TYPE_CARD;
 		for (i = 0; i < 20; i++)
-			adgl.reserv1[i] = readb(pmem++);
-		*(int *) &adgl.reserv1[20] = (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2));
+			adgl->reserv1[i] = readb(pmem++);
+		*(int *)&adgl->reserv1[20] =  
+			(readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) + 
+			(readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) + 
+			(readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2) );
 
-		if (copy_to_user((void *) arg, &adgl, sizeof(struct st_ram_io)))
-			return -EFAULT;
+		if (copy_to_user((void *)arg, adgl, sizeof(struct st_ram_io)))
+			ret = -EFAULT;
 		break;
 	case 2:
 		pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
 		for (i = 0; i < 10; i++)
 			writeb(0xff, pmem++);
-		writeb(adgl.data_from_pc_ready, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+		writeb(adgl->data_from_pc_ready, 
+		       apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
 
 		writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
 		
-		/*
-		 *	FIXME: can trash waitqueue that is active.
-		 */
-#if LINUX_VERSION_CODE > 0x20300
-		init_waitqueue_head(&FlagSleepRec);
-#else
-		FlagSleepRec = NULL;
-#endif
 		for (i = 0; i < MAX_BOARD; i++) {
 			if (apbs[i].RamIO) {
-#if LINUX_VERSION_CODE > 0x20300
-				init_waitqueue_head(&apbs[i].FlagSleepSend);
-#else
-				apbs[i].FlagSleepSend = NULL;
-#endif
 				byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC);
 			}
 		}
 		break;
 	case 3:
 		pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC;
-		writeb(adgl.tic_des_from_pc, pmem);
+		writeb(adgl->tic_des_from_pc, pmem);
 		break;
 	case 4:
 		pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC;
-		adgl.tic_owner_to_pc = readb(pmem++);
-		adgl.numcard_owner_to_pc = readb(pmem);
-		if (copy_to_user((void *) arg, &adgl, sizeof(struct st_ram_io)))
-			return -EFAULT;
+		adgl->tic_owner_to_pc     = readb(pmem++);
+		adgl->numcard_owner_to_pc = readb(pmem);
+		if (copy_to_user((void *)arg, adgl,sizeof(struct st_ram_io)))
+			ret = -EFAULT;
 		break;
 	case 5:
-		writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
-		writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
-		writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
+		writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
+		writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
+		writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
 		writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
 		writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
 		break;
 	case 6:
-		printk(KERN_INFO "APPLICOM driver release .... V2.8.0\n");
+		printk(KERN_INFO "APPLICOM driver release .... V2.8.0 ($Revision: 1.30 $)\n");
 		printk(KERN_INFO "Number of installed boards . %d\n", (int) numboards);
 		printk(KERN_INFO "Segment of board ........... %X\n", (int) mem);
 		printk(KERN_INFO "Interrupt IRQ number ....... %d\n", (int) irq);
@@ -723,16 +800,20 @@
 			if (!apbs[i].RamIO)
 				continue;
 
-
 			for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
 				boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
 			boardname[serial] = 0;
 
-
-			printk(KERN_INFO "Prom version board %d ....... V%d.%d %s", i + 1, (int) (readb(apbs[IndexCard].RamIO + VERS) >> 4), (int) (readb(apbs[IndexCard].RamIO + VERS) & 0xF), boardname);
+			printk(KERN_INFO "Prom version board %d ....... V%d.%d %s",
+			       i+1,
+			       (int)(readb(apbs[IndexCard].RamIO + VERS) >> 4),
+			       (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF),
+			       boardname);
 
 
-			serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2));
+			serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + 
+				(readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + 
+				(readb(apbs[i].RamIO + SERIAL_NUMBER + 2) );
 
 			if (serial != 0)
 				printk(" S/N %d\n", serial);
@@ -746,18 +827,19 @@
 		if (WriteErrorCount != 0)
 			printk(KERN_INFO "WriteErrorCount ............ %d\n", WriteErrorCount);
 		if (waitqueue_active(&FlagSleepRec))
-			printk("Process in read pending\n");
+			printk(KERN_INFO "Process in read pending\n");
 		for (i = 0; i < MAX_BOARD; i++) {
 			if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend))
-				printk("Process in write pending board %d\n", i + 1);
+				printk(KERN_INFO "Process in write pending board %d\n",i+1);
 		}
 		break;
 	default:
-		printk("APPLICOM driver ioctl, unknown function code %d\n", cmd);
-		return -EINVAL;
+		printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
+		ret = -EINVAL;
 		break;
 	}
 	Dummy = readb(apbs[IndexCard].RamIO + VERS);
+	kfree(adgl);
 	return 0;
 }
 
@@ -773,7 +855,7 @@
 	}
 
 	if (ints[0] < 2) {
-		printk("applicom numargs: %d\n", ints[0]);
+		printk(KERN_INFO"applicom numargs: %d\n", ints[0]);
 		return 0;
 	}
 
@@ -782,7 +864,7 @@
 	return 1;
 }
 
-#if LINUX_VERSION_CODE > 0x20300
 __setup("applicom=", applicom_setup);
-#endif
+
 #endif				/* MODULE */
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.3.99-pre3/linux/drivers/char/bttv.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/char/bttv.c	Sun Apr  2 15:32:49 2000
@@ -490,7 +490,8 @@
 	bttv_bit_setscl(btv,1);
 	bttv_bit_setsda(btv,1);
 
-	return i2c_bit_add_bus(&btv->i2c_adap);
+	btv->i2c_ok = i2c_bit_add_bus(&btv->i2c_adap);
+	return btv->i2c_ok;
 }
 
 /* read I2C */
@@ -498,6 +499,8 @@
 {
         unsigned char buffer = 0;
 
+	if (0 != btv->i2c_ok)
+		return -1;
 	if (verbose && NULL != probe_for)
 		printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
 		       btv->nr,probe_for,addr);
@@ -523,11 +526,13 @@
         unsigned char buffer[2];
         int bytes = both ? 2 : 1;
 
+	if (0 != btv->i2c_ok)
+		return -1;
         btv->i2c_client.addr = addr >> 1;
         buffer[0] = b1;
         buffer[1] = b2;
         if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
-                return -1;
+		return -1;
         return 0;
 }
 
@@ -702,42 +707,25 @@
 
 /* ----------------------------------------------------------------------- */
 
-/* for some vendors it is just the PCI ID */
-static struct VENDOR {
-	int id;
-	char *name;
-} vendors[] = {
-	{ 0x0001, "ATI Technologies Inc" },
-	{ 0x10b4, "STB Systems Inc" },
-	{ 0x1118, "Terratec" },
-	{ 0x13eb, "Hauppauge Computer Works Inc" },
-	{ 0x1461, "Avermedia" },
-	{ 0x1850, "Chronos" },
-	{ 0x1852, "Typhoon" },
-	{ 0x3000, "Askey" },
-	{ 0x3002, "Askey" },
-	{ 0x6606, "Leadtek" },
-	{ -1, NULL }
-};
-
 static struct CARD {
-	int vid;
-	int id;
+	unsigned id;
 	int cardnr;
 	char *name;
 } cards[] = {
-	{ 0x0001, 0x1002, BTTV_HAUPPAUGE878,  "TV Wonder" },
-	{ 0x10b4, 0x2636, BTTV_HAUPPAUGE878,  "???" },
-	{ 0x1118, 0x153b, BTTV_TERRATVALUE,   "TV Value" },
-	{ 0x13eb, 0x0070, BTTV_HAUPPAUGE878,  "WinTV" },
-	{ 0x1461, 0x0002, BTTV_AVERMEDIA98,   "TVCapture 98" },
-	{ 0x1850, 0x1851, BTTV_CHRONOS_VS2,   "Video Shuttle II" },
-	{ 0x1852, 0x1852, BTTV_TYPHOON_TVIEW, "TView TV/FM Tuner" },
-	{ 0x3000, 0x14ff, BTTV_MAGICTVIEW061, "TView 99"  },
-	{ 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView"  },
-	{ 0x3002, 0x14ff, BTTV_PHOEBE_TVMAS,  "TV Master"  },
-	{ 0x6606, 0x217d, BTTV_WINFAST2000,   "WinFast TV 2000" },
-	{ -1, -1, -1, NULL }
+	{ 0x00011002, BTTV_HAUPPAUGE878,  "ATI TV Wonder" },
+	{ 0x00031461, BTTV_AVERMEDIA98,   "AVerMedia TVPhone98" },
+	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
+	{ 0x1118153b, BTTV_TERRATVALUE,   "Terratec TV Value" },
+	{ 0x13eb0070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV" },
+	{ 0x14610002, BTTV_AVERMEDIA98,   "Avermedia TVCapture 98" },
+	{ 0x18501851, BTTV_CHRONOS_VS2,   "Chronos Video Shuttle II" },
+	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
+	{ 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" },
+	{ 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
+	{ 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" },
+	{ 0x300214ff, BTTV_PHOEBE_TVMAS,  "Phoebe TV Master" },
+	{ 0x6606217d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0, -1, NULL }
 };
 
 struct tvcard
@@ -869,7 +857,7 @@
 	  1,1,1,1,0 },
         { "FlyVideo 98",
           3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, 
-          { 0, 0x8dff00, 0x800, 0x400, 0x8dff00, 0 },0,
+          { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },0,
 	  1,1,1,1,0 },
         { "iProTV",
 	  3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0,
@@ -893,9 +881,12 @@
 	{ "Typhoon TView TV/FM Tuner",
 	  3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0,
 	  1,1,1,1,0 },
-	{ "PixelView PlayTV pro",                                                               
-          3, 1, 0, 2, 0xff, { 2, 3, 1, 1 },                                                     
-          { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 }
+	{ "PixelView PlayTV pro",
+          3, 1, 0, 2, 0xff, { 2, 3, 1, 1 },
+          { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 },
+	{ "TView99 CPH063",
+	  3, 1, 0, 2, 0x551e00, { 2, 0, 1, 1},
+	  { 0x551400, 0x551200, 0, 0, 0x551200 }, 0,1,1,1,1,0 },
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
 
@@ -920,39 +911,35 @@
 static int
 idcard_eeprom(struct bttv *btv)
 {
-	int i,id1,id2,n1,n2;
+	unsigned id;
+	int i,n;
 
-	id1 = (eeprom_data[254] << 8) | (eeprom_data[255]);
-	id2 = (eeprom_data[252] << 8) | (eeprom_data[253]);
-	if (id1 == 0 || id1 == 0xffff ||
-	    id2 == 0 || id2 == 0xffff)
-		return -1;
+	id = (eeprom_data[252] << 24) |
+		(eeprom_data[253] << 16) |
+		(eeprom_data[254] << 8)  |
+		(eeprom_data[255]);
+	if (id == 0 || id == 0xffffffff)
+	    return -1;
 
 	/* look for the card */
-	n1 = -1; n2 = -1;
-	for (i = 0; vendors[i].id != -1; i++)
-		if (vendors[i].id == id2)
-			n2 = i;
-	for (i = 0; cards[i].id != -1; i++)
-		if (cards[i].id  == id1 &&
-		    cards[i].vid == id2)
-			n1 = i;
+	for (n = -1, i = 0; cards[i].id != 0; i++)
+		if (cards[i].id  == id)
+			n = i;
 
-	if (n1 != -1 && n2 != -1) {
+	if (n != -1) {
 		/* found it */
-		printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n",
-		       btv->nr,cards[n1].name,id1,vendors[n2].name,id2);
+		printk(KERN_INFO "bttv%d: id: %s (0x%08x)\n",
+		       btv->nr,cards[n].name,id);
 		if (verbose)
 			printk(KERN_INFO "bttv%d:   => card=%d (%s)\n",
-			       btv->nr,cards[n1].cardnr,
-			       tvcards[cards[n1].cardnr].name);
-		return cards[n1].cardnr;
+			       btv->nr,cards[n].cardnr,
+			       tvcards[cards[n].cardnr].name);
+		return cards[n].cardnr;
 	} else {
 		/* 404 */
-		printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n",
-		       btv->nr, "unknown", id1,
-		       (n2 != -1) ? vendors[n2].name : "unknown", id2);
-		printk(KERN_INFO "please mail id + vendor, board name and "
+		printk(KERN_INFO "bttv%d: id: unknown (0x%08x)\n",
+		       btv->nr, id);
+		printk(KERN_INFO "please mail id, board name and "
 		       "the correct card= insmod option to "
 		       "kraxel@goldbach.in-berlin.de\n");
 		return -1;
@@ -1670,30 +1657,48 @@
  *	www.brooktree.com - nicely done those folks.
  */
  
-/* set geometry for even/odd frames 
-   just if you are wondering:
-   handling of even and odd frames will be separated, e.g. for grabbing
-   the even ones as RGB into videomem and the others as YUV in main memory for 
-   compressing and sending to the video conferencing partner.
-
-*/
-static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc, 
-				   u16 hscale, u16 vscale,
-				   u16 hactive, u16 vactive,
-				   u16 hdelay, u16 vdelay,
-				   u8 crop)
+static inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn,
+				   int odd, int width, int height)
 {
+        u16 vscale, hscale;
+	u32 xsf, sr;
+	u16 hdelay;
+	u8 crop, vtc;
+	int inter = (height>tvn->sheight/2) ? 0 : 1;
         int off = odd ? 0x80 : 0x00;
-  
+
+	xsf = (width*tvn->scaledtwidth)/tvn->swidth;
+	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
+	hdelay =  tvn->hdelayx1;
+	hdelay =  (hdelay*width)/tvn->swidth;
+	hdelay &= 0x3fe;
+	sr=((tvn->sheight>>inter)*512)/height-512;
+	vscale=(0x10000UL-sr)&0x1fff;
+	crop=((width>>8)&0x03)|((hdelay>>6)&0x0c)|
+		((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
+	vscale |= inter ? (BT848_VSCALE_INT<<8) : 0;
+
+#if 0
+	/* Some people say interpolation looks bad ... */
+	vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+	if (width < 767)
+		btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+	else
+		btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+#else
+	vtc = 0;
+	btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+#endif
+
 	btwrite(vtc, BT848_E_VTC+off);
 	btwrite(hscale>>8, BT848_E_HSCALE_HI+off);
 	btwrite(hscale&0xff, BT848_E_HSCALE_LO+off);
 	btaor((vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
 	btwrite(vscale&0xff, BT848_E_VSCALE_LO+off);
-	btwrite(hactive&0xff, BT848_E_HACTIVE_LO+off);
+	btwrite(width&0xff, BT848_E_HACTIVE_LO+off);
 	btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off);
-	btwrite(vactive&0xff, BT848_E_VACTIVE_LO+off);
-	btwrite(vdelay&0xff, BT848_E_VDELAY_LO+off);
+	btwrite(tvn->sheight&0xff, BT848_E_VACTIVE_LO+off);
+	btwrite(tvn->vdelay&0xff, BT848_E_VDELAY_LO+off);
 	btwrite(crop, BT848_E_CROP+off);
 }
 
@@ -1701,14 +1706,8 @@
 static void bt848_set_geo(struct bttv *btv,
 			  int no_irq_context)
 {
-        u16 vscale, hscale;
-	u32 xsf, sr;
 	u16 ewidth, eheight, owidth, oheight;
 	u16 format, bswap;
-	u16 hdelay;
-	u16 hactive;
-	u16 inter;
-	u8 crop, vtc;  
 	struct tvnorm *tvn;
 	unsigned long flags;
  	
@@ -1727,10 +1726,6 @@
 	if (no_irq_context)
 		set_pll(btv);
 
-        vtc=0;
-	/* Some people say interpolation looks bad ... */
-	/* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */
-     
 	btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0;
 
 	if (0 == btv->risc_cap_odd &&
@@ -1762,40 +1757,11 @@
 		eheight = btv->gbuf[btv->gq_grab].height;
 		format  = btv->gbuf[btv->gq_grab].fmt;
 		bswap   = 0;
-		inter   = (btv->win.height>tvn->sheight/2) ? 0 : 1;
 	}
 
-	inter = (oheight>tvn->sheight/2) ? 0 : 1;
-
-	/* odd field */
-	hactive=owidth;
-	xsf = (hactive*tvn->scaledtwidth)/tvn->swidth;
-	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
-	hdelay =  tvn->hdelayx1;
-	hdelay =  (hdelay*hactive)/tvn->swidth;
-	hdelay &= 0x3fe;
-	sr=((tvn->sheight>>inter)*512)/oheight-512;
-	vscale=(0x10000UL-sr)&0x1fff;
-	crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
-		((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
-	vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
-	bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, tvn->sheight,
-			hdelay, tvn->vdelay, crop);
-
-	/* even field */
-	hactive=ewidth;
-	xsf = (hactive*tvn->scaledtwidth)/tvn->swidth;
-	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
-	hdelay =  tvn->hdelayx1;
-	hdelay =  (hdelay*hactive)/tvn->swidth;
-	hdelay &= 0x3fe;
-	sr=((tvn->sheight>>inter)*512)/eheight-512;
-	vscale=(0x10000UL-sr)&0x1fff;
-	crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
-		((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
-	vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
-	bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, tvn->sheight,
-			hdelay, tvn->vdelay, crop);
+	/* program odd + even fields */
+	bt848_set_eogeo(btv, tvn, 1, owidth, oheight);
+	bt848_set_eogeo(btv, tvn, 0, ewidth, eheight);
 
 	btwrite(format, BT848_COLOR_FMT);
 	btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
@@ -1897,8 +1863,8 @@
         make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format);
 
 	if (debug)
-		printk("bttv%d: cap vgrab: queue %d (%dx%d)\n",
-		       btv->nr,mp->frame,mp->width,mp->height);
+		printk("bttv%d: cap vgrab: queue %d (%d:%dx%d)\n",
+		       btv->nr,mp->frame,mp->format,mp->width,mp->height);
         cli();
         btv->gbuf[mp->frame].stat    = GBUFFER_GRABBING;
 	btv->gbuf[mp->frame].fmt     = palette2fmt[mp->format];
@@ -1914,10 +1880,6 @@
 #endif
 
 	if (btv->gq_in == btv->gq_out) {
-		if(mp->format>=VIDEO_PALETTE_COMPONENT) {
-			btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
-			btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
-		}
 		btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
         }
 	btv->gqueue[btv->gq_in++] = mp->frame;
@@ -2317,7 +2279,7 @@
 		btv->win.height=vw.height;
 
 		bt848_set_risc_jmps(btv,0);
-		
+
 		bt848_set_winsize(btv);
 		up(&btv->lock);
 
@@ -2573,10 +2535,8 @@
 				if (debug)
 					printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i);
 				interruptible_sleep_on(&btv->capq);
-				if(signal_pending(current)) {
-					ret = -EINTR;
-					break;
-				}
+				if(signal_pending(current))
+					return -EINTR;
 			}
 			/* fall throuth */
 		case GBUFFER_DONE:
@@ -2649,9 +2609,6 @@
 		else
 			vu.radio=VIDEO_NO_UNIT;
 		vu.audio=VIDEO_NO_UNIT;
-#if 0
-		AUDIO(AUDC_GET_UNIT, &vu.audio);
-#endif
 		vu.teletext=VIDEO_NO_UNIT;
 		if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
 			return -EFAULT;
@@ -3054,17 +3011,6 @@
 	}
 }
 
-#if 0
-#warning please use tda8425.c instead
-static void init_tda8425(struct bttv *btv) 
-{
-        I2CWrite(btv, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB  */
-        I2CWrite(btv, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */
-        I2CWrite(btv, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB         */
-        I2CWrite(btv, I2C_TDA8425, TDA8425_TR, 0xF6, 1); /* treble 0dB       */
-        I2CWrite(btv, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off         */
-}
-#endif
 
 /* can tda9855.c handle this too maybe? */
 static void init_tda9840(struct bttv *btv)
@@ -3164,6 +3110,7 @@
 	    btv->type == BTTV_PIXVIEWPLAYTV	||
 	    btv->type == BTTV_AVERMEDIA98	||
 	    btv->type == BTTV_MAGICTVIEW061	||
+	    btv->type == BTTV_MAGICTVIEW063	||
 	    btv->type == BTTV_CHRONOS_VS2	||
 	    btv->type == BTTV_TYPHOON_TVIEW	||
 	    btv->type == BTTV_PXELVWPLTVPRO     ||
@@ -3600,8 +3547,6 @@
                                         btv->risc_cap_odd  = 0;
 					btv->risc_cap_even = 0;
 					bt848_set_risc_jmps(btv,-1);
-					btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
-					btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
                                         bt848_set_geo(btv,0);
 					btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA,
 						BT848_COLOR_CTL);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/bttv.h linux/drivers/char/bttv.h
--- v2.3.99-pre3/linux/drivers/char/bttv.h	Mon Mar 27 08:08:23 2000
+++ linux/drivers/char/bttv.h	Sun Apr  2 15:32:49 2000
@@ -21,7 +21,7 @@
 #ifndef _BTTV_H_
 #define _BTTV_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,24) 
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,25) 
 
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -138,7 +138,7 @@
 	struct i2c_adapter         i2c_adap;
 	struct i2c_algo_bit_data   i2c_algo;
 	struct i2c_client          i2c_client;
-	int                        i2c_state;
+	int                        i2c_state, i2c_ok;
 	struct i2c_client         *i2c_clients[I2C_CLIENTS_MAX];
 
         int tuner_type;
@@ -270,6 +270,7 @@
 #define BTTV_CHRONOS_VS2   0x23
 #define BTTV_TYPHOON_TVIEW 0x24
 #define BTTV_PXELVWPLTVPRO 0x25
+#define BTTV_MAGICTVIEW063 0x26
 
 
 #define AUDIO_TUNER        0x00
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.3.99-pre3/linux/drivers/char/console.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/char/console.c	Sun Apr  2 15:20:27 2000
@@ -121,8 +121,6 @@
 #define DEFAULT_BELL_PITCH	750
 #define DEFAULT_BELL_DURATION	(HZ/8)
 
-extern int tty_register_devfs (struct tty_driver *driver, unsigned int flags,
-			       unsigned int minor);
 extern void vcs_make_devfs (unsigned int index, int unregister);
 
 #ifndef MIN
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/cpia.c linux/drivers/char/cpia.c
--- v2.3.99-pre3/linux/drivers/char/cpia.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/cpia.c	Mon Mar 27 10:22:31 2000
@@ -0,0 +1,3319 @@
+/*
+ * cpia CPiA driver
+ *
+ * Supports CPiA based Video Camera's.
+ *
+ * (C) Copyright 1999-2000 Peter Pregler,
+ * (C) Copyright 1999-2000 Scott J. Bertin,
+ * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* #define _CPIA_DEBUG_		define for verbose debug output */
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/pagemap.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <linux/wrapper.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include "cpia.h"
+
+#ifdef CONFIG_VIDEO_CPIA_PP
+extern int cpia_pp_init(void);
+#endif
+#ifdef CONFIG_VIDEO_CPIA_USB
+extern int cpia_usb_init(void);
+#endif
+
+#ifdef MODULE
+MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
+MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
+MODULE_SUPPORTED_DEVICE("video");
+#endif
+
+#define ABOUT "V4L-Driver for Vision CPiA based cameras"
+
+#ifndef VID_HARDWARE_CPIA
+#define VID_HARDWARE_CPIA 24    /* FIXME -> from linux/videodev.h */
+#endif
+
+#define CPIA_MODULE_CPIA			(0<<5)
+#define CPIA_MODULE_SYSTEM			(1<<5)
+#define CPIA_MODULE_VP_CTRL			(5<<5)
+#define CPIA_MODULE_CAPTURE			(6<<5)
+#define CPIA_MODULE_DEBUG			(7<<5)
+
+#define INPUT (DATA_IN << 8)
+#define OUTPUT (DATA_OUT << 8)
+
+#define CPIA_COMMAND_GetCPIAVersion	(INPUT | CPIA_MODULE_CPIA | 1)
+#define CPIA_COMMAND_GetPnPID		(INPUT | CPIA_MODULE_CPIA | 2)
+#define CPIA_COMMAND_GetCameraStatus	(INPUT | CPIA_MODULE_CPIA | 3)
+#define CPIA_COMMAND_GotoHiPower	(OUTPUT | CPIA_MODULE_CPIA | 4)
+#define CPIA_COMMAND_GotoLoPower	(OUTPUT | CPIA_MODULE_CPIA | 5)
+#define CPIA_COMMAND_GotoSuspend	(OUTPUT | CPIA_MODULE_CPIA | 7)
+#define CPIA_COMMAND_GotoPassThrough	(OUTPUT | CPIA_MODULE_CPIA | 8)
+#define CPIA_COMMAND_ModifyCameraStatus	(OUTPUT | CPIA_MODULE_CPIA | 10)
+
+#define CPIA_COMMAND_ReadVCRegs		(INPUT | CPIA_MODULE_SYSTEM | 1)
+#define CPIA_COMMAND_WriteVCReg		(OUTPUT | CPIA_MODULE_SYSTEM | 2)
+#define CPIA_COMMAND_ReadMCPorts	(INPUT | CPIA_MODULE_SYSTEM | 3)
+#define CPIA_COMMAND_WriteMCPort	(OUTPUT | CPIA_MODULE_SYSTEM | 4)
+#define CPIA_COMMAND_SetBaudRate	(OUTPUT | CPIA_MODULE_SYSTEM | 5)
+#define CPIA_COMMAND_SetECPTiming	(OUTPUT | CPIA_MODULE_SYSTEM | 6)
+#define CPIA_COMMAND_ReadIDATA		(INPUT | CPIA_MODULE_SYSTEM | 7)
+#define CPIA_COMMAND_WriteIDATA		(OUTPUT | CPIA_MODULE_SYSTEM | 8)
+#define CPIA_COMMAND_GenericCall	(OUTPUT | CPIA_MODULE_SYSTEM | 9)
+#define CPIA_COMMAND_I2CStart		(OUTPUT | CPIA_MODULE_SYSTEM | 10)
+#define CPIA_COMMAND_I2CStop		(OUTPUT | CPIA_MODULE_SYSTEM | 11)
+#define CPIA_COMMAND_I2CWrite		(OUTPUT | CPIA_MODULE_SYSTEM | 12)
+#define CPIA_COMMAND_I2CRead		(INPUT | CPIA_MODULE_SYSTEM | 13)
+
+#define CPIA_COMMAND_GetVPVersion	(INPUT | CPIA_MODULE_VP_CTRL | 1)
+#define CPIA_COMMAND_SetColourParams	(OUTPUT | CPIA_MODULE_VP_CTRL | 3)
+#define CPIA_COMMAND_SetExposure	(OUTPUT | CPIA_MODULE_VP_CTRL | 4)
+#define CPIA_COMMAND_SetColourBalance	(OUTPUT | CPIA_MODULE_VP_CTRL | 6)
+#define CPIA_COMMAND_SetSensorFPS	(OUTPUT | CPIA_MODULE_VP_CTRL | 7)
+#define CPIA_COMMAND_SetVPDefaults	(OUTPUT | CPIA_MODULE_VP_CTRL | 8)
+#define CPIA_COMMAND_SetApcor		(OUTPUT | CPIA_MODULE_VP_CTRL | 9)
+#define CPIA_COMMAND_SetFlickerCtrl	(OUTPUT | CPIA_MODULE_VP_CTRL | 10)
+#define CPIA_COMMAND_SetVLOffset	(OUTPUT | CPIA_MODULE_VP_CTRL | 11)
+#define CPIA_COMMAND_GetColourParams	(INPUT | CPIA_MODULE_VP_CTRL | 16)
+#define CPIA_COMMAND_GetColourBalance	(INPUT | CPIA_MODULE_VP_CTRL | 17)
+#define CPIA_COMMAND_GetExposure	(INPUT | CPIA_MODULE_VP_CTRL | 18)
+#define CPIA_COMMAND_SetSensorMatrix	(OUTPUT | CPIA_MODULE_VP_CTRL | 19)
+#define CPIA_COMMAND_ColourBars		(OUTPUT | CPIA_MODULE_VP_CTRL | 25)
+#define CPIA_COMMAND_ReadVPRegs		(INPUT | CPIA_MODULE_VP_CTRL | 30)
+#define CPIA_COMMAND_WriteVPReg		(OUTPUT | CPIA_MODULE_VP_CTRL | 31)
+
+#define CPIA_COMMAND_GrabFrame		(OUTPUT | CPIA_MODULE_CAPTURE | 1)
+#define CPIA_COMMAND_UploadFrame	(OUTPUT | CPIA_MODULE_CAPTURE | 2)
+#define CPIA_COMMAND_SetGrabMode	(OUTPUT | CPIA_MODULE_CAPTURE | 3)
+#define CPIA_COMMAND_InitStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 4)
+#define CPIA_COMMAND_FiniStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 5)
+#define CPIA_COMMAND_StartStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 6)
+#define CPIA_COMMAND_EndStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 7)
+#define CPIA_COMMAND_SetFormat		(OUTPUT | CPIA_MODULE_CAPTURE | 8)
+#define CPIA_COMMAND_SetROI		(OUTPUT | CPIA_MODULE_CAPTURE | 9)
+#define CPIA_COMMAND_SetCompression	(OUTPUT | CPIA_MODULE_CAPTURE | 10)
+#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
+#define CPIA_COMMAND_SetYUVThresh	(OUTPUT | CPIA_MODULE_CAPTURE | 12)
+#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
+#define CPIA_COMMAND_DiscardFrame	(OUTPUT | CPIA_MODULE_CAPTURE | 14)
+
+#define CPIA_COMMAND_OutputRS232	(OUTPUT | CPIA_MODULE_DEBUG | 1)
+#define CPIA_COMMAND_AbortProcess	(OUTPUT | CPIA_MODULE_DEBUG | 4)
+#define CPIA_COMMAND_SetDramPage	(OUTPUT | CPIA_MODULE_DEBUG | 5)
+#define CPIA_COMMAND_StartDramUpload	(OUTPUT | CPIA_MODULE_DEBUG | 6)
+#define CPIA_COMMAND_StartDummyDtream	(OUTPUT | CPIA_MODULE_DEBUG | 8)
+#define CPIA_COMMAND_AbortStream	(OUTPUT | CPIA_MODULE_DEBUG | 9)
+#define CPIA_COMMAND_DownloadDRAM	(OUTPUT | CPIA_MODULE_DEBUG | 10)
+
+enum {
+	FRAME_READY,		/* Ready to grab into */
+	FRAME_GRABBING,		/* In the process of being grabbed into */
+	FRAME_DONE,		/* Finished grabbing, but not been synced yet */
+	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
+};
+
+#define COMMAND_NONE			0x0000
+#define COMMAND_SETCOMPRESSION		0x0001
+#define COMMAND_SETCOMPRESSIONTARGET	0x0002
+#define COMMAND_SETCOLOURPARAMS		0x0004
+#define COMMAND_SETFORMAT		0x0008
+#define COMMAND_PAUSE			0x0010
+#define COMMAND_RESUME			0x0020
+#define COMMAND_SETYUVTHRESH		0x0040
+#define COMMAND_SETECPTIMING		0x0080
+#define COMMAND_SETCOMPRESSIONPARAMS	0x0100
+#define COMMAND_SETEXPOSURE		0x0200
+#define COMMAND_SETCOLOURBALANCE	0x0400
+#define COMMAND_SETSENSORFPS		0x0800
+#define COMMAND_SETAPCOR		0x1000
+#define COMMAND_SETFLICKERCTRL		0x2000
+#define COMMAND_SETVLOFFSET		0x4000
+
+/* Developer's Guide Table 5 p 3-34
+ * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
+static u8 flicker_jumps[2][2][4] =
+{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
+  { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
+};
+
+/* forward declaration of local function */
+static void reset_camera_struct(struct cam_data *cam);
+
+/**********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet - jerdfelt
+ *
+ **********************************************************************/
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+	unsigned long ret = 0UL;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+
+	if (!pgd_none(*pgd)) {
+		pmd = pmd_offset(pgd, adr);
+		if (!pmd_none(*pmd)) {
+			ptep = pte_offset(pmd, adr);
+			pte = *ptep;
+			if (pte_present(pte))
+				ret = page_address(pte_page(pte)) |
+				      (adr & (PAGE_SIZE-1));
+		}
+	}
+	return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+	unsigned long va, kva, ret;
+
+	va = VMALLOC_VMADDR(adr);
+	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = __pa(kva);
+	return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr, page;
+
+	/* Round it off to PAGE_SIZE */
+	size += (PAGE_SIZE - 1);
+	size &= ~(PAGE_SIZE - 1);
+
+	mem = vmalloc(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa(adr);
+		mem_map_reserve(MAP_NR(__va(page)));
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+	unsigned long adr, page;
+
+	if (!mem)
+		return;
+
+	size += (PAGE_SIZE - 1);
+	size &= ~(PAGE_SIZE - 1);
+
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa(adr);
+		mem_map_unreserve(MAP_NR(__va(page)));
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+	vfree(mem);
+}
+
+/**********************************************************************
+ *
+ * /proc interface
+ *
+ **********************************************************************/
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *cpia_proc_root=NULL;
+
+static int cpia_read_proc(char *page, char **start, off_t off,
+                          int count, int *eof, void *data)
+{
+	char *out = page;
+	int len, tmp;
+	struct cam_data *cam = data;
+	char tmpstr[20];
+
+	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
+	 *            or we need to get more sophisticated. */
+
+	out += sprintf(out, "read-only\n-----------------------\n");
+	out += sprintf(out, "V4L Driver version:       %d.%d.%d\n",
+		       CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+	out += sprintf(out, "CPIA Version:             %d.%02d (%d.%d)\n",
+	               cam->params.version.firmwareVersion,
+	               cam->params.version.firmwareRevision,
+	               cam->params.version.vcVersion,
+	               cam->params.version.vcRevision);
+	out += sprintf(out, "CPIA PnP-ID:              %04x:%04x:%04x\n",
+	               cam->params.pnpID.vendor, cam->params.pnpID.product,
+	               cam->params.pnpID.deviceRevision);
+	out += sprintf(out, "VP-Version:               %d.%d %04x\n",
+	               cam->params.vpVersion.vpVersion,
+	               cam->params.vpVersion.vpRevision,
+	               cam->params.vpVersion.cameraHeadID);
+	
+	out += sprintf(out, "system_state:             %#04x\n",
+	               cam->params.status.systemState);
+	out += sprintf(out, "grab_state:               %#04x\n",
+	               cam->params.status.grabState);
+	out += sprintf(out, "stream_state:             %#04x\n",
+	               cam->params.status.streamState);
+	out += sprintf(out, "fatal_error:              %#04x\n",
+	               cam->params.status.fatalError);
+	out += sprintf(out, "cmd_error:                %#04x\n",
+	               cam->params.status.cmdError);
+	out += sprintf(out, "debug_flags:              %#04x\n",
+	               cam->params.status.debugFlags);
+	out += sprintf(out, "vp_status:                %#04x\n",
+	               cam->params.status.vpStatus);
+	out += sprintf(out, "error_code:               %#04x\n",
+	               cam->params.status.errorCode);
+	out += sprintf(out, "video_size:               %s\n",
+	               cam->params.format.videoSize == VIDEOSIZE_CIF ?
+		       "CIF " : "QCIF");
+	out += sprintf(out, "sub_sample:               %s\n",
+	               cam->params.format.subSample == SUBSAMPLE_420 ?
+		       "420" : "422");
+	out += sprintf(out, "yuv_order:                %s\n",
+	               cam->params.format.yuvOrder == YUVORDER_YUYV ?
+		       "YUYV" : "UYVY");
+	out += sprintf(out, "roi:                      (%3d, %3d) to (%3d, %3d)\n",
+	               cam->params.roi.colStart*8,
+	               cam->params.roi.rowStart*4,
+	               cam->params.roi.colEnd*8,
+	               cam->params.roi.rowEnd*4);
+	out += sprintf(out, "actual_fps:               %3d\n", cam->fps);
+	out += sprintf(out, "transfer_rate:            %4dkB/s\n",
+	               cam->transfer_rate);
+	
+	out += sprintf(out, "\nread-write\n");
+	out += sprintf(out, "-----------------------  current       min"
+	               "       max   default  comment\n");
+	out += sprintf(out, "brightness:             %8d  %8d  %8d  %8d\n",
+	               cam->params.colourParams.brightness, 0, 100, 50);
+	if (cam->params.version.firmwareVersion == 1 &&
+	   cam->params.version.firmwareRevision == 2)
+		/* 1-02 firmware limits contrast to 80 */
+		tmp = 80;
+	else
+		tmp = 96;
+
+	out += sprintf(out, "contrast:               %8d  %8d  %8d  %8d"
+	               "  steps of 8\n",
+	               cam->params.colourParams.contrast, 0, tmp, 48);
+	out += sprintf(out, "saturation:             %8d  %8d  %8d  %8d\n",
+	               cam->params.colourParams.saturation, 0, 100, 50);
+	tmp = (25000+5000*cam->params.sensorFps.baserate)/
+	      (1<<cam->params.sensorFps.divisor);
+	out += sprintf(out, "sensor_fps:             %4d.%03d  %8d  %8d  %8d\n",
+	               tmp/1000, tmp%1000, 3, 30, 15);
+	out += sprintf(out, "stream_start_line:      %8d  %8d  %8d  %8d\n",
+	               2*cam->params.streamStartLine, 0,
+		       cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
+		       cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
+	out += sprintf(out, "ecp_timing:             %8s  %8s  %8s  %8s\n",
+	               cam->params.ecpTiming ? "slow" : "normal", "slow",
+		       "normal", "normal");
+
+	if (cam->params.colourBalance.balanceModeIsAuto) {
+		sprintf(tmpstr, "auto");
+	} else {
+		sprintf(tmpstr, "manual");
+	}
+	out += sprintf(out, "color_balance_mode:     %8s  %8s  %8s"
+		       "  %8s\n",  tmpstr, "manual", "auto", "auto");
+	out += sprintf(out, "red_gain:               %8d  %8d  %8d  %8d\n",
+	               cam->params.colourBalance.redGain, 0, 212, 32);
+	out += sprintf(out, "green_gain:             %8d  %8d  %8d  %8d\n",
+	               cam->params.colourBalance.greenGain, 0, 212, 6);
+	out += sprintf(out, "blue_gain:              %8d  %8d  %8d  %8d\n",
+	               cam->params.colourBalance.blueGain, 0, 212, 92);
+
+	if (cam->params.version.firmwareVersion == 1 &&
+	   cam->params.version.firmwareRevision == 2)
+		/* 1-02 firmware limits gain to 2 */
+		sprintf(tmpstr, "%8d  %8d", 1, 2);
+	else
+		sprintf(tmpstr, "1,2,4,8");
+
+	if (cam->params.exposure.gainMode == 0)
+		out += sprintf(out, "max_gain:                unknown  %18s"
+		               "  %8d\n", tmpstr, 2); 
+	else
+		out += sprintf(out, "max_gain:               %8d  %18s  %8d\n", 
+		               1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
+
+	switch(cam->params.exposure.expMode) {
+	case 1:
+	case 3:
+		sprintf(tmpstr, "manual");
+		break;
+	case 2:
+		sprintf(tmpstr, "auto");
+		break;
+	default:
+		sprintf(tmpstr, "unknown");
+		break;
+	}
+	out += sprintf(out, "exposure_mode:          %8s  %8s  %8s"
+		       "  %8s\n",  tmpstr, "manual", "auto", "auto");
+	out += sprintf(out, "centre_weight:          %8s  %8s  %8s  %8s\n",
+	               (2-cam->params.exposure.centreWeight) ? "on" : "off",
+	               "off", "on", "on");
+	out += sprintf(out, "gain:                   %8d  %8d  max_gain  %8d  1,2,4,8 possible\n",
+	               1<<cam->params.exposure.gain, 1, 1);
+	if (cam->params.version.firmwareVersion == 1 &&
+	   cam->params.version.firmwareRevision == 2)
+		/* 1-02 firmware limits fineExp to 127 */
+		tmp = 255;
+	else
+		tmp = 511;
+
+	out += sprintf(out, "fine_exp:               %8d  %8d  %8d  %8d\n",
+	               cam->params.exposure.fineExp*2, 0, tmp, 0);
+	if (cam->params.version.firmwareVersion == 1 &&
+	   cam->params.version.firmwareRevision == 2)
+		/* 1-02 firmware limits coarseExpHi to 0 */
+		tmp = 255;
+	else
+		tmp = 65535;
+
+	out += sprintf(out, "coarse_exp:             %8d  %8d  %8d"
+		       "  %8d\n", cam->params.exposure.coarseExpLo+
+		       256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
+	out += sprintf(out, "red_comp:               %8d  %8d  %8d  %8d\n",
+	               cam->params.exposure.redComp, 220, 255, 220);
+	out += sprintf(out, "green1_comp:            %8d  %8d  %8d  %8d\n",
+	               cam->params.exposure.green1Comp, 214, 255, 214);
+	out += sprintf(out, "green2_comp:            %8d  %8d  %8d  %8d\n",
+	               cam->params.exposure.green2Comp, 214, 255, 214);
+	out += sprintf(out, "blue_comp:              %8d  %8d  %8d  %8d\n",
+	               cam->params.exposure.blueComp, 230, 255, 230);
+	
+	out += sprintf(out, "apcor_gain1:            %#8x  %#8x  %#8x  %#8x\n",
+	               cam->params.apcor.gain1, 0, 0xff, 0x1c);
+	out += sprintf(out, "apcor_gain2:            %#8x  %#8x  %#8x  %#8x\n",
+	               cam->params.apcor.gain2, 0, 0xff, 0x1a);
+	out += sprintf(out, "apcor_gain4:            %#8x  %#8x  %#8x  %#8x\n",
+	               cam->params.apcor.gain4, 0, 0xff, 0x2d);
+	out += sprintf(out, "apcor_gain8:            %#8x  %#8x  %#8x  %#8x\n",
+	               cam->params.apcor.gain8, 0, 0xff, 0x2a);
+	out += sprintf(out, "vl_offset_gain1:        %8d  %8d  %8d  %8d\n",
+	               cam->params.vlOffset.gain1, 0, 255, 24);
+	out += sprintf(out, "vl_offset_gain2:        %8d  %8d  %8d  %8d\n",
+	               cam->params.vlOffset.gain2, 0, 255, 28);
+	out += sprintf(out, "vl_offset_gain4:        %8d  %8d  %8d  %8d\n",
+	               cam->params.vlOffset.gain4, 0, 255, 30);
+	out += sprintf(out, "vl_offset_gain8:        %8d  %8d  %8d  %8d\n",
+	               cam->params.vlOffset.gain8, 0, 255, 30);
+	out += sprintf(out, "flicker_control:        %8s  %8s  %8s  %8s\n",
+	               cam->params.flickerControl.flickerMode ? "on" : "off",
+		       "off", "on", "off");
+	out += sprintf(out, "mains_frequency:        %8d  %8d  %8d  %8d"
+	               " only 50/60\n",
+	               cam->mainsFreq ? 60 : 50, 50, 60, 50);
+	out += sprintf(out, "allowable_overexposure: %8d  %8d  %8d  %8d\n",
+	               cam->params.flickerControl.allowableOverExposure, 0,
+		       255, 0);
+	out += sprintf(out, "compression_mode:       ");
+	switch(cam->params.compression.mode) {
+	case CPIA_COMPRESSION_NONE:
+		out += sprintf(out, "%8s", "none");
+		break;
+	case CPIA_COMPRESSION_AUTO:
+		out += sprintf(out, "%8s", "auto");
+		break;
+	case CPIA_COMPRESSION_MANUAL:
+		out += sprintf(out, "%8s", "manual");
+		break;
+	default:
+		out += sprintf(out, "%8s", "unknown");
+		break;
+	}
+	out += sprintf(out, "    none,auto,manual      auto\n");
+	out += sprintf(out, "decimation_enable:      %8s  %8s  %8s  %8s\n",
+        	       cam->params.compression.decimation == 
+		       DECIMATION_ENAB ? "on":"off", "off", "off",
+		       "off");
+	out += sprintf(out, "compression_target:    %9s %9s %9s %9s\n",
+	               cam->params.compressionTarget.frTargeting  == 
+		       CPIA_COMPRESSION_TARGET_FRAMERATE ?
+		       "framerate":"quality",
+		       "framerate", "quality", "quality");
+	out += sprintf(out, "target_framerate:       %8d  %8d  %8d  %8d\n",
+	               cam->params.compressionTarget.targetFR, 0, 30, 7);
+	out += sprintf(out, "target_quality:         %8d  %8d  %8d  %8d\n",
+	               cam->params.compressionTarget.targetQ, 0, 255, 10);
+	out += sprintf(out, "y_threshold:            %8d  %8d  %8d  %8d\n",
+	               cam->params.yuvThreshold.yThreshold, 0, 31, 15);
+	out += sprintf(out, "uv_threshold:           %8d  %8d  %8d  %8d\n",
+	               cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
+	out += sprintf(out, "hysteresis:             %8d  %8d  %8d  %8d\n",
+	               cam->params.compressionParams.hysteresis, 0, 255, 3);
+	out += sprintf(out, "threshold_max:          %8d  %8d  %8d  %8d\n",
+	               cam->params.compressionParams.threshMax, 0, 255, 11);
+	out += sprintf(out, "small_step:             %8d  %8d  %8d  %8d\n",
+	               cam->params.compressionParams.smallStep, 0, 255, 1);
+	out += sprintf(out, "large_step:             %8d  %8d  %8d  %8d\n",
+	               cam->params.compressionParams.largeStep, 0, 255, 3);
+	out += sprintf(out, "decimation_hysteresis:  %8d  %8d  %8d  %8d\n",
+	               cam->params.compressionParams.decimationHysteresis,
+		       0, 255, 2);
+	out += sprintf(out, "fr_diff_step_thresh:    %8d  %8d  %8d  %8d\n",
+	               cam->params.compressionParams.frDiffStepThresh,
+		       0, 255, 5);
+	out += sprintf(out, "q_diff_step_thresh:     %8d  %8d  %8d  %8d\n",
+	               cam->params.compressionParams.qDiffStepThresh,
+		       0, 255, 3);
+	out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
+	               cam->params.compressionParams.decimationThreshMod,
+		       0, 255, 2);
+	
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else
+		len = count;
+
+	*start = page + off;
+	return len;
+}
+
+static int cpia_write_proc(struct file *file, const char *buffer,
+                           unsigned long count, void *data)
+{
+	struct cam_data *cam = data;
+	struct cam_params new_params;
+	int retval, find_colon;
+	int size = count;
+	unsigned long val;
+	u32 command_flags = 0;
+	u8 new_mains;
+	
+	if (down_interruptible(&cam->param_lock))
+		return -ERESTARTSYS;
+	
+	/*
+	 * Skip over leading whitespace
+	 */
+	while (count && isspace(*buffer)) {
+		--count;
+		++buffer;
+	}
+	
+	memcpy(&new_params, &cam->params, sizeof(struct cam_params));
+	new_mains = cam->mainsFreq;
+	
+#define MATCH(x) \
+	({ \
+		int _len = strlen(x), _ret, _colon_found; \
+		_ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
+		if (_ret) { \
+			buffer += _len; \
+			count -= _len; \
+			if (find_colon) { \
+				_colon_found = 0; \
+				while (count && (*buffer == ' ' || *buffer == '\t' || \
+				       (!_colon_found && *buffer == ':'))) { \
+					if (*buffer == ':')  \
+						_colon_found = 1; \
+					--count; \
+					++buffer; \
+				} \
+				if (!count || !_colon_found) \
+					retval = -EINVAL; \
+				find_colon = 0; \
+			} \
+		} \
+		_ret; \
+	})
+#define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
+                               new_params.version.firmwareRevision == (y))
+#define VALUE \
+	({ \
+		char *_p; \
+		unsigned long int _ret; \
+		_ret = simple_strtoul(buffer, &_p, 0); \
+		if (_p == buffer) \
+			retval = -EINVAL; \
+		else { \
+			count -= _p - buffer; \
+			buffer = _p; \
+		} \
+		_ret; \
+	})
+
+	retval = 0;
+	while (count && !retval) {
+		find_colon = 1;
+		if (MATCH("brightness")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 100)
+					new_params.colourParams.brightness = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOLOURPARAMS;
+		} else if (MATCH("contrast")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 100) {
+					/* contrast is in steps of 8, so round*/
+					val = ((val + 3) / 8) * 8;
+					/* 1-02 firmware limits contrast to 80*/
+					if (FIRMWARE_VERSION(1,2) && val > 80)
+						val = 80;
+
+					new_params.colourParams.contrast = val;
+				} else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOLOURPARAMS;
+		} else if (MATCH("saturation")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 100)
+					new_params.colourParams.saturation = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOLOURPARAMS;
+		} else if (MATCH("sensor_fps")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				/* find values so that sensorFPS is minimized,
+				 * but >= val */
+				if (val > 30)
+					retval = -EINVAL;
+				else if (val > 25) {
+					new_params.sensorFps.divisor = 0;
+					new_params.sensorFps.baserate = 1;
+				} else if (val > 15) {
+					new_params.sensorFps.divisor = 0;
+					new_params.sensorFps.baserate = 0;
+				} else if (val > 12) {
+					new_params.sensorFps.divisor = 1;
+					new_params.sensorFps.baserate = 1;
+				} else if (val > 7) {
+					new_params.sensorFps.divisor = 1;
+					new_params.sensorFps.baserate = 0;
+				} else if (val > 6) {
+					new_params.sensorFps.divisor = 2;
+					new_params.sensorFps.baserate = 1;
+				} else if (val > 3) {
+					new_params.sensorFps.divisor = 2;
+					new_params.sensorFps.baserate = 0;
+				} else {
+					new_params.sensorFps.divisor = 3;
+					/* Either base rate would work here */
+					new_params.sensorFps.baserate = 1;
+				}
+				new_params.flickerControl.coarseJump = 
+					flicker_jumps[new_mains]
+					[new_params.sensorFps.baserate]
+					[new_params.sensorFps.divisor];
+				if (new_params.flickerControl.flickerMode)
+					command_flags |= COMMAND_SETFLICKERCTRL;
+			}
+			command_flags |= COMMAND_SETSENSORFPS;
+		} else if (MATCH("stream_start_line")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				int max_line = 288;
+
+				if (new_params.format.videoSize == VIDEOSIZE_QCIF)
+					max_line = 144;
+				if (val <= max_line)
+					new_params.streamStartLine = val/2;
+				else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("ecp_timing")) {
+			if (!retval && MATCH("normal"))
+				new_params.ecpTiming = 0;
+			else if (!retval && MATCH("slow"))
+				new_params.ecpTiming = 1;
+			else
+				retval = -EINVAL;
+
+			command_flags |= COMMAND_SETECPTIMING;
+		} else if (MATCH("color_balance_mode")) {
+			if (!retval && MATCH("manual"))
+				new_params.colourBalance.balanceModeIsAuto = 0;
+			else if (!retval && MATCH("auto"))
+				new_params.colourBalance.balanceModeIsAuto = 1;
+			else
+				retval = -EINVAL;
+
+			command_flags |= COMMAND_SETCOLOURBALANCE;
+		} else if (MATCH("red_gain")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 212)
+					new_params.colourBalance.redGain = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOLOURBALANCE;
+		} else if (MATCH("green_gain")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 212)
+					new_params.colourBalance.greenGain = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOLOURBALANCE;
+		} else if (MATCH("blue_gain")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 212)
+					new_params.colourBalance.blueGain = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOLOURBALANCE;
+		} else if (MATCH("max_gain")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				/* 1-02 firmware limits gain to 2 */
+				if (FIRMWARE_VERSION(1,2) && val > 2)
+					val = 2;
+				switch(val) {
+				case 1:
+					new_params.exposure.gainMode = 1;
+					break;
+				case 2:
+					new_params.exposure.gainMode = 2;
+					break;
+				case 4:
+					new_params.exposure.gainMode = 3;
+					break;
+				case 8:
+					new_params.exposure.gainMode = 4;
+					break;
+				default:
+					retval = -EINVAL;
+					break;
+				}
+			}
+			command_flags |= COMMAND_SETEXPOSURE;
+		} else if (MATCH("exposure_mode")) {
+			if (!retval && MATCH("auto"))
+				new_params.exposure.expMode = 2;
+			else if (!retval && MATCH("manual")) {
+				if (new_params.exposure.expMode == 2)
+					new_params.exposure.expMode = 3;
+				new_params.flickerControl.flickerMode = 0;
+				command_flags |= COMMAND_SETFLICKERCTRL;
+			} else
+				retval = -EINVAL;
+
+			command_flags |= COMMAND_SETEXPOSURE;
+		} else if (MATCH("centre_weight")) {
+			if (!retval && MATCH("on"))
+				new_params.exposure.centreWeight = 1;
+			else if (!retval && MATCH("off"))
+				new_params.exposure.centreWeight = 2;
+			else
+				retval = -EINVAL;
+
+			command_flags |= COMMAND_SETEXPOSURE;
+		} else if (MATCH("gain")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				switch(val) {
+				case 1:
+					new_params.exposure.gain = 0;
+					new_params.exposure.expMode = 1;
+					new_params.flickerControl.flickerMode = 0;
+					command_flags |= COMMAND_SETFLICKERCTRL;
+					break;
+				case 2:
+					new_params.exposure.gain = 1;
+					new_params.exposure.expMode = 1;
+					new_params.flickerControl.flickerMode = 0;
+					command_flags |= COMMAND_SETFLICKERCTRL;
+					break;
+				case 4:
+					new_params.exposure.gain = 2;
+					new_params.exposure.expMode = 1;
+					new_params.flickerControl.flickerMode = 0;
+					command_flags |= COMMAND_SETFLICKERCTRL;
+					break;
+				case 8:
+					new_params.exposure.gain = 3;
+					new_params.exposure.expMode = 1;
+					new_params.flickerControl.flickerMode = 0;
+					command_flags |= COMMAND_SETFLICKERCTRL;
+					break;
+				default:
+					retval = -EINVAL;
+					break;
+				}
+				command_flags |= COMMAND_SETEXPOSURE;
+				if (new_params.exposure.gain >
+				    new_params.exposure.gainMode-1)
+					retval = -EINVAL;
+			}
+		} else if (MATCH("fine_exp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val < 256) {
+					/* 1-02 firmware limits fineExp to 127*/
+					if (FIRMWARE_VERSION(1,2) && val > 127)
+						val = 127;
+					new_params.exposure.fineExp = val;
+					new_params.exposure.expMode = 1;
+					command_flags |= COMMAND_SETEXPOSURE;
+					new_params.flickerControl.flickerMode = 0;
+					command_flags |= COMMAND_SETFLICKERCTRL;
+				} else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("coarse_exp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val < 65536) {
+					/* 1-02 firmware limits
+					 * coarseExp to 255 */
+					if (FIRMWARE_VERSION(1,2) && val > 255)
+						val = 255;
+					new_params.exposure.coarseExpLo =
+						val & 0xff;
+					new_params.exposure.coarseExpHi =
+						val >> 8;
+					new_params.exposure.expMode = 1;
+					command_flags |= COMMAND_SETEXPOSURE;
+					new_params.flickerControl.flickerMode = 0;
+					command_flags |= COMMAND_SETFLICKERCTRL;
+				} else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("red_comp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val >= 220 && val <= 255) {
+					new_params.exposure.redComp = val;
+					command_flags |= COMMAND_SETEXPOSURE;
+				} else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("green1_comp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val >= 214 && val <= 255) {
+					new_params.exposure.green1Comp = val;
+					command_flags |= COMMAND_SETEXPOSURE;
+				} else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("green2_comp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val >= 214 && val <= 255) {
+					new_params.exposure.green2Comp = val;
+					command_flags |= COMMAND_SETEXPOSURE;
+				} else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("blue_comp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val >= 230 && val <= 255) {
+					new_params.exposure.blueComp = val;
+					command_flags |= COMMAND_SETEXPOSURE;
+				} else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("apcor_gain1")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				command_flags |= COMMAND_SETAPCOR;
+				if (val <= 0xff)
+					new_params.apcor.gain1 = val;
+				else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("apcor_gain2")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				command_flags |= COMMAND_SETAPCOR;
+				if (val <= 0xff)
+					new_params.apcor.gain2 = val;
+				else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("apcor_gain4")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				command_flags |= COMMAND_SETAPCOR;
+				if (val <= 0xff)
+					new_params.apcor.gain4 = val;
+				else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("apcor_gain8")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				command_flags |= COMMAND_SETAPCOR;
+				if (val <= 0xff)
+					new_params.apcor.gain8 = val;
+				else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("vl_offset_gain1")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.vlOffset.gain1 = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETVLOFFSET;
+		} else if (MATCH("vl_offset_gain2")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.vlOffset.gain2 = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETVLOFFSET;
+		} else if (MATCH("vl_offset_gain4")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.vlOffset.gain4 = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETVLOFFSET;
+		} else if (MATCH("vl_offset_gain8")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.vlOffset.gain8 = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETVLOFFSET;
+		} else if (MATCH("flicker_control")) {
+			if (!retval && MATCH("on")) {
+				new_params.flickerControl.flickerMode = 1;
+				new_params.exposure.expMode = 2;
+				command_flags |= COMMAND_SETEXPOSURE;
+			} else if (!retval && MATCH("off"))
+				new_params.flickerControl.flickerMode = 0;
+			else
+				retval = -EINVAL;
+
+			command_flags |= COMMAND_SETFLICKERCTRL;
+		} else if (MATCH("mains_frequency")) {
+			if (!retval && MATCH("50")) {
+				new_mains = 0;
+				new_params.flickerControl.coarseJump = 
+					flicker_jumps[new_mains]
+					[new_params.sensorFps.baserate]
+					[new_params.sensorFps.divisor];
+				if (new_params.flickerControl.flickerMode)
+					command_flags |= COMMAND_SETFLICKERCTRL;
+			} else if (!retval && MATCH("60")) {
+				new_mains = 1;
+				new_params.flickerControl.coarseJump = 
+					flicker_jumps[new_mains]
+					[new_params.sensorFps.baserate]
+					[new_params.sensorFps.divisor];
+				if (new_params.flickerControl.flickerMode)
+					command_flags |= COMMAND_SETFLICKERCTRL;
+			} else
+				retval = -EINVAL;
+		} else if (MATCH("allowable_overexposure")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff) {
+					new_params.flickerControl.
+						allowableOverExposure = val;
+					command_flags |= COMMAND_SETFLICKERCTRL;
+				} else
+					retval = -EINVAL;
+			}
+		} else if (MATCH("compression_mode")) {
+			if (!retval && MATCH("none"))
+				new_params.compression.mode =
+					CPIA_COMPRESSION_NONE;
+			else if (!retval && MATCH("auto"))
+				new_params.compression.mode =
+					CPIA_COMPRESSION_AUTO;
+			else if (!retval && MATCH("manual"))
+				new_params.compression.mode =
+					CPIA_COMPRESSION_MANUAL;
+			else
+				retval = -EINVAL;
+
+			command_flags |= COMMAND_SETCOMPRESSION;
+		} else if (MATCH("decimation_enable")) {
+			if (!retval && MATCH("off"))
+				new_params.compression.decimation = 0;
+			else
+				retval = -EINVAL;
+
+			command_flags |= COMMAND_SETCOMPRESSION;
+		} else if (MATCH("compression_target")) {
+			if (!retval && MATCH("quality"))
+				new_params.compressionTarget.frTargeting = 
+					CPIA_COMPRESSION_TARGET_QUALITY;
+			else if (!retval && MATCH("framerate"))
+				new_params.compressionTarget.frTargeting = 
+					CPIA_COMPRESSION_TARGET_FRAMERATE;
+			else
+				retval = -EINVAL;
+
+			command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+		} else if (MATCH("target_framerate")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval)
+				new_params.compressionTarget.targetFR = val;
+			command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+		} else if (MATCH("target_quality")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval)
+				new_params.compressionTarget.targetQ = val;
+
+			command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+		} else if (MATCH("y_threshold")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val < 32)
+					new_params.yuvThreshold.yThreshold = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETYUVTHRESH;
+		} else if (MATCH("uv_threshold")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val < 32)
+					new_params.yuvThreshold.uvThreshold = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETYUVTHRESH;
+		} else if (MATCH("hysteresis")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.hysteresis = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("threshold_max")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.threshMax = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("small_step")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.smallStep = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("large_step")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.largeStep = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("decimation_hysteresis")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.decimationHysteresis = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("fr_diff_step_thresh")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.frDiffStepThresh = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("q_diff_step_thresh")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.qDiffStepThresh = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("decimation_thresh_mod")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.decimationThreshMod = val;
+				else
+					retval = -EINVAL;
+			}
+			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else {
+			DBG("No match found\n");
+			retval = -EINVAL;
+		}
+
+		if (!retval) {
+			while (count && isspace(*buffer) && *buffer != '\n') {
+				--count;
+				++buffer;
+			}
+			if (count) {
+				if (*buffer != '\n' && *buffer != ';')
+					retval = -EINVAL;
+				else {
+					--count;
+					++buffer;
+				}
+			}
+		}
+	}
+#undef MATCH	
+#undef FIRMWARE_VERSION
+#undef VALUE
+#undef FIND_VALUE
+#undef FIND_END
+	if (!retval) {
+		if (command_flags & COMMAND_SETCOLOURPARAMS) {
+			/* Adjust cam->vp to reflect these changes */
+			cam->vp.brightness =
+				new_params.colourParams.brightness*65535/100;
+			cam->vp.contrast =
+				new_params.colourParams.contrast*65535/100;
+			cam->vp.colour =
+				new_params.colourParams.saturation*65535/100;
+		}
+		
+		memcpy(&cam->params, &new_params, sizeof(struct cam_params));
+		cam->mainsFreq = new_mains;
+		cam->cmd_queue |= command_flags;
+		retval = size;
+	} else
+		DBG("error: %d\n", retval);
+	
+	up(&cam->param_lock);
+	
+	return retval;
+}
+
+static void create_proc_cpia_cam(struct cam_data *cam)
+{
+	char name[7];
+	struct proc_dir_entry *ent;
+	
+	if (!cpia_proc_root || !cam)
+		return;
+
+	sprintf(name, "video%d", cam->vdev.minor);
+	
+	ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
+	if (!ent)
+		return;
+
+	ent->data = cam;
+	ent->read_proc = cpia_read_proc;
+	ent->write_proc = cpia_write_proc;
+	ent->size = 3626;
+	cam->proc_entry = ent;
+}
+
+static void destroy_proc_cpia_cam(struct cam_data *cam)
+{
+	char name[7];
+	
+	if (!cam || !cam->proc_entry)
+		return;
+	
+	sprintf(name, "video%d", cam->vdev.minor);
+	remove_proc_entry(name, cpia_proc_root);
+	cam->proc_entry = NULL;
+}
+
+static void proc_cpia_create(void)
+{
+	cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
+
+	if (cpia_proc_root)
+		cpia_proc_root->owner = THIS_MODULE;
+	else
+		LOG("Unable to initialise /proc/cpia\n");
+}
+
+static void proc_cpia_destroy(void)
+{
+	remove_proc_entry("cpia", 0);
+}
+#endif /* CONFIG_PROC_FS */
+
+/* ----------------------- debug functions ---------------------- */
+
+#define printstatus(cam) \
+  DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
+	cam->params.status.systemState, cam->params.status.grabState, \
+	cam->params.status.streamState, cam->params.status.fatalError, \
+	cam->params.status.cmdError, cam->params.status.debugFlags, \
+	cam->params.status.vpStatus, cam->params.status.errorCode);
+
+/* ----------------------- v4l helpers -------------------------- */
+
+/* supported frame palettes and depths */
+static inline int valid_mode(u16 palette, u16 depth)
+{
+	return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
+	       (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
+	       (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
+	       (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
+	       (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
+	       (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
+	       (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
+	       (palette == VIDEO_PALETTE_UYVY && depth == 16);
+}
+
+static int match_videosize( int width, int height )
+{
+	/* return the best match, where 'best' is as always
+	 * the largest that is not bigger than what is requested. */
+	if (width>=352 && height>=288)
+		return VIDEOSIZE_352_288; /* CIF */
+
+	if (width>=320 && height>=240)
+		return VIDEOSIZE_320_240; /* SIF */
+
+	if (width>=288 && height>=216)
+		return VIDEOSIZE_288_216;
+
+	if (width>=256 && height>=192)
+		return VIDEOSIZE_256_192;
+
+	if (width>=224 && height>=168)
+		return VIDEOSIZE_224_168;
+
+	if (width>=192 && height>=144)
+		return VIDEOSIZE_192_144;
+
+	if (width>=176 && height>=144)
+		return VIDEOSIZE_176_144; /* QCIF */
+
+	if (width>=160 && height>=120)
+		return VIDEOSIZE_160_120; /* QSIF */
+
+	if (width>=128 && height>=96)
+		return VIDEOSIZE_128_96;
+
+	if (width>=88 && height>=72)
+		return VIDEOSIZE_88_72;
+
+	if (width>=64 && height>=48)
+		return VIDEOSIZE_64_48;
+
+	if (width>=48 && height>=48)
+		return VIDEOSIZE_48_48;
+
+	return -1;
+}
+
+/* these are the capture sizes we support */
+static void set_vw_size(struct cam_data *cam)
+{
+	/* the col/row/start/end values are the result of simple math    */
+	/* study the SetROI-command in cpia developers guide p 2-22      */
+	/* streamStartLine is set to the recommended value in the cpia   */
+	/*  developers guide p 3-37                                      */
+	switch(cam->video_size) {
+	case VIDEOSIZE_CIF:
+		cam->vw.width = 352;
+		cam->vw.height = 288;
+		cam->params.format.videoSize=VIDEOSIZE_CIF;
+		cam->params.roi.colStart=0;
+		cam->params.roi.colEnd=44;
+		cam->params.roi.rowStart=0;
+		cam->params.roi.rowEnd=72;
+		cam->params.streamStartLine = 120;
+		break;
+	case VIDEOSIZE_SIF:
+		cam->vw.width = 320;
+		cam->vw.height = 240;
+		cam->params.format.videoSize=VIDEOSIZE_CIF;
+		cam->params.roi.colStart=2;
+		cam->params.roi.colEnd=42;
+		cam->params.roi.rowStart=6;
+		cam->params.roi.rowEnd=66;
+		cam->params.streamStartLine = 120;
+		break;
+	case VIDEOSIZE_288_216:
+		cam->vw.width = 288;
+		cam->vw.height = 216;
+		cam->params.format.videoSize=VIDEOSIZE_CIF;
+		cam->params.roi.colStart=4;
+		cam->params.roi.colEnd=40;
+		cam->params.roi.rowStart=9;
+		cam->params.roi.rowEnd=63;
+		cam->params.streamStartLine = 120;
+		break;
+	case VIDEOSIZE_256_192:
+		cam->vw.width = 256;
+		cam->vw.height = 192;
+		cam->params.format.videoSize=VIDEOSIZE_CIF;
+		cam->params.roi.colStart=6;
+		cam->params.roi.colEnd=38;
+		cam->params.roi.rowStart=12;
+		cam->params.roi.rowEnd=60;
+		cam->params.streamStartLine = 120;
+		break;
+	case VIDEOSIZE_224_168:
+		cam->vw.width = 224;
+		cam->vw.height = 168;
+		cam->params.format.videoSize=VIDEOSIZE_CIF;
+		cam->params.roi.colStart=8;
+		cam->params.roi.colEnd=36;
+		cam->params.roi.rowStart=15;
+		cam->params.roi.rowEnd=57;
+		cam->params.streamStartLine = 120;
+		break;
+	case VIDEOSIZE_192_144:
+		cam->vw.width = 192;
+		cam->vw.height = 144;
+		cam->params.format.videoSize=VIDEOSIZE_CIF;
+		cam->params.roi.colStart=10;
+		cam->params.roi.colEnd=34;
+		cam->params.roi.rowStart=18;
+		cam->params.roi.rowEnd=54;
+		cam->params.streamStartLine = 120;
+		break;
+	case VIDEOSIZE_QCIF:
+		cam->vw.width = 176;
+		cam->vw.height = 144;
+		cam->params.format.videoSize=VIDEOSIZE_QCIF;
+		cam->params.roi.colStart=0;
+		cam->params.roi.colEnd=22;
+		cam->params.roi.rowStart=0;
+		cam->params.roi.rowEnd=36;
+		cam->params.streamStartLine = 60;
+		break;
+	case VIDEOSIZE_QSIF:
+		cam->vw.width = 160;
+		cam->vw.height = 120;
+		cam->params.format.videoSize=VIDEOSIZE_QCIF;
+		cam->params.roi.colStart=1;
+		cam->params.roi.colEnd=21;
+		cam->params.roi.rowStart=3;
+		cam->params.roi.rowEnd=33;
+		cam->params.streamStartLine = 60;
+		break;
+	case VIDEOSIZE_128_96:
+		cam->vw.width = 128;
+		cam->vw.height = 96;
+		cam->params.format.videoSize=VIDEOSIZE_QCIF;
+		cam->params.roi.colStart=3;
+		cam->params.roi.colEnd=19;
+		cam->params.roi.rowStart=6;
+		cam->params.roi.rowEnd=30;
+		cam->params.streamStartLine = 60;
+		break;
+	case VIDEOSIZE_88_72:
+		cam->vw.width = 88;
+		cam->vw.height = 72;
+		cam->params.format.videoSize=VIDEOSIZE_QCIF;
+		cam->params.roi.colStart=5;
+		cam->params.roi.colEnd=16;
+		cam->params.roi.rowStart=9;
+		cam->params.roi.rowEnd=27;
+		cam->params.streamStartLine = 60;
+		break;
+	case VIDEOSIZE_64_48:
+		cam->vw.width = 64;
+		cam->vw.height = 48;
+		cam->params.format.videoSize=VIDEOSIZE_QCIF;
+		cam->params.roi.colStart=7;
+		cam->params.roi.colEnd=15;
+		cam->params.roi.rowStart=12;
+		cam->params.roi.rowEnd=24;
+		cam->params.streamStartLine = 60;
+		break;
+	case VIDEOSIZE_48_48:
+		cam->vw.width = 48;
+		cam->vw.height = 48;
+		cam->params.format.videoSize=VIDEOSIZE_QCIF;
+		cam->params.roi.colStart=8;
+		cam->params.roi.colEnd=14;
+		cam->params.roi.rowStart=6;
+		cam->params.roi.rowEnd=30;
+		cam->params.streamStartLine = 60;
+		break;
+	default:
+		LOG("bad videosize value: %d\n", cam->video_size);
+	}
+
+	return;
+}
+
+static int allocate_frame_buf(struct cam_data *cam)
+{
+	int i;
+
+	cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
+	if (!cam->frame_buf)
+		return -ENOBUFS;
+
+	for (i = 0; i < FRAME_NUM; i++)
+		cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
+
+	return 0;
+}
+
+static int free_frame_buf(struct cam_data *cam)
+{
+	int i;
+	
+	rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
+	cam->frame_buf = 0;
+	for (i=0; i < FRAME_NUM; i++)
+		cam->frame[i].data = NULL;
+
+	return 0;
+}
+
+
+static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
+{
+	int i;
+
+	for (i=0; i < FRAME_NUM; i++)
+		frame[i].state = FRAME_UNUSED;
+	return;
+}
+
+/**********************************************************************
+ *
+ * General functions
+ *
+ **********************************************************************/
+/* send an arbitrary command to the camera */
+static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
+{
+	int retval, datasize;
+	u8 cmd[8], data[8];
+
+	switch(command) {
+	case CPIA_COMMAND_GetCPIAVersion:
+	case CPIA_COMMAND_GetPnPID:
+	case CPIA_COMMAND_GetCameraStatus:
+	case CPIA_COMMAND_GetVPVersion:
+		datasize=8;
+		break;
+	case CPIA_COMMAND_GetColourParams:
+	case CPIA_COMMAND_GetColourBalance:
+	case CPIA_COMMAND_GetExposure:
+		down(&cam->param_lock);
+		datasize=8;
+		break;
+	default:
+		datasize=0;
+		break;
+	}
+
+	cmd[0] = command>>8;
+	cmd[1] = command&0xff;
+	cmd[2] = a;
+	cmd[3] = b;
+	cmd[4] = c;
+	cmd[5] = d;
+	cmd[6] = datasize;
+	cmd[7] = 0;
+
+	retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
+	if (retval)
+		DBG("%x - failed, retval=%d\n", command, retval);
+	else {
+		switch(command) {
+		case CPIA_COMMAND_GetCPIAVersion:
+			cam->params.version.firmwareVersion = data[0];
+			cam->params.version.firmwareRevision = data[1];
+			cam->params.version.vcVersion = data[2];
+			cam->params.version.vcRevision = data[3];
+			break;
+		case CPIA_COMMAND_GetPnPID:
+			cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
+			cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
+			cam->params.pnpID.deviceRevision =
+				data[4]+(((u16)data[5])<<8);
+			break;
+		case CPIA_COMMAND_GetCameraStatus:
+			cam->params.status.systemState = data[0];
+			cam->params.status.grabState = data[1];
+			cam->params.status.streamState = data[2];
+			cam->params.status.fatalError = data[3];
+			cam->params.status.cmdError = data[4];
+			cam->params.status.debugFlags = data[5];
+			cam->params.status.vpStatus = data[6];
+			cam->params.status.errorCode = data[7];
+			break;
+		case CPIA_COMMAND_GetVPVersion:
+			cam->params.vpVersion.vpVersion = data[0];
+			cam->params.vpVersion.vpRevision = data[1];
+			cam->params.vpVersion.cameraHeadID =
+				data[2]+(((u16)data[3])<<8);
+			break;
+		case CPIA_COMMAND_GetColourParams:
+			cam->params.colourParams.brightness = data[0];
+			cam->params.colourParams.contrast = data[1];
+			cam->params.colourParams.saturation = data[2];
+			up(&cam->param_lock);
+			break;
+		case CPIA_COMMAND_GetColourBalance:
+			cam->params.colourBalance.redGain = data[0];
+			cam->params.colourBalance.greenGain = data[1];
+			cam->params.colourBalance.blueGain = data[2];
+			up(&cam->param_lock);
+			break;
+		case CPIA_COMMAND_GetExposure:
+			cam->params.exposure.gain = data[0];
+			cam->params.exposure.fineExp = data[1];
+			cam->params.exposure.coarseExpLo = data[2];
+			cam->params.exposure.coarseExpHi = data[3];
+			cam->params.exposure.redComp = data[4];
+			cam->params.exposure.green1Comp = data[5];
+			cam->params.exposure.green2Comp = data[6];
+			cam->params.exposure.blueComp = data[7];
+			/* If the *Comp parameters are wacko, generate
+			 * a warning, and reset them back to default
+			 * values.             - rich@annexia.org
+			 */
+			if (cam->params.exposure.redComp < 220 ||
+			    cam->params.exposure.redComp > 255 ||
+			    cam->params.exposure.green1Comp < 214 ||
+			    cam->params.exposure.green1Comp > 255 ||
+			    cam->params.exposure.green2Comp < 214 ||
+			    cam->params.exposure.green2Comp > 255 ||
+			    cam->params.exposure.blueComp < 230 ||
+			    cam->params.exposure.blueComp > 255)
+			  {
+			    printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
+				    cam->params.exposure.redComp,
+				    cam->params.exposure.green1Comp,
+				    cam->params.exposure.green2Comp,
+				    cam->params.exposure.blueComp);
+			    cam->params.exposure.redComp = 220;
+			    cam->params.exposure.green1Comp = 214;
+			    cam->params.exposure.green2Comp = 214;
+			    cam->params.exposure.blueComp = 230;
+			  }
+			up(&cam->param_lock);
+			break;
+		default:
+			break;
+		}
+	}
+	return retval;
+}
+
+/* send a command  to the camera with an additional data transaction */
+static int do_command_extended(struct cam_data *cam, u16 command,
+                               u8 a, u8 b, u8 c, u8 d,
+                               u8 e, u8 f, u8 g, u8 h,
+                               u8 i, u8 j, u8 k, u8 l)
+{
+	int retval;
+	u8 cmd[8], data[8];
+
+	cmd[0] = command>>8;
+	cmd[1] = command&0xff;
+	cmd[2] = a;
+	cmd[3] = b;
+	cmd[4] = c;
+	cmd[5] = d;
+	cmd[6] = 8;
+	cmd[7] = 0;
+	data[0] = e;
+	data[1] = f;
+	data[2] = g;
+	data[3] = h;
+	data[4] = i;
+	data[5] = j;
+	data[6] = k;
+	data[7] = l;
+
+	retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
+	if (retval)
+		LOG("%x - failed\n", command);
+
+	return retval;
+}
+
+/**********************************************************************
+ *
+ * Colorspace conversion
+ *
+ **********************************************************************/
+#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
+
+static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
+                      int in_uyvy, int mmap_kludge)
+{
+	int y, u, v, r, g, b, y1;
+
+	switch(out_fmt) {
+	case VIDEO_PALETTE_RGB555:
+	case VIDEO_PALETTE_RGB565:
+	case VIDEO_PALETTE_RGB24:
+	case VIDEO_PALETTE_RGB32:
+		if (in_uyvy) {
+			u = *yuv++ - 128;
+			y = (*yuv++ - 16) * 76310;
+			v = *yuv++ - 128;
+			y1 = (*yuv - 16) * 76310;
+		} else {
+			y = (*yuv++ - 16) * 76310;
+			u = *yuv++ - 128;
+			y1 = (*yuv++ - 16) * 76310;
+			v = *yuv - 128;
+		}
+		r = 104635 * v;
+		g = -25690 * u + -53294 * v;
+		b = 132278 * u;
+		break;
+	default:
+		y = *yuv++;
+		u = *yuv++;
+		y1 = *yuv++;
+		v = *yuv;
+		/* Just to avoid compiler warnings */
+		r = 0;
+		g = 0;
+		b = 0;
+		break;
+	}
+	switch(out_fmt) {
+	case VIDEO_PALETTE_RGB555:
+		*rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
+		*rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
+		*rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
+		*rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
+		return 4;
+	case VIDEO_PALETTE_RGB565:
+		*rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
+		*rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
+		*rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
+		*rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
+		return 4;
+	case VIDEO_PALETTE_RGB24:
+		if (mmap_kludge) {
+			*rgb++ = LIMIT(b+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(r+y);
+			*rgb++ = LIMIT(b+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(r+y1);
+		} else {
+			*rgb++ = LIMIT(r+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(b+y);
+			*rgb++ = LIMIT(r+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(b+y1);
+		}
+		return 6;
+	case VIDEO_PALETTE_RGB32:
+		if (mmap_kludge) {
+			*rgb++ = LIMIT(b+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(r+y);
+			rgb++;
+			*rgb++ = LIMIT(b+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(r+y1);
+		} else {
+			*rgb++ = LIMIT(r+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(b+y);
+			rgb++;
+			*rgb++ = LIMIT(r+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(b+y1);
+		}
+		return 8;
+	case VIDEO_PALETTE_GREY:
+		*rgb++ = y;
+		*rgb = y1;
+		return 2;
+	case VIDEO_PALETTE_YUV422:
+	case VIDEO_PALETTE_YUYV:
+		*rgb++ = y;
+		*rgb++ = u;
+		*rgb++ = y1;
+		*rgb = v;
+		return 4;
+	case VIDEO_PALETTE_UYVY:
+		*rgb++ = u;
+		*rgb++ = y;
+		*rgb++ = v;
+		*rgb = y1;
+		return 4;
+	default:
+		DBG("Empty: %d\n", out_fmt);
+		return 0;
+	}
+}
+
+static int skipcount(int count, int fmt)
+{
+	switch(fmt) {
+	case VIDEO_PALETTE_GREY:
+	case VIDEO_PALETTE_RGB555:
+	case VIDEO_PALETTE_RGB565:
+	case VIDEO_PALETTE_YUV422:
+	case VIDEO_PALETTE_YUYV:
+	case VIDEO_PALETTE_UYVY:
+		return 2*count;
+	case VIDEO_PALETTE_RGB24:
+		return 3*count;
+	case VIDEO_PALETTE_RGB32:
+		return 4*count;
+	default:
+		return 0;
+	}
+}
+
+static int parse_picture(struct cam_data *cam, int size)
+{
+	u8 *obuf, *ibuf, *end_obuf;
+	int ll, in_uyvy, compressed, origsize, out_fmt;
+
+	/* make sure params don't change while we are decoding */
+	down(&cam->param_lock);
+
+	obuf = cam->decompressed_frame.data;
+	end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
+	ibuf = cam->raw_image;
+	origsize = size;
+	out_fmt = cam->vp.palette;
+
+	if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
+		LOG("header not found\n");
+		up(&cam->param_lock);
+		return -1;
+	}
+
+	if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
+		LOG("wrong video size\n");
+		up(&cam->param_lock);
+		return -1;
+	}
+	
+	if (ibuf[17] != SUBSAMPLE_422) {
+		LOG("illegal subtype %d\n",ibuf[17]);
+		up(&cam->param_lock);
+		return -1;
+	}
+	
+	if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
+		LOG("illegal yuvorder %d\n",ibuf[18]);
+		up(&cam->param_lock);
+		return -1;
+	}
+	in_uyvy = ibuf[18] == YUVORDER_UYVY;
+	
+#if 0
+	/* FIXME: ROI mismatch occurs when switching capture sizes */
+	if ((ibuf[24] != cam->params.roi.colStart) ||
+	    (ibuf[25] != cam->params.roi.colEnd) ||
+	    (ibuf[26] != cam->params.roi.rowStart) ||
+	    (ibuf[27] != cam->params.roi.rowEnd)) {
+		LOG("ROI mismatch\n");
+		up(&cam->param_lock);
+		return -1;
+	}
+#endif
+	
+	if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
+		LOG("illegal compression %d\n",ibuf[28]);
+		up(&cam->param_lock);
+		return -1;
+	}
+	compressed = (ibuf[28] == COMPRESSED);
+	
+	if (ibuf[29] != NO_DECIMATION) {
+		LOG("decimation not supported\n");
+		up(&cam->param_lock);
+		return -1;
+	}
+	
+	cam->params.yuvThreshold.yThreshold = ibuf[30];
+	cam->params.yuvThreshold.uvThreshold = ibuf[31];
+	cam->params.status.systemState = ibuf[32];
+	cam->params.status.grabState = ibuf[33];
+	cam->params.status.streamState = ibuf[34];
+	cam->params.status.fatalError = ibuf[35];
+	cam->params.status.cmdError = ibuf[36];
+	cam->params.status.debugFlags = ibuf[37];
+	cam->params.status.vpStatus = ibuf[38];
+	cam->params.status.errorCode = ibuf[39];
+	cam->fps = ibuf[41];
+	up(&cam->param_lock);
+	
+	ibuf += FRAME_HEADER_SIZE;
+	size -= FRAME_HEADER_SIZE;
+	ll = ibuf[0] | (ibuf[1] << 8);
+	ibuf += 2;
+
+	while (size > 0) {
+		size -= (ll+2);
+		if (size < 0) {
+			LOG("Insufficient data in buffer\n");
+			return -1;
+		}
+
+		while (ll > 1) {
+			if (!compressed || (compressed && !(*ibuf & 1))) {
+				obuf += yuvconvert(ibuf, obuf, out_fmt,
+				                   in_uyvy, cam->mmap_kludge);
+				ibuf += 4;
+				ll -= 4;
+			} else {
+				/*skip compressed interval from previous frame*/
+				int skipsize = skipcount(*ibuf >> 1, out_fmt);
+				obuf += skipsize;
+				if (obuf > end_obuf) {
+					LOG("Insufficient data in buffer\n");
+					return -1;
+				}
+				++ibuf;
+				ll--;
+			}
+		}
+		if (ll == 1) {
+			if (*ibuf != EOL) {
+				LOG("EOL not found giving up after %d/%d"
+				    " bytes\n", origsize-size, origsize);
+				return -1;
+			}
+
+			ibuf++; /* skip over EOL */
+
+			if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
+			   (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
+			 	size -= 4;
+				break;
+			}
+
+			if (size > 1) {
+				ll = ibuf[0] | (ibuf[1] << 8);
+				ibuf += 2; /* skip over line length */
+			}
+		} else {
+			LOG("line length was not 1 but %d after %d/%d bytes\n",
+			    ll, origsize-size, origsize);
+			return -1;
+		}
+	}
+	
+	cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
+
+	return cam->decompressed_frame.count;
+}
+
+/* InitStreamCap wrapper to select correct start line */
+static inline int init_stream_cap(struct cam_data *cam)
+{
+	return do_command(cam, CPIA_COMMAND_InitStreamCap,
+	                  0, cam->params.streamStartLine, 0, 0);
+}
+
+/* update various camera modes and settings */
+static void dispatch_commands(struct cam_data *cam)
+{
+	down(&cam->param_lock);
+	if (cam->cmd_queue==COMMAND_NONE) {
+		up(&cam->param_lock);
+		return;
+	}
+	DEB_BYTE(cam->cmd_queue);
+	DEB_BYTE(cam->cmd_queue>>8);
+	if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
+		do_command(cam, CPIA_COMMAND_SetColourParams,
+		           cam->params.colourParams.brightness,
+		           cam->params.colourParams.contrast,
+		           cam->params.colourParams.saturation, 0);
+
+	if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
+		do_command(cam, CPIA_COMMAND_SetCompression,
+		           cam->params.compression.mode,
+			   cam->params.compression.decimation, 0, 0);
+
+	if (cam->cmd_queue & COMMAND_SETFORMAT) {
+		do_command(cam, CPIA_COMMAND_SetFormat,
+	        	   cam->params.format.videoSize,
+	        	   cam->params.format.subSample,
+	        	   cam->params.format.yuvOrder, 0);
+		do_command(cam, CPIA_COMMAND_SetROI,
+	        	   cam->params.roi.colStart, cam->params.roi.colEnd,
+	        	   cam->params.roi.rowStart, cam->params.roi.rowEnd);
+		cam->first_frame = 1;
+	}
+
+	if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
+		do_command(cam, CPIA_COMMAND_SetCompressionTarget,
+		           cam->params.compressionTarget.frTargeting,
+		           cam->params.compressionTarget.targetFR,
+		           cam->params.compressionTarget.targetQ, 0);
+
+	if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
+		do_command(cam, CPIA_COMMAND_SetYUVThresh,
+		           cam->params.yuvThreshold.yThreshold,
+		           cam->params.yuvThreshold.uvThreshold, 0, 0);
+
+	if (cam->cmd_queue & COMMAND_SETECPTIMING)
+		do_command(cam, CPIA_COMMAND_SetECPTiming,
+		           cam->params.ecpTiming, 0, 0, 0);
+
+	if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
+		do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
+		            0, 0, 0, 0,
+		            cam->params.compressionParams.hysteresis,
+		            cam->params.compressionParams.threshMax,
+		            cam->params.compressionParams.smallStep,
+		            cam->params.compressionParams.largeStep,
+		            cam->params.compressionParams.decimationHysteresis,
+		            cam->params.compressionParams.frDiffStepThresh,
+		            cam->params.compressionParams.qDiffStepThresh,
+		            cam->params.compressionParams.decimationThreshMod);
+
+	if (cam->cmd_queue & COMMAND_SETEXPOSURE)
+		do_command_extended(cam, CPIA_COMMAND_SetExposure,
+		                    cam->params.exposure.gainMode,
+		                    cam->params.exposure.expMode,
+		                    cam->params.exposure.compMode,
+		                    cam->params.exposure.centreWeight,
+		                    cam->params.exposure.gain,
+		                    cam->params.exposure.fineExp,
+		                    cam->params.exposure.coarseExpLo,
+		                    cam->params.exposure.coarseExpHi,
+		                    cam->params.exposure.redComp,
+		                    cam->params.exposure.green1Comp,
+		                    cam->params.exposure.green2Comp,
+		                    cam->params.exposure.blueComp);
+
+	if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
+		if (cam->params.colourBalance.balanceModeIsAuto) {
+			do_command(cam, CPIA_COMMAND_SetColourBalance,
+				   2, 0, 0, 0);
+		} else {
+			do_command(cam, CPIA_COMMAND_SetColourBalance,
+				   1,
+				   cam->params.colourBalance.redGain,
+				   cam->params.colourBalance.greenGain,
+				   cam->params.colourBalance.blueGain);
+			do_command(cam, CPIA_COMMAND_SetColourBalance,
+				   3, 0, 0, 0);
+		}
+	}
+
+	if (cam->cmd_queue & COMMAND_SETSENSORFPS)
+		do_command(cam, CPIA_COMMAND_SetSensorFPS,
+		           cam->params.sensorFps.divisor,
+		           cam->params.sensorFps.baserate, 0, 0);
+
+	if (cam->cmd_queue & COMMAND_SETAPCOR)
+		do_command(cam, CPIA_COMMAND_SetApcor,
+		           cam->params.apcor.gain1,
+		           cam->params.apcor.gain2,
+		           cam->params.apcor.gain4,
+		           cam->params.apcor.gain8);
+
+	if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
+		do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
+		           cam->params.flickerControl.flickerMode,
+		           cam->params.flickerControl.coarseJump,
+		           cam->params.flickerControl.allowableOverExposure, 0);
+
+	if (cam->cmd_queue & COMMAND_SETVLOFFSET)
+		do_command(cam, CPIA_COMMAND_SetVLOffset,
+		           cam->params.vlOffset.gain1,
+		           cam->params.vlOffset.gain2,
+		           cam->params.vlOffset.gain4,
+		           cam->params.vlOffset.gain8);
+
+	if (cam->cmd_queue & COMMAND_PAUSE)
+		do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
+
+	if (cam->cmd_queue & COMMAND_RESUME)
+		init_stream_cap(cam);
+
+	up(&cam->param_lock);
+	cam->cmd_queue = COMMAND_NONE;
+	return;
+}
+
+/* kernel thread function to read image from camera */
+static void fetch_frame(void *data)
+{
+	int image_size, retry;
+	struct cam_data *cam = (struct cam_data *)data;
+	unsigned long oldjif, rate, diff;
+
+	/* Allow up to two bad images in a row to be read and
+	 * ignored before an error is reported */
+	for (retry = 0; retry < 3; ++retry) {
+		if (retry)
+			DBG("retry=%d\n", retry);
+
+		if (!cam->ops)
+			continue;
+
+		/* load first frame always uncompressed */
+		if (cam->first_frame &&
+		    cam->params.compression.mode != CPIA_COMPRESSION_NONE)
+			do_command(cam, CPIA_COMMAND_SetCompression,
+				   CPIA_COMPRESSION_NONE,
+				   NO_DECIMATION, 0, 0);
+
+		/* init camera upload */
+		if (do_command(cam, CPIA_COMMAND_SetGrabMode,
+			       CPIA_GRAB_CONTINUOUS, 0, 0, 0))
+			continue;
+
+		if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
+			       cam->params.streamStartLine, 0, 0))
+			continue;
+
+		if (cam->ops->wait_for_stream_ready) {
+			/* loop until image ready */
+			do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
+			while (cam->params.status.streamState != STREAM_READY) {
+				if (current->need_resched)
+					schedule();
+
+				current->state = TASK_INTERRUPTIBLE;
+
+				/* sleep for 10 ms, hopefully ;) */
+				schedule_timeout(10*HZ/1000);
+				if (signal_pending(current))
+					return;
+
+				do_command(cam, CPIA_COMMAND_GetCameraStatus,
+				           0, 0, 0, 0);
+			}
+		}
+
+		/* grab image from camera */
+		if (current->need_resched)
+			schedule();
+
+		oldjif = jiffies;
+		image_size = cam->ops->streamRead(cam->lowlevel_data,
+						  cam->raw_image, 0);
+		if (image_size <= 0) {
+			DBG("streamRead failed: %d\n", image_size);
+			continue;
+		}
+
+		rate = image_size * HZ / 1024;
+		diff = jiffies-oldjif;
+		cam->transfer_rate = diff==0 ? rate : rate/diff;
+			/* diff==0 ? unlikely but possible */
+
+		/* camera idle now so dispatch queued commands */
+		dispatch_commands(cam);
+
+		/* Update our knowledge of the camera state - FIXME: necessary? */
+		do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+		do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+
+		/* decompress and convert image to by copying it from
+		 * raw_image to decompressed_frame
+		 */
+		if (current->need_resched)
+			schedule();
+
+		cam->image_size = parse_picture(cam, image_size);
+		if (cam->image_size <= 0)
+			DBG("parse_picture failed %d\n", cam->image_size);
+		else
+			break;
+	}
+
+	if (retry < 3) {
+		/* FIXME: this only works for double buffering */
+		if (cam->frame[cam->curframe].state == FRAME_READY) {
+			memcpy(cam->frame[cam->curframe].data,
+			       cam->decompressed_frame.data,
+			       cam->decompressed_frame.count);
+			cam->frame[cam->curframe].state = FRAME_DONE;
+		} else
+			cam->decompressed_frame.state = FRAME_DONE;
+
+#if 0
+		if (cam->first_frame &&
+		    cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
+			cam->first_frame = 0;
+			cam->cmd_queue |= COMMAND_SETCOMPRESSION;
+		}
+#else
+		if (cam->first_frame) {
+			cam->first_frame = 0;
+			cam->cmd_queue |= COMMAND_SETCOMPRESSION;
+			cam->cmd_queue |= COMMAND_SETEXPOSURE;
+		}
+#endif
+	}
+}
+
+static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
+{
+	int retval = 0;
+
+	if (!cam->frame_buf) {
+		/* we do lazy allocation */
+		if ((retval = allocate_frame_buf(cam)))
+			return retval;
+	}
+	
+	/* FIXME: the first frame seems to be captured by the camera
+	   without regards to any initial settings, so we throw away
+	   that one, the next one is generated with our settings
+	   (exposure, color balance, ...)
+	*/
+	if (cam->first_frame) {
+		cam->curframe = vm->frame;
+		cam->frame[cam->curframe].state = FRAME_READY;
+		fetch_frame(cam);
+		if (cam->frame[cam->curframe].state != FRAME_DONE)
+			retval = -EIO;
+	}
+	cam->curframe = vm->frame;
+	cam->frame[cam->curframe].state = FRAME_READY;
+	fetch_frame(cam);
+	if (cam->frame[cam->curframe].state != FRAME_DONE)
+		retval=-EIO;
+
+	return retval;
+}
+  
+static int goto_high_power(struct cam_data *cam)
+{
+	if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
+		return -1;
+	mdelay(100);		/* windows driver does it too */
+	if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+		return -1;
+	if (cam->params.status.systemState == HI_POWER_STATE) {
+		DBG("camera now in HIGH power state\n");
+		return 0;
+	}
+	printstatus(cam);
+	return -1;
+}
+
+static int goto_low_power(struct cam_data *cam)
+{
+	if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
+		return -1;
+	if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+		return -1;
+	if (cam->params.status.systemState == LO_POWER_STATE) {
+		DBG("camera now in LOW power state\n");
+		return 0;
+	}
+	printstatus(cam);
+	return -1;
+}
+
+static void save_camera_state(struct cam_data *cam)
+{
+	do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+	do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+
+	DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
+	     cam->params.exposure.gain,
+	     cam->params.exposure.fineExp,
+	     cam->params.exposure.coarseExpLo,
+	     cam->params.exposure.coarseExpHi,
+	     cam->params.exposure.redComp,
+	     cam->params.exposure.green1Comp,
+	     cam->params.exposure.green2Comp,
+	     cam->params.exposure.blueComp);
+	DBG("%d/%d/%d\n",
+	     cam->params.colourBalance.redGain,
+	     cam->params.colourBalance.greenGain,
+	     cam->params.colourBalance.blueGain);
+}
+
+static void set_camera_state(struct cam_data *cam)
+{
+	if(cam->params.colourBalance.balanceModeIsAuto) {
+		do_command(cam, CPIA_COMMAND_SetColourBalance, 
+	        	   2, 0, 0, 0);
+	} else {
+		do_command(cam, CPIA_COMMAND_SetColourBalance, 
+	        	   1,
+	        	   cam->params.colourBalance.redGain,
+	        	   cam->params.colourBalance.greenGain,
+	        	   cam->params.colourBalance.blueGain);
+		do_command(cam, CPIA_COMMAND_SetColourBalance, 
+	        	   3, 0, 0, 0);
+	}
+
+
+	do_command_extended(cam, CPIA_COMMAND_SetExposure,
+			    cam->params.exposure.gainMode, 1, 1,
+			    cam->params.exposure.centreWeight,
+	                    cam->params.exposure.gain,
+	                    cam->params.exposure.fineExp,
+	                    cam->params.exposure.coarseExpLo,
+	                    cam->params.exposure.coarseExpHi,
+			    cam->params.exposure.redComp,
+			    cam->params.exposure.green1Comp,
+			    cam->params.exposure.green2Comp,
+			    cam->params.exposure.blueComp);
+	do_command_extended(cam, CPIA_COMMAND_SetExposure,
+			    0, 3, 0, 0,
+			    0, 0, 0, 0, 0, 0, 0, 0);
+
+	if (!cam->params.exposure.gainMode)
+		cam->params.exposure.gainMode = 2;
+	if (!cam->params.exposure.expMode)
+		cam->params.exposure.expMode = 2;
+	if (!cam->params.exposure.centreWeight)
+		cam->params.exposure.centreWeight = 1;
+	
+	cam->cmd_queue = COMMAND_SETCOMPRESSION |
+	                 COMMAND_SETCOMPRESSIONTARGET |
+	                 COMMAND_SETCOLOURPARAMS |
+	                 COMMAND_SETFORMAT |
+	                 COMMAND_SETYUVTHRESH |
+	                 COMMAND_SETECPTIMING |
+	                 COMMAND_SETCOMPRESSIONPARAMS |
+#if 0
+	                 COMMAND_SETEXPOSURE |
+#endif
+	                 COMMAND_SETCOLOURBALANCE |
+	                 COMMAND_SETSENSORFPS |
+	                 COMMAND_SETAPCOR |
+	                 COMMAND_SETFLICKERCTRL |
+	                 COMMAND_SETVLOFFSET;
+	dispatch_commands(cam);
+	save_camera_state(cam);
+
+	return;
+}
+
+static void get_version_information(struct cam_data *cam)
+{
+	/* GetCPIAVersion */
+	do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
+
+	/* GetPnPID */
+	do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
+}
+
+/* initialize camera */
+static int reset_camera(struct cam_data *cam)
+{
+	/* Start the camera in low power mode */
+	if (goto_low_power(cam)) {
+		if (cam->params.status.systemState != WARM_BOOT_STATE)
+			return -ENODEV;
+
+		/* FIXME: this is just dirty trial and error */
+		reset_camera_struct(cam);
+		goto_high_power(cam);
+		do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
+		if (goto_low_power(cam))
+			return -NODEV;
+	}
+	
+	/* procedure described in developer's guide p3-28 */
+	
+	/* Check the firmware version FIXME: should we check PNPID? */
+	cam->params.version.firmwareVersion = 0;
+	get_version_information(cam);
+	if (cam->params.version.firmwareVersion != 1)
+		return -ENODEV;
+	
+	/* The fatal error checking should be done after
+	 * the camera powers up (developer's guide p 3-38) */
+
+	/* Set streamState before transition to high power to avoid bug
+	 * in firmware 1-02 */
+	do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
+	           STREAM_NOT_READY, 0);
+	
+	/* GotoHiPower */
+	if (goto_high_power(cam))
+		return -ENODEV;
+
+	/* Check the camera status */
+	if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+		return -EIO;
+
+	if (cam->params.status.fatalError) {
+		DBG("fatal_error:              %#04x\n",
+		    cam->params.status.fatalError);
+		DBG("vp_status:                %#04x\n",
+		    cam->params.status.vpStatus);
+		if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
+			/* Fatal error in camera */
+			return -EIO;
+		} else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
+			/* Firmware 1-02 may do this for parallel port cameras,
+			 * just clear the flags (developer's guide p 3-38) */
+			do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
+			           FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
+		}
+	}
+	
+	/* Check the camera status again */
+	if (cam->params.status.fatalError) {
+		if (cam->params.status.fatalError)
+			return -EIO;
+	}
+	
+	/* VPVersion can't be retrieved before the camera is in HiPower,
+	 * so get it here instead of in get_version_information. */
+	do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
+
+	/* set camera to a known state */
+	set_camera_state(cam);
+	
+	return 0;
+}
+
+/* ------------------------- V4L interface --------------------- */
+static int cpia_open(struct video_device *dev, int flags)
+{
+	int i;
+	struct cam_data *cam = dev->priv;
+
+	if (!cam) {
+		DBG("Internal error, cam_data not found!\n");
+		return -EBUSY;
+	}
+	    
+	if (cam->open_count > 0) {
+		DBG("Camera already open\n");
+		return -EBUSY;
+	}
+	
+	if (!cam->raw_image) {
+		cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
+		if (!cam->raw_image)
+			return -ENOMEM;
+	}
+
+	if (!cam->decompressed_frame.data) {
+		cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
+		if (!cam->decompressed_frame.data) {
+			rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+			cam->raw_image = NULL;
+			return -ENOMEM;
+		}
+	}
+	
+	/* open cpia */
+	if (cam->ops->open(cam->lowlevel_data)) {
+		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+		cam->decompressed_frame.data = NULL;
+		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+		cam->raw_image = NULL;
+		return -ENODEV;
+	}
+	
+	/* reset the camera */
+	if ((i = reset_camera(cam)) != 0) {
+		cam->ops->close(cam->lowlevel_data);
+		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+		cam->decompressed_frame.data = NULL;
+		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+		cam->raw_image = NULL;
+		return i;
+	}
+	
+	/* Set ownership of /proc/cpia/videoX to current user */
+	if(cam->proc_entry)
+		cam->proc_entry->uid = current->uid;
+
+	/* set mark for loading first frame uncompressed */
+	cam->first_frame = 1;
+
+	/* init it to something */
+	cam->mmap_kludge = 0;
+	
+	++cam->open_count;
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+	return 0;
+}
+
+static void cpia_close(struct video_device *dev)
+{
+	struct cam_data *cam;
+
+	cam = dev->priv;
+
+	if (cam->ops) {
+	        /* Return ownership of /proc/cpia/videoX to root */
+		if(cam->proc_entry)
+			cam->proc_entry->uid = 0;
+	
+		/* save camera state for later open (developers guide ch 3.5.3) */
+		save_camera_state(cam);
+
+		/* GotoLoPower */
+		goto_low_power(cam);
+
+		/* Update the camera ststus */
+		do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+
+		/* cleanup internal state stuff */
+		free_frames(cam->frame);
+
+		/* close cpia */
+		cam->ops->close(cam->lowlevel_data);
+	}
+
+	if (--cam->open_count == 0) {
+		/* clean up capture-buffers */
+		if (cam->raw_image) {
+			rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+			cam->raw_image = NULL;
+		}
+
+		if (cam->decompressed_frame.data) {
+			rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+			cam->decompressed_frame.data = NULL;
+		}
+
+		if (cam->frame_buf)
+			free_frame_buf(cam);
+
+		if (!cam->ops) {
+			video_unregister_device(dev);
+			kfree(cam);
+		}
+	}
+	
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return;
+}
+
+static long cpia_read(struct video_device *dev, char *buf,
+                      unsigned long count, int noblock)
+{
+	struct cam_data *cam = dev->priv;
+
+	/* make this _really_ smp and multithredi-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
+
+	if (!buf) {
+		DBG("buf NULL\n");
+		up(&cam->busy_lock);
+		return -EINVAL;
+	}
+
+	if (!count) {
+		DBG("count 0\n");
+		up(&cam->busy_lock);
+		return 0;
+	}
+
+	if (!cam->ops) {
+		DBG("ops NULL\n");
+		up(&cam->busy_lock);
+		return -ENODEV;
+	}
+
+	/* upload frame */
+	cam->decompressed_frame.state = FRAME_READY;
+	cam->mmap_kludge=0;
+	fetch_frame(cam);
+	if (cam->decompressed_frame.state != FRAME_DONE) {
+		DBG("upload failed %d/%d\n", cam->decompressed_frame.count,
+		    cam->decompressed_frame.state);
+		up(&cam->busy_lock);
+		return -EIO;
+	}
+	cam->decompressed_frame.state = FRAME_UNUSED;
+
+	/* copy data to user space */
+	if (cam->decompressed_frame.count > count) {
+		DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
+		    count);
+		up(&cam->busy_lock);
+		return -EFAULT;
+	}
+	if (copy_to_user(buf, cam->decompressed_frame.data,
+	                cam->decompressed_frame.count)) {
+		DBG("copy_to_user failed\n");
+		up(&cam->busy_lock);
+		return -EFAULT;
+	}
+
+	up(&cam->busy_lock);
+	return cam->decompressed_frame.count;
+}
+
+static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
+{
+	struct cam_data *cam = dev->priv;
+	int retval = 0;
+
+	if (!cam || !cam->ops)
+		return -ENODEV;
+	
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
+
+	//DBG("cpia_ioctl: %u\n", ioctlnr);
+
+	switch (ioctlnr) {
+	/* query capabilites */
+	case VIDIOCGCAP:
+	{
+		struct video_capability b;
+
+		DBG("VIDIOCGCAP\n");
+		strcpy(b.name, "CPiA Camera");
+		b.type = VID_TYPE_CAPTURE;
+		b.channels = 1;
+		b.audios = 0;
+		b.maxwidth = 352;	/* VIDEOSIZE_CIF */
+		b.maxheight = 288;
+		b.minwidth = 48;	/* VIDEOSIZE_48_48 */
+		b.minheight = 48;
+
+		if (copy_to_user(arg, &b, sizeof(b)))
+			retval = -EFAULT;
+
+		break;
+	}
+
+	/* get/set video source - we are a camera and nothing else */
+	case VIDIOCGCHAN:
+	{
+		struct video_channel v;
+
+		DBG("VIDIOCGCHAN\n");
+		if (copy_from_user(&v, arg, sizeof(v))) {
+			retval = -EFAULT;
+			break;
+		}
+		if (v.channel != 0) {
+			retval = -EINVAL;
+			break;
+		}
+
+		v.channel = 0;
+		strcpy(v.name, "Camera");
+		v.tuners = 0;
+		v.flags = 0;
+		v.type = VIDEO_TYPE_CAMERA;
+		v.norm = 0;
+
+		if (copy_to_user(arg, &v, sizeof(v)))
+			retval = -EFAULT;
+		break;
+	}
+	
+	case VIDIOCSCHAN:
+	{
+		int v;
+
+		DBG("VIDIOCSCHAN\n");
+		if (copy_from_user(&v, arg, sizeof(v)))
+			retval = -EFAULT;
+
+		if (retval == 0 && v != 0)
+			retval = -EINVAL;
+
+		break;
+	}
+
+	/* image properties */
+	case VIDIOCGPICT:
+		DBG("VIDIOCGPICT\n");
+		if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
+			retval = -EFAULT;
+		break;
+	
+	case VIDIOCSPICT:
+	{
+		struct video_picture vp;
+
+		DBG("VIDIOCSPICT\n");
+
+		/* copy_from_user */
+		if (copy_from_user(&vp, arg, sizeof(vp))) {
+			retval = -EFAULT;
+			break;
+		}
+
+		/* check validity */
+		DBG("palette: %d\n", vp.palette);
+		DBG("depth: %d\n", vp.depth);
+		if (!valid_mode(vp.palette, vp.depth)) {
+			retval = -EINVAL;
+			break;
+		}
+
+		down(&cam->param_lock);
+		/* brightness, colour, contrast need no check 0-65535 */
+		memcpy( &cam->vp, &vp, sizeof(vp) );
+		/* update cam->params.colourParams */
+		cam->params.colourParams.brightness = vp.brightness*100/65535;
+		cam->params.colourParams.contrast = vp.contrast*100/65535;
+		cam->params.colourParams.saturation = vp.colour*100/65535;
+		/* contrast is in steps of 8, so round */
+		cam->params.colourParams.contrast =
+			((cam->params.colourParams.contrast + 3) / 8) * 8;
+		if (cam->params.version.firmwareVersion == 1 &&
+		    cam->params.version.firmwareRevision == 2 &&
+		    cam->params.colourParams.contrast > 80) {
+			/* 1-02 firmware limits contrast to 80 */
+			cam->params.colourParams.contrast = 80;
+		}
+
+		/* queue command to update camera */
+		cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
+		up(&cam->param_lock);
+		DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
+		    vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour,
+		    vp.contrast);
+		break;
+	}
+
+	/* get/set capture window */
+	case VIDIOCGWIN:
+		DBG("VIDIOCGWIN\n");
+
+		if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
+			retval = -EFAULT;
+		break;
+	
+	case VIDIOCSWIN:
+	{
+		/* copy_from_user, check validity, copy to internal structure */
+		struct video_window vw;
+		DBG("VIDIOCSWIN\n");
+		if (copy_from_user(&vw, arg, sizeof(vw))) {
+			retval = -EFAULT;
+			break;
+		}
+
+		if (vw.clipcount != 0) {    /* clipping not supported */
+			retval = -EINVAL;
+			break;
+		}
+		if (vw.clips != NULL) {     /* clipping not supported */
+			retval = -EINVAL;
+			break;
+		}
+
+		/* we set the video window to something smaller or equal to what
+		* is requested by the user???
+		*/
+		down(&cam->param_lock);
+		if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
+			int video_size = match_videosize(vw.width, vw.height);
+
+			if (video_size < 0) {
+				retval = -EINVAL;
+				up(&cam->param_lock);
+				break;
+			}
+			cam->video_size = video_size;
+			set_vw_size(cam);
+			DBG("%d / %d\n", cam->vw.width, cam->vw.height);
+			cam->cmd_queue |= COMMAND_SETFORMAT;
+		}
+
+		// FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw));
+		up(&cam->param_lock);
+
+		/* setformat ignored by camera during streaming,
+		 * so stop/dispatch/start */
+		if (cam->cmd_queue & COMMAND_SETFORMAT) {
+			DBG("\n");
+			dispatch_commands(cam);
+		}
+		DBG("%d/%d:%d\n", cam->video_size,
+		    cam->vw.width, cam->vw.height);
+		break;
+	}
+
+	/* mmap interface */
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf vm;
+		int i;
+
+		DBG("VIDIOCGMBUF\n");
+		memset(&vm, 0, sizeof(vm));
+		vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
+		vm.frames = FRAME_NUM;
+		for (i = 0; i < FRAME_NUM; i++)
+			vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
+
+		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+			retval = -EFAULT;
+
+		break;
+	}
+	
+	case VIDIOCMCAPTURE:
+	{
+		struct video_mmap vm;
+		int video_size;
+
+		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
+			retval = -EFAULT;
+			break;
+		}
+#if 1
+		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
+		    vm.width, vm.height);
+#endif
+		if (vm.frame<0||vm.frame>FRAME_NUM) {
+			retval = -EINVAL;
+			break;
+		}
+
+		/* set video format */
+		cam->vp.palette = vm.format;
+		switch(vm.format) {
+		case VIDEO_PALETTE_GREY:
+		case VIDEO_PALETTE_RGB555:
+		case VIDEO_PALETTE_RGB565:
+		case VIDEO_PALETTE_YUV422:
+		case VIDEO_PALETTE_YUYV:
+		case VIDEO_PALETTE_UYVY:
+			cam->vp.depth = 16;
+			break;
+		case VIDEO_PALETTE_RGB24:
+			cam->vp.depth = 24;
+			break;
+		case VIDEO_PALETTE_RGB32:
+			cam->vp.depth = 32;
+			break;
+		default:
+			retval = -EINVAL;
+			break;
+		}
+		if (retval)
+			break;
+
+		/* set video size */
+		video_size = match_videosize(vm.width, vm.height);
+		if (cam->video_size < 0) {
+			retval = -EINVAL;
+			break;
+		}
+		if (video_size != cam->video_size) {
+			cam->video_size = video_size;
+			set_vw_size(cam);
+			cam->cmd_queue |= COMMAND_SETFORMAT;
+			dispatch_commands(cam);
+		}
+#if 0
+		DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
+		    cam->vw.width, cam->vw.height);
+#endif
+		/* according to v4l-spec we must start streaming here */
+		cam->mmap_kludge = 1;
+		retval = capture_frame(cam, &vm);
+
+		break;
+	}
+	
+	case VIDIOCSYNC:
+	{
+		int frame;
+
+		if (copy_from_user((void *)&frame, arg, sizeof(int))) {
+			retval = -EFAULT;
+			break;
+		}
+		//DBG("VIDIOCSYNC: %d\n", frame);
+
+		if (frame<0 || frame >= FRAME_NUM) {
+			retval = -EINVAL;
+			break;
+		}
+
+		switch (cam->frame[frame].state) {
+		case FRAME_UNUSED:
+		case FRAME_READY:
+		case FRAME_GRABBING:
+			DBG("sync to unused frame %d\n", frame);
+			retval = -EINVAL;
+			break;
+
+		case FRAME_DONE:
+			cam->frame[frame].state = FRAME_UNUSED;
+			//DBG("VIDIOCSYNC: %d synced\n", frame);
+			break;
+		}
+		if (retval == -EINTR) {
+			/* FIXME - xawtv does not handle this nice */
+			retval = 0;
+		}
+		break;
+	}
+
+	/* pointless to implement overlay with this camera */
+	case VIDIOCCAPTURE:
+		retval = -EINVAL;
+		break;
+	case VIDIOCGFBUF:
+		retval = -EINVAL;
+		break;
+	case VIDIOCSFBUF:
+		retval = -EINVAL;
+		break;
+	case VIDIOCKEY:
+		retval = -EINVAL;
+		break;
+
+	/* tuner interface - we have none */
+	case VIDIOCGTUNER:
+		retval = -EINVAL;
+		break;
+	case VIDIOCSTUNER:
+		retval = -EINVAL;
+		break;
+	case VIDIOCGFREQ:
+		retval = -EINVAL;
+		break;
+	case VIDIOCSFREQ:
+		retval = -EINVAL;
+		break;
+
+	/* audio interface - we have none */
+	case VIDIOCGAUDIO:
+		retval = -EINVAL;
+		break;
+	case VIDIOCSAUDIO:
+		retval = -EINVAL;
+		break;
+	default:
+		retval = -ENOIOCTLCMD;
+		break;
+	}
+
+	up(&cam->param_lock);
+	up(&cam->busy_lock);
+	return retval;
+} 
+
+/* FIXME */
+static int cpia_mmap(struct video_device *dev, const char *adr,
+                     unsigned long size)
+{
+	unsigned long start = (unsigned long)adr;
+	unsigned long page, pos;
+	struct cam_data *cam = dev->priv;
+	int retval;
+
+	if (!cam || !cam->ops)
+		return -ENODEV;
+	
+	DBG("cpia_mmap: %ld\n", size);
+
+	if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
+		return -EINVAL;
+
+	if (!cam || !cam->ops)
+		return -ENODEV;
+	
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
+
+	if (!cam->frame_buf) {	/* we do lazy allocation */
+		if ((retval = allocate_frame_buf(cam))) {
+			up(&cam->busy_lock);
+			return retval;
+		}
+	}
+
+	pos = (unsigned long)(cam->frame_buf);
+	while (size > 0) {
+		page = kvirt_to_pa(pos);
+		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+			up(&cam->busy_lock);
+			return -EAGAIN;
+		}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	DBG("cpia_mmap: %ld\n", size);
+	up(&cam->busy_lock);
+
+	return 0;
+}
+
+int cpia_video_init(struct video_device *vdev)
+{
+#ifdef CONFIG_PROC_FS
+	create_proc_cpia_cam(vdev->priv);
+#endif
+	return 0;
+}
+
+static struct video_device cpia_template = {
+	"CPiA Camera",
+	VID_TYPE_CAPTURE,
+	VID_HARDWARE_CPIA,      /* FIXME */
+	cpia_open,              /* open */
+	cpia_close,             /* close */
+	cpia_read,              /* read */
+	NULL,                   /* no write */
+	NULL,                   /* no poll */
+	cpia_ioctl,             /* ioctl */
+	cpia_mmap,              /* mmap */
+	cpia_video_init,        /* initialize */
+	NULL,                   /* priv */
+	0,                      /* busy */
+	-1                      /* minor - unset */
+};
+
+/* initialise cam_data structure  */
+static void reset_camera_struct(struct cam_data *cam)
+{
+	/* The following parameter values are the defaults from
+	 * "Software Developer's Guide for CPiA Cameras".  Any changes
+	 * to the defaults are noted in comments. */
+	cam->params.colourParams.brightness = 50;
+	cam->params.colourParams.contrast = 48;
+	cam->params.colourParams.saturation = 50;
+	cam->params.exposure.gainMode = 2;
+	cam->params.exposure.expMode = 2;		/* AEC */
+	cam->params.exposure.compMode = 1;
+	cam->params.exposure.centreWeight = 1;
+	cam->params.exposure.gain = 0;
+	cam->params.exposure.fineExp = 0;
+	cam->params.exposure.coarseExpLo = 185;
+	cam->params.exposure.coarseExpHi = 0;
+	cam->params.exposure.redComp = 220;
+	cam->params.exposure.green1Comp = 214;
+	cam->params.exposure.green2Comp = 214;
+	cam->params.exposure.blueComp = 230;
+	cam->params.colourBalance.balanceModeIsAuto = 1;
+	cam->params.colourBalance.redGain = 32;
+	cam->params.colourBalance.greenGain = 6;
+	cam->params.colourBalance.blueGain = 92;
+	cam->params.apcor.gain1 = 0x1c;
+	cam->params.apcor.gain2 = 0x1a;
+	cam->params.apcor.gain4 = 0x2d;
+	cam->params.apcor.gain8 = 0x2a;
+	cam->params.flickerControl.flickerMode = 0;
+	cam->params.flickerControl.coarseJump = 
+		flicker_jumps[cam->mainsFreq]
+		             [cam->params.sensorFps.baserate]
+		             [cam->params.sensorFps.divisor];
+	cam->params.vlOffset.gain1 = 24;
+	cam->params.vlOffset.gain2 = 28;
+	cam->params.vlOffset.gain4 = 30;
+	cam->params.vlOffset.gain8 = 30;
+	cam->params.compressionParams.hysteresis = 3;
+	cam->params.compressionParams.threshMax = 11;
+	cam->params.compressionParams.smallStep = 1;
+	cam->params.compressionParams.largeStep = 3;
+	cam->params.compressionParams.decimationHysteresis = 2;
+	cam->params.compressionParams.frDiffStepThresh = 5;
+	cam->params.compressionParams.qDiffStepThresh = 3;
+	cam->params.compressionParams.decimationThreshMod = 2;
+	/* End of default values from Software Developer's Guide */
+	
+	cam->transfer_rate = 0;
+	
+	/* Set Sensor FPS to 15fps. This seems better than 30fps
+	 * for indoor lighting. */
+	cam->params.sensorFps.divisor = 1;
+	cam->params.sensorFps.baserate = 1;
+	
+	cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
+	cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
+	
+	cam->params.format.subSample = SUBSAMPLE_422;
+	cam->params.format.yuvOrder = YUVORDER_YUYV;
+	
+	cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
+	cam->params.compressionTarget.frTargeting =
+		CPIA_COMPRESSION_TARGET_QUALITY;
+	cam->params.compressionTarget.targetFR = 7; /* FIXME? */
+	cam->params.compressionTarget.targetQ = 10; /* FIXME? */
+
+	cam->video_size = VIDEOSIZE_CIF;
+	
+	cam->vp.colour = 32768;      /* 50% */
+	cam->vp.hue = 32768;         /* 50% */
+	cam->vp.brightness = 32768;  /* 50% */
+	cam->vp.contrast = 32768;    /* 50% */
+	cam->vp.whiteness = 0;       /* not used -> grayscale only */
+	cam->vp.depth = 0;           /* FIXME: to be set by user? */
+	cam->vp.palette = VIDEO_PALETTE_RGB24;         /* FIXME: to be set by user? */
+
+	cam->vw.x = 0;
+	cam->vw.y = 0;
+	set_vw_size(cam);
+	cam->vw.chromakey = 0;
+	/* PP NOTE: my extension to use vw.flags for this, bear it! */
+	cam->vw.flags = 0;
+	cam->vw.clipcount = 0;
+	cam->vw.clips = NULL;
+
+	cam->cmd_queue = COMMAND_NONE;
+	cam->first_frame = 0;
+
+	return;
+}
+
+/* initialize cam_data structure  */
+static void init_camera_struct(struct cam_data *cam,
+                               struct cpia_camera_ops *ops )
+{
+	int i;
+
+	/* Default everything to 0 */
+	memset(cam, 0, sizeof(struct cam_data));
+
+	cam->ops = ops;
+	init_MUTEX(&cam->param_lock);
+	init_MUTEX(&cam->busy_lock);
+
+	reset_camera_struct(cam);
+
+	cam->proc_entry = NULL;
+
+	memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
+	cam->vdev.priv = cam;
+	
+	cam->curframe = 0;
+	for (i = 0; i < FRAME_NUM; i++) {
+		cam->frame[i].width = 0;
+		cam->frame[i].height = 0;
+		cam->frame[i].state = FRAME_UNUSED;
+		cam->frame[i].data = NULL;
+	}
+	cam->decompressed_frame.width = 0;
+	cam->decompressed_frame.height = 0;
+	cam->decompressed_frame.state = FRAME_UNUSED;
+	cam->decompressed_frame.data = NULL;
+}
+
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
+{
+        struct cam_data *camera;
+	
+	/* Need a lock when adding/removing cameras.  This doesn't happen
+	 * often and doesn't take very long, so grabbing the kernel lock
+	 * should be OK. */
+	
+	if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
+		unlock_kernel();
+		return NULL;
+	}
+	
+	init_camera_struct( camera, ops );
+	camera->lowlevel_data = lowlevel;
+	
+	/* register v4l device */
+	if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) {
+		kfree(camera);
+		unlock_kernel();
+		printk(KERN_DEBUG "video_register_device failed\n");
+		return NULL;
+	}
+
+	/* get version information from camera: open/reset/close */
+
+	/* open cpia */
+	if (camera->ops->open(camera->lowlevel_data))
+		return camera;
+	
+	/* reset the camera */
+	if (reset_camera(camera) != 0) {
+		camera->ops->close(camera->lowlevel_data);
+		return camera;
+	}
+
+	/* close cpia */
+	camera->ops->close(camera->lowlevel_data);
+
+/* Eh? Feeling happy? - jerdfelt */
+/*
+	camera->ops->open(camera->lowlevel_data);
+	camera->ops->close(camera->lowlevel_data);
+*/
+	
+	printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
+	       camera->params.version.firmwareVersion,
+	       camera->params.version.firmwareRevision,
+	       camera->params.version.vcVersion,
+	       camera->params.version.vcRevision);
+	printk(KERN_INFO "  CPiA PnP-ID: %04x:%04x:%04x\n",
+	       camera->params.pnpID.vendor,
+	       camera->params.pnpID.product,
+	       camera->params.pnpID.deviceRevision);
+	printk(KERN_INFO "  VP-Version: %d.%d %04x\n",
+	       camera->params.vpVersion.vpVersion,
+	       camera->params.vpVersion.vpRevision,
+	       camera->params.vpVersion.cameraHeadID);
+
+	return camera;
+}
+
+void cpia_unregister_camera(struct cam_data *cam)
+{
+	if (!cam->open_count) {
+		DBG("unregistering video\n");
+		video_unregister_device(&cam->vdev);
+	} else {
+		LOG("/dev/video%d removed while open, "
+		    "deferring video_unregister_device\n", cam->vdev.minor);
+		DBG("camera open -- setting ops to NULL\n");
+		cam->ops = NULL;
+	}
+	
+#ifdef CONFIG_PROC_FS
+	DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
+	destroy_proc_cpia_cam(cam);
+#endif	
+	if (!cam->open_count) {
+		DBG("freeing camera\n");
+		kfree(cam);
+	}
+}
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
+#ifdef MODULE
+int init_module(void)
+{
+	printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
+	       CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+#ifdef CONFIG_PROC_FS
+	proc_cpia_create();
+#endif
+#ifdef CONFIG_KMOD
+#ifdef CONFIG_VIDEO_CPIA_PP_MODULE
+	request_module("cpia_pp");
+#endif
+#ifdef CONFIG_VIDEO_CPIA_USB_MODULE
+	request_module("cpia_usb");
+#endif
+#endif
+return 0;
+}
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_PROC_FS
+	proc_cpia_destroy();
+#endif
+}
+
+#else
+
+int cpia_init(struct video_init *unused)
+{
+	printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
+	       CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+#ifdef CONFIG_PROC_FS
+	proc_cpia_create();
+#endif
+
+#ifdef CONFIG_VIDEO_CPIA_PP
+	cpia_pp_init();
+#endif
+#ifdef CONFIG_KMOD
+#ifdef CONFIG_VIDEO_CPIA_PP_MODULE
+	request_module("cpia_pp");
+#endif
+
+#ifdef CONFIG_VIDEO_CPIA_USB_MODULE
+	request_module("cpia_usb");
+#endif
+#endif	/* CONFIG_KMOD */
+#ifdef CONFIG_VIDEO_CPIA_USB
+	cpia_usb_init();
+#endif
+	return 0;
+}
+
+/* Exported symbols for modules. */
+
+EXPORT_SYMBOL(cpia_register_camera);
+EXPORT_SYMBOL(cpia_unregister_camera);
+
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/cpia.h linux/drivers/char/cpia.h
--- v2.3.99-pre3/linux/drivers/char/cpia.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/cpia.h	Mon Mar 27 10:22:31 2000
@@ -0,0 +1,421 @@
+#ifndef cpia_h
+#define cpia_h
+
+/*
+ * CPiA Parallel Port Video4Linux driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * (C) Copyright 1999 Bas Huisman,
+ *                    Peter Pregler,
+ *                    Scott J. Bertin,
+ *                    VLSI Vision Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define CPIA_MAJ_VER	0
+#define CPIA_MIN_VER    7
+#define CPIA_PATCH_VER	4
+
+#define CPIA_PP_MAJ_VER       0
+#define CPIA_PP_MIN_VER       7
+#define CPIA_PP_PATCH_VER     4
+
+#define CPIA_MAX_FRAME_SIZE_UNALIGNED	(352 * 288 * 4)   /* CIF at RGB32 */
+#define CPIA_MAX_FRAME_SIZE	((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
+
+#ifdef __KERNEL__
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+
+struct cpia_camera_ops
+{
+	/* open sets privdata to point to structure for this camera.
+         * Returns negative value on error, otherwise 0.
+	 */
+	int (*open)(void *privdata);
+	
+	/* Registers callback function cb to be called with cbdata
+	 * when an image is ready.  If cb is NULL, only single image grabs
+	 * should be used.  cb should immediately call streamRead to read
+	 * the data or data may be lost. Returns negative value on error,
+	 * otherwise 0.
+	 */
+	int (*registerCallback)(void *privdata, void (*cb)(void *cbdata),
+	                        void *cbdata);
+	
+	/* transferCmd sends commands to the camera.  command MUST point to
+	 * an  8 byte buffer in kernel space. data can be NULL if no extra
+	 * data is needed.  The size of the data is given by the last 2
+	 * bytes of comand.  data must also point to memory in kernel space.
+	 * Returns negative value on error, otherwise 0.
+	 */
+	int (*transferCmd)(void *privdata, u8 *command, u8 *data);
+
+	/* streamStart initiates stream capture mode.
+	 * Returns negative value on error, otherwise 0.
+	 */
+	int (*streamStart)(void *privdata);
+	
+	/* streamStop terminates stream capture mode.
+	 * Returns negative value on error, otherwise 0.
+	 */
+	int (*streamStop)(void *privdata);
+        
+	/* streamRead reads a frame from the camera.  buffer points to a
+         * buffer large enough to hold a complete frame in kernel space.
+         * noblock indicates if this should be a non blocking read.
+	 * Returns the number of bytes read, or negative value on error.
+         */
+	int (*streamRead)(void *privdata, u8 *buffer, int noblock);
+	
+	/* close disables the device until open() is called again.
+	 * Returns negative value on error, otherwise 0.
+	 */
+	int (*close)(void *privdata);
+	
+	/* If wait_for_stream_ready is non-zero, wait until the streamState
+	 * is STREAM_READY before calling streamRead.
+	 */
+	int wait_for_stream_ready;
+};
+
+struct cpia_frame {
+	u8 *data;
+	int count;
+	int width;
+	int height;
+	volatile int state;
+};
+
+struct cam_params {
+	struct {
+		u8 firmwareVersion;
+		u8 firmwareRevision;
+		u8 vcVersion;
+		u8 vcRevision;
+	} version;
+	struct {
+		u16 vendor;
+		u16 product;
+		u16 deviceRevision;
+	} pnpID;
+	struct {
+		u8 vpVersion;
+		u8 vpRevision;
+		u16 cameraHeadID;
+	} vpVersion;
+	struct {
+		u8 systemState;
+		u8 grabState;
+		u8 streamState;
+		u8 fatalError;
+		u8 cmdError;
+		u8 debugFlags;
+		u8 vpStatus;
+		u8 errorCode;
+	} status;
+	struct {
+		u8 brightness;
+		u8 contrast;
+		u8 saturation;
+	} colourParams;
+	struct {
+		u8 gainMode;
+		u8 expMode;
+		u8 compMode;
+		u8 centreWeight;
+		u8 gain;
+		u8 fineExp;
+		u8 coarseExpLo;
+		u8 coarseExpHi;
+		u8 redComp;
+		u8 green1Comp;
+		u8 green2Comp;
+		u8 blueComp;
+	} exposure;
+	struct {
+		u8 balanceModeIsAuto;
+		u8 redGain;
+		u8 greenGain;
+		u8 blueGain;
+	} colourBalance;
+	struct {
+		u8 divisor;
+		u8 baserate;
+	} sensorFps;
+	struct {
+		u8 gain1;
+		u8 gain2;
+		u8 gain4;
+		u8 gain8;
+	} apcor;
+	struct {
+		u8 flickerMode;
+		u8 coarseJump;
+		u8 allowableOverExposure;
+	} flickerControl;
+	struct {
+		u8 gain1;
+		u8 gain2;
+		u8 gain4;
+		u8 gain8;
+	} vlOffset;
+	struct {
+		u8 mode;
+		u8 decimation;
+	} compression;
+	struct {
+		u8 frTargeting;
+		u8 targetFR;
+		u8 targetQ;
+	} compressionTarget;
+	struct {
+		u8 yThreshold;
+		u8 uvThreshold;
+	} yuvThreshold;
+	struct {
+		u8 hysteresis;
+		u8 threshMax;
+		u8 smallStep;
+		u8 largeStep;
+		u8 decimationHysteresis;
+		u8 frDiffStepThresh;
+		u8 qDiffStepThresh;
+		u8 decimationThreshMod;
+	} compressionParams;
+	struct {
+		u8 videoSize;		/* CIF/QCIF */
+		u8 subSample;
+		u8 yuvOrder;
+	} format;
+	struct {
+		u8 colStart;		/* skip first 8*colStart pixels */
+		u8 colEnd;		/* finish at 8*colEnd pixels */
+		u8 rowStart;		/* skip first 4*rowStart lines */
+		u8 rowEnd;		/* finish at 4*rowEnd lines */
+	} roi;
+	u8 ecpTiming;
+	u8 streamStartLine;
+};
+
+enum v4l_camstates {
+	CPIA_V4L_IDLE = 0,
+	CPIA_V4L_ERROR,
+	CPIA_V4L_COMMAND,
+	CPIA_V4L_GRABBING,
+	CPIA_V4L_STREAMING,
+	CPIA_V4L_STREAMING_PAUSED,
+};
+
+#define FRAME_NUM	2	/* double buffering for now */
+
+struct cam_data {
+	struct cam_data **previous;
+	struct cam_data *next;
+
+        struct semaphore busy_lock;     /* guard against SMP multithreading */
+	struct cpia_camera_ops *ops;	/* lowlevel driver operations */
+	void *lowlevel_data;		/* private data for lowlevel driver */
+	u8 *raw_image;			/* buffer for raw image data */
+	struct cpia_frame decompressed_frame;
+                                        /* buffer to hold decompressed frame */
+	int image_size;		        /* sizeof last decompressed image */
+	int open_count;			/* # of process that have camera open */
+
+				/* camera status */
+	int fps;			/* actual fps reported by the camera */
+	int transfer_rate;		/* transfer rate from camera in kB/s */
+	u8 mainsFreq;			/* for flicker control */
+
+				/* proc interface */
+	struct semaphore param_lock;	/* params lock for this camera */
+	struct cam_params params;	/* camera settings */
+	struct proc_dir_entry *proc_entry;	/* /proc/cpia/videoX */
+	
+					/* v4l */
+	int video_size;			/* VIDEO_SIZE_ */
+	volatile enum v4l_camstates camstate;	/* v4l layer status */
+	struct video_device vdev;	/* v4l videodev */
+	struct video_picture vp;	/* v4l camera settings */
+	struct video_window vw;		/* v4l capture area */
+
+				/* mmap interface */
+	int curframe;			/* the current frame to grab into */
+	u8 *frame_buf;			/* frame buffer data */
+        struct cpia_frame frame[FRAME_NUM];
+				/* FRAME_NUM-buffering, so we need a array */
+
+	int first_frame;
+	int mmap_kludge;		/* 'wrong' byte order for mmap */
+	volatile u32 cmd_queue;		/* queued commands */
+};
+
+/* cpia_register_camera is called by low level driver for each camera.
+ * A unique camera number is returned, or a negative value on error */
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel);
+
+/* cpia_unregister_camera is called by low level driver when a camera
+ * is removed.  This must not fail. */
+void cpia_unregister_camera(struct cam_data *cam);
+
+/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI +
+ * one byte 16bit DMA alignment
+ */
+#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5)
+
+/* constant value's */
+#define MAGIC_0		0x19
+#define MAGIC_1		0x68
+#define DATA_IN		0xC0
+#define DATA_OUT	0x40
+#define VIDEOSIZE_QCIF	0	/* 176x144 */
+#define VIDEOSIZE_CIF	1	/* 352x288 */
+#define VIDEOSIZE_SIF	2	/* 320x240 */
+#define VIDEOSIZE_QSIF	3	/* 160x120 */
+#define VIDEOSIZE_48_48		4 /* where no one has gone before, iconsize! */
+#define VIDEOSIZE_64_48		5
+#define VIDEOSIZE_128_96	6
+#define VIDEOSIZE_160_120	VIDEOSIZE_QSIF
+#define VIDEOSIZE_176_144	VIDEOSIZE_QCIF
+#define VIDEOSIZE_192_144	7
+#define VIDEOSIZE_224_168	8
+#define VIDEOSIZE_256_192	9
+#define VIDEOSIZE_288_216	10
+#define VIDEOSIZE_320_240	VIDEOSIZE_SIF
+#define VIDEOSIZE_352_288	VIDEOSIZE_CIF
+#define VIDEOSIZE_88_72		11 /* quarter CIF */
+#define SUBSAMPLE_420	0
+#define SUBSAMPLE_422	1
+#define YUVORDER_YUYV	0
+#define YUVORDER_UYVY	1
+#define NOT_COMPRESSED	0
+#define COMPRESSED	1
+#define NO_DECIMATION	0
+#define DECIMATION_ENAB	1
+#define EOI		0xff	/* End Of Image */
+#define EOL		0xfd	/* End Of Line */
+#define FRAME_HEADER_SIZE	64
+
+/* Image grab modes */
+#define CPIA_GRAB_SINGLE	0
+#define CPIA_GRAB_CONTINUOUS	1
+
+/* Compression parameters */
+#define CPIA_COMPRESSION_NONE	0
+#define CPIA_COMPRESSION_AUTO	1
+#define CPIA_COMPRESSION_MANUAL	2
+#define CPIA_COMPRESSION_TARGET_QUALITY         0
+#define CPIA_COMPRESSION_TARGET_FRAMERATE       1
+
+/* Return offsets for GetCameraState */
+#define SYSTEMSTATE	0
+#define GRABSTATE	1
+#define STREAMSTATE	2
+#define FATALERROR	3
+#define CMDERROR	4
+#define DEBUGFLAGS	5
+#define VPSTATUS	6
+#define ERRORCODE	7
+
+/* SystemState */
+#define UNINITIALISED_STATE	0
+#define PASS_THROUGH_STATE	1
+#define LO_POWER_STATE		2
+#define HI_POWER_STATE		3
+#define WARM_BOOT_STATE		4
+
+/* GrabState */
+#define GRAB_IDLE		0
+#define GRAB_ACTIVE		1
+#define GRAB_DONE		2
+
+/* StreamState */
+#define STREAM_NOT_READY	0
+#define STREAM_READY		1
+#define STREAM_OPEN		2
+#define STREAM_PAUSED		3
+#define STREAM_FINISHED		4
+
+/* Fatal Error, CmdError, and DebugFlags */
+#define CPIA_FLAG	  1
+#define SYSTEM_FLAG	  2
+#define INT_CTRL_FLAG	  4
+#define PROCESS_FLAG	  8
+#define COM_FLAG	 16
+#define VP_CTRL_FLAG	 32
+#define CAPTURE_FLAG	 64
+#define DEBUG_FLAG	128
+
+/* VPStatus */
+#define VP_STATE_OK			0x00
+
+#define VP_STATE_FAILED_VIDEOINIT	0x01
+#define VP_STATE_FAILED_AECACBINIT	0x02
+#define VP_STATE_AEC_MAX		0x04
+#define VP_STATE_ACB_BMAX		0x08
+
+#define VP_STATE_ACB_RMIN		0x10
+#define VP_STATE_ACB_GMIN		0x20
+#define VP_STATE_ACB_RMAX		0x40
+#define VP_STATE_ACB_GMAX		0x80
+
+/* ErrorCode */
+#define ERROR_FLICKER_BELOW_MIN_EXP     0x01 /*flicker exposure got below minimum exposure */
+
+#define ALOG(lineno,fmt,args...) printk(fmt,lineno,##args)
+#define LOG(fmt,args...) ALOG((__LINE__),KERN_INFO __FILE__":"__FUNCTION__"(%d):"fmt,##args)
+
+#ifdef _CPIA_DEBUG_
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args)
+#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):"__FUNCTION__"(%d):"fmt,##args)
+#else
+#define DBG(fmn,args...) do {} while(0)
+#endif
+
+#define DEB_BYTE(p)\
+  DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
+      (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
+        (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
+
+#define ADD_TO_LIST(l, drv) \
+  {\
+    lock_kernel();\
+    (drv)->next = l;\
+    (drv)->previous = &(l);\
+    (l) = drv;\
+    unlock_kernel();\
+  } while(0)
+
+#define REMOVE_FROM_LIST(drv) \
+  {\
+    if ((drv)->previous != NULL) {\
+      lock_kernel();\
+      if ((drv)->next != NULL)\
+        (drv)->next->previous = (drv)->previous;\
+      *((drv)->previous) = (drv)->next;\
+      (drv)->previous = NULL;\
+      (drv)->next = NULL;\
+      unlock_kernel();\
+    }\
+  } while (0)
+
+
+#endif /* __KERNEL__ */
+
+#endif /* cpia_h */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/cpia_pp.c linux/drivers/char/cpia_pp.c
--- v2.3.99-pre3/linux/drivers/char/cpia_pp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/cpia_pp.c	Mon Mar 27 10:22:31 2000
@@ -0,0 +1,745 @@
+/*
+ * cpia_pp CPiA Parallel Port driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl>
+ * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@mindspring.com>,
+ * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+/* #define _CPIA_DEBUG_		define for verbose debug output */
+#include "cpia.h"
+
+static int cpia_pp_open(void *privdata);
+static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata),
+                                    void *cbdata);
+static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data);
+static int cpia_pp_streamStart(void *privdata);
+static int cpia_pp_streamStop(void *privdata);
+static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock);
+static int cpia_pp_close(void *privdata);
+
+#define ABOUT "Parallel port driver for Vision CPiA based cameras"
+
+/* IEEE 1284 Compatiblity Mode signal names 	*/
+#define nStrobe		PARPORT_CONTROL_STROBE	  /* inverted */
+#define nAutoFd		PARPORT_CONTROL_AUTOFD	  /* inverted */
+#define nInit		PARPORT_CONTROL_INIT
+#define nSelectIn	PARPORT_CONTROL_SELECT
+#define IntrEnable	PARPORT_CONTROL_INTEN	  /* normally zero for no IRQ */
+#define DirBit		PARPORT_CONTROL_DIRECTION /* 0 = Forward, 1 = Reverse	*/
+
+#define nFault		PARPORT_STATUS_ERROR
+#define Select		PARPORT_STATUS_SELECT
+#define PError		PARPORT_STATUS_PAPEROUT
+#define nAck		PARPORT_STATUS_ACK
+#define Busy		PARPORT_STATUS_BUSY	  /* inverted */	
+
+/* some more */
+#define HostClk		nStrobe
+#define HostAck		nAutoFd
+#define nReverseRequest	nInit
+#define Active_1284	nSelectIn
+#define nPeriphRequest	nFault
+#define XFlag		Select
+#define nAckReverse	PError
+#define PeriphClk	nAck
+#define PeriphAck	Busy
+
+/* these can be used to correct for the inversion on some bits */
+#define STATUS_INVERSION_MASK	(Busy)
+#define CONTROL_INVERSION_MASK	(nStrobe|nAutoFd|nSelectIn)
+
+#define ECR_empty	0x01
+#define ECR_full	0x02
+#define ECR_serviceIntr 0x04
+#define ECR_dmaEn	0x08
+#define ECR_nErrIntrEn	0x10
+
+#define ECR_mode_mask	0xE0
+#define ECR_SPP_mode	0x00
+#define ECR_PS2_mode	0x20
+#define ECR_FIFO_mode	0x40
+#define ECR_ECP_mode	0x60
+
+#define ECP_FIFO_SIZE	16
+#define DMA_BUFFER_SIZE               PAGE_SIZE
+	/* for 16bit DMA make sure DMA_BUFFER_SIZE is 16 bit aligned */
+#define PARPORT_CHUNK_SIZE	PAGE_SIZE/* >=2.3.x */
+				/* we read this many bytes at once */
+
+#define GetECRMasked(port,mask)	(parport_read_econtrol(port) & (mask))
+#define GetStatus(port)		((parport_read_status(port)^STATUS_INVERSION_MASK)&(0xf8))
+#define SetStatus(port,val)	parport_write_status(port,(val)^STATUS_INVERSION_MASK)
+#define GetControl(port)	((parport_read_control(port)^CONTROL_INVERSION_MASK)&(0x3f))
+#define SetControl(port,val)	parport_write_control(port,(val)^CONTROL_INVERSION_MASK)
+
+#define GetStatusMasked(port,mask)	(GetStatus(port) & (mask))
+#define GetControlMasked(port,mask)	(GetControl(port) & (mask))
+#define SetControlMasked(port,mask)	SetControl(port,GetControl(port) | (mask));
+#define ClearControlMasked(port,mask)	SetControl(port,GetControl(port)&~(mask));
+#define FrobControlBit(port,mask,value)	SetControl(port,(GetControl(port)&~(mask))|((value)&(mask)));
+
+#define PACKET_LENGTH 	8
+
+/* Magic numbers for defining port-device mappings */
+#define PPCPIA_PARPORT_UNSPEC -4
+#define PPCPIA_PARPORT_AUTO -3
+#define PPCPIA_PARPORT_OFF -2
+#define PPCPIA_PARPORT_NONE -1
+
+#ifdef MODULE
+static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
+static char *parport[PARPORT_MAX] = {NULL,};
+
+MODULE_AUTHOR("B. Huisman <bhuism@cs.utwente.nl> & Peter Pregler <Peter_Pregler@email.com>");
+MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras");
+MODULE_PARM(parport, "1-" __MODULE_STRING(PARPORT_MAX) "s");
+MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");
+#else
+static int parport_nr[PARPORT_MAX] __initdata =
+	{[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
+static int parport_ptr = 0;
+#endif
+
+struct pp_cam_entry {
+	struct pardevice *pdev;
+	struct parport *port;
+	struct tq_struct cb_task;
+	int open_count;
+	wait_queue_head_t wq_stream;
+	/* image state flags */
+	int image_ready;	/* we got an interrupt */
+	int image_complete;	/* we have seen 4 EOI */
+
+	int streaming; /* we are in streaming mode */
+	int stream_irq;
+};
+
+static struct cpia_camera_ops cpia_pp_ops = 
+{
+	cpia_pp_open,
+	cpia_pp_registerCallback,
+	cpia_pp_transferCmd,
+	cpia_pp_streamStart,
+	cpia_pp_streamStop,
+	cpia_pp_streamRead,
+	cpia_pp_close,
+	1
+};
+
+static struct cam_data *cam_list;
+
+#ifdef _CPIA_DEBUG_
+#define DEB_PORT(port) { \
+u8 controll = GetControl(port); \
+u8 statusss = GetStatus(port); \
+DBG("nsel %c per %c naut %c nstrob %c nak %c busy %c nfaul %c sel %c init %c dir %c\n",\
+((controll & nSelectIn)	? 'U' : 'D'), \
+((statusss & PError)	? 'U' : 'D'), \
+((controll & nAutoFd)	? 'U' : 'D'), \
+((controll & nStrobe)	? 'U' : 'D'), \
+((statusss & nAck)	? 'U' : 'D'), \
+((statusss & Busy)	? 'U' : 'D'), \
+((statusss & nFault)	? 'U' : 'D'), \
+((statusss & Select)	? 'U' : 'D'), \
+((controll & nInit)	? 'U' : 'D'), \
+((controll & DirBit)	? 'R' : 'F')  \
+); }
+#else
+#define DEB_PORT(port) {}
+#endif
+
+#define WHILE_OUT_TIMEOUT (HZ/10)
+#define DMA_TIMEOUT 10*HZ
+
+/* FIXME */
+static void cpia_parport_enable_irq( struct parport *port ) {
+	parport_enable_irq(port);
+	mdelay(10);
+	return;
+}
+
+static void cpia_parport_disable_irq( struct parport *port ) {
+	parport_disable_irq(port);
+	mdelay(10);
+	return;
+}
+
+/****************************************************************************
+ *
+ *  EndTransferMode
+ *
+ ***************************************************************************/
+static void EndTransferMode(struct pp_cam_entry *cam)
+{
+	parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
+}
+
+/****************************************************************************
+ *
+ *  ForwardSetup
+ *
+ ***************************************************************************/
+static int ForwardSetup(struct pp_cam_entry *cam)
+{
+	int retry;
+	
+	/* After some commands the camera needs extra time before
+	 * it will respond again, so we try up to 3 times */
+	for(retry=0; retry<3; ++retry) {
+		if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) {
+			break;
+		}
+	}
+	if(retry == 3) {
+		DBG("Unable to negotiate ECP mode\n");
+		return -1;
+	}
+	return 0;
+}
+
+/****************************************************************************
+ *
+ *  ReverseSetup
+ *
+ ***************************************************************************/
+static int ReverseSetup(struct pp_cam_entry *cam, int extensibility)
+{
+	int retry;
+	int mode = IEEE1284_MODE_ECP;
+	if(extensibility) mode = 8|3|IEEE1284_EXT_LINK;
+
+	/* After some commands the camera needs extra time before
+	 * it will respond again, so we try up to 3 times */
+	for(retry=0; retry<3; ++retry) {
+		if(!parport_negotiate(cam->port, mode)) {
+			break;
+		}
+	}
+	if(retry == 3) {
+		if(extensibility)
+			DBG("Unable to negotiate extensibility mode\n");
+		else
+			DBG("Unable to negotiate ECP mode\n");
+		return -1;
+	}
+	if(extensibility) cam->port->ieee1284.mode = IEEE1284_MODE_ECP;
+	return 0;
+}
+
+/****************************************************************************
+ *
+ *  WritePacket
+ *
+ ***************************************************************************/
+static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size)
+{
+	int retval=0;
+	int size_written;
+
+	if (packet == NULL) {
+		return -EINVAL;
+	}
+	if (ForwardSetup(cam)) {
+		DBG("Write failed in setup\n");
+		return -EIO;
+	}
+	size_written = parport_write(cam->port, packet, size);
+	if(size_written != size) {
+		DBG("Write failed, wrote %d/%d\n", size_written, size);
+		retval = -EIO;
+	}
+	EndTransferMode(cam);
+	return retval;
+}
+
+/****************************************************************************
+ *
+ *  ReadPacket
+ *
+ ***************************************************************************/
+static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size)
+{
+	int retval=0;
+	if (packet == NULL) {
+		return -EINVAL;
+	}
+	if (ReverseSetup(cam, 0)) {
+		return -EIO;
+	}
+	if(parport_read(cam->port, packet, size) != size) {
+		retval = -EIO;
+	}
+	EndTransferMode(cam);
+	return retval;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_streamStart
+ *
+ ***************************************************************************/
+static int cpia_pp_streamStart(void *privdata)
+{
+	struct pp_cam_entry *cam = privdata;
+	DBG("\n");
+	cam->streaming=1;
+	cam->image_ready=0;
+	//if (ReverseSetup(cam,1)) return -EIO;
+	if(cam->stream_irq) cpia_parport_enable_irq(cam->port);
+	return 0;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_streamStop
+ *
+ ***************************************************************************/
+static int cpia_pp_streamStop(void *privdata)
+{
+	struct pp_cam_entry *cam = privdata;
+
+	DBG("\n");
+	cam->streaming=0;
+	cpia_parport_disable_irq(cam->port);
+	//EndTransferMode(cam);
+
+	return 0;
+}
+
+static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
+{
+	int bytes_read, new_bytes;
+	for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
+		new_bytes = parport_read(port, buffer+bytes_read,
+			                 len-bytes_read);
+		if(new_bytes < 0) break;
+	}
+	return bytes_read;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_streamRead
+ *
+ ***************************************************************************/
+static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
+{
+	struct pp_cam_entry *cam = privdata;
+	int read_bytes = 0;
+	int i, endseen, block_size, new_bytes;
+
+	if(cam == NULL) {
+		DBG("Internal driver error: cam is NULL\n");
+		return -EINVAL;
+	}
+	if(buffer == NULL) {
+		DBG("Internal driver error: buffer is NULL\n");
+		return -EINVAL;
+	}
+	//if(cam->streaming) DBG("%d / %d\n", cam->image_ready, noblock);
+	if( cam->stream_irq ) {
+		DBG("%d\n", cam->image_ready);
+		cam->image_ready--;
+	}
+	cam->image_complete=0;
+	if (0/*cam->streaming*/) {
+		if(!cam->image_ready) {
+			if(noblock) return -EWOULDBLOCK;
+			interruptible_sleep_on(&cam->wq_stream);
+			if( signal_pending(current) ) return -EINTR;
+			DBG("%d\n", cam->image_ready);
+		}
+	} else {
+		if (ReverseSetup(cam, 1)) {
+			DBG("unable to ReverseSetup\n");
+			return -EIO;
+		}
+	}
+	endseen = 0;
+	block_size = PARPORT_CHUNK_SIZE;
+	while( !cam->image_complete ) {
+		if(current->need_resched)  schedule();
+		
+		new_bytes = cpia_pp_read(cam->port, buffer, block_size );
+		if( new_bytes <= 0 ) {
+			break;
+		}
+		i=-1;
+		while(++i<new_bytes && endseen<4) {
+	        	if(*buffer==EOI) {
+	                	endseen++;
+	                } else {
+	                	endseen=0;
+	                }
+			buffer++;
+		}
+		read_bytes += i;
+		if( endseen==4 ) {
+			cam->image_complete=1;
+			break;
+		}
+		if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
+			block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
+		}
+	}
+	EndTransferMode(cam);
+	return cam->image_complete ? read_bytes : -EIO;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_transferCmd
+ *
+ ***************************************************************************/
+static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data)
+{
+	int err;
+	int retval=0;
+	int databytes;
+	struct pp_cam_entry *cam = privdata;
+
+	if(cam == NULL) {
+		DBG("Internal driver error: cam is NULL\n");
+		return -EINVAL;
+	}
+	if(command == NULL) {
+		DBG("Internal driver error: command is NULL\n");
+		return -EINVAL;
+	}
+	databytes = (((int)command[7])<<8) | command[6];
+	if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) {
+		DBG("Error writing command\n");
+		return err;
+	}
+	if(command[0] == DATA_IN) {
+		u8 buffer[8];
+		if(data == NULL) {
+			DBG("Internal driver error: data is NULL\n");
+			return -EINVAL;
+		}
+		if((err = ReadPacket(cam, buffer, 8)) < 0) {
+			return err;
+			DBG("Error reading command result\n");
+		}
+		memcpy(data, buffer, databytes);
+	} else if(command[0] == DATA_OUT) {
+		if(databytes > 0) {
+			if(data == NULL) {
+				DBG("Internal driver error: data is NULL\n");
+				retval = -EINVAL;
+			} else {
+				if((err=WritePacket(cam, data, databytes)) < 0){
+					DBG("Error writing command data\n");
+					return err;
+				}
+			}
+		}
+	} else {
+		DBG("Unexpected first byte of command: %x\n", command[0]);
+		retval = -EINVAL;
+	}
+	return retval;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_open
+ *
+ ***************************************************************************/
+static int cpia_pp_open(void *privdata)
+{
+	struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata;
+	
+	if (cam == NULL)
+		return -EINVAL;
+	
+	if(cam->open_count == 0) {
+		if (parport_claim(cam->pdev)) {
+			DBG("failed to claim the port\n");
+			return -EBUSY;
+		}
+		parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
+		parport_data_forward(cam->port);
+		parport_write_control(cam->port, PARPORT_CONTROL_SELECT);
+		udelay(50);
+		parport_write_control(cam->port,
+		                      PARPORT_CONTROL_SELECT
+		                      | PARPORT_CONTROL_INIT);
+	}
+	
+	++cam->open_count;
+	
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+	return 0;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_registerCallback
+ *
+ ***************************************************************************/
+static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void *cbdata)
+{
+	struct pp_cam_entry *cam = privdata;
+	int retval = 0;
+	
+	if(cam->port->irq != PARPORT_IRQ_NONE) {
+		cam->cb_task.routine = cb;
+		cam->cb_task.data = cbdata;
+	} else {
+		retval = -1;
+	}
+	return retval;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_close
+ *
+ ***************************************************************************/
+static int cpia_pp_close(void *privdata)
+{
+	struct pp_cam_entry *cam = privdata;
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	if (--cam->open_count == 0) {
+		parport_release(cam->pdev);
+	}
+	return 0;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_register
+ *
+ ***************************************************************************/
+static int cpia_pp_register(struct parport *port)
+{
+	struct pardevice *pdev = NULL;
+	struct pp_cam_entry *cam;
+	struct cam_data *cpia;
+
+	if (!(port->modes & PARPORT_MODE_ECP) &&
+	    !(port->modes & PARPORT_MODE_TRISTATE)) {
+		LOG("port is not ECP capable\n");
+		return -ENXIO;
+	}
+
+	cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);
+	if (cam == NULL) {
+		LOG("failed to allocate camera structure\n");
+		return -ENOMEM;
+	}
+	memset(cam,0,sizeof(struct pp_cam_entry));
+	
+	pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
+	                               NULL, 0, cam);
+
+	if (!pdev) {
+		LOG("failed to parport_register_device\n");
+		kfree(cam);
+		return -ENXIO;
+	}
+
+	cam->pdev = pdev;
+	cam->port = port;
+	init_waitqueue_head(&cam->wq_stream);
+
+	cam->streaming = 0;
+	cam->stream_irq = 0;
+
+	if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) {
+		LOG("failed to cpia_register_camera\n");
+		parport_unregister_device(pdev);
+		kfree(cam);
+		return -ENXIO;
+	}
+	ADD_TO_LIST(cam_list, cpia);
+
+	return 0;
+}
+
+static void cpia_pp_detach (struct parport *port)
+{
+	struct cam_data *cpia;
+
+	for(cpia = cam_list; cpia != NULL; cpia = cpia->next) {
+		struct pp_cam_entry *cam = cpia->lowlevel_data;
+		if (cam && cam->port->number == port->number) {
+			REMOVE_FROM_LIST(cpia);
+			
+			cpia_unregister_camera(cpia);
+			
+			if(cam->open_count > 0) {
+				cpia_pp_close(cam);
+			}
+
+			parport_unregister_device(cam->pdev);
+		
+			kfree(cam);
+			cpia->lowlevel_data = NULL;
+			break;
+		}
+	}
+}
+
+static void cpia_pp_attach (struct parport *port)
+{
+	unsigned int i;
+
+	switch (parport_nr[0])
+	{
+	case PPCPIA_PARPORT_UNSPEC:
+	case PPCPIA_PARPORT_AUTO:
+		if (port->probe_info[0].class != PARPORT_CLASS_MEDIA ||
+		    port->probe_info[0].cmdset == NULL ||
+		    strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0)
+			return;
+
+		cpia_pp_register(port);
+
+		break;
+
+	default:
+		for (i = 0; i < PARPORT_MAX; ++i) {
+			if (port->number == parport_nr[i]) {
+				cpia_pp_register(port);
+				break;
+			}
+		}
+		break;
+	}
+}
+
+static struct parport_driver cpia_pp_driver = {
+	"cpia_pp",
+	cpia_pp_attach,
+	cpia_pp_detach,
+	NULL
+};
+
+int cpia_pp_init(void)
+{
+	printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, 
+	       CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
+
+	if(parport_nr[0] == PPCPIA_PARPORT_OFF) {
+		printk("  disabled\n");
+		return 0;
+	}
+	
+	if (parport_register_driver (&cpia_pp_driver)) {
+		LOG ("unable to register with parport\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	if (parport[0]) {
+		/* The user gave some parameters.  Let's see what they were. */
+		if (!strncmp(parport[0], "auto", 4)) {
+			parport_nr[0] = PPCPIA_PARPORT_AUTO;
+		} else {
+			int n;
+			for (n = 0; n < PARPORT_MAX && parport[n]; n++) {
+				if (!strncmp(parport[n], "none", 4)) {
+					parport_nr[n] = PPCPIA_PARPORT_NONE;
+				} else {
+					char *ep;
+					unsigned long r = simple_strtoul(parport[n], &ep, 0);
+					if (ep != parport[n]) {
+						parport_nr[n] = r;
+					} else {
+						LOG("bad port specifier `%s'\n", parport[n]);
+						return -ENODEV;
+					}
+				}
+			}
+		}
+	}
+#if defined(CONFIG_KMOD) && defined(CONFIG_PNP_PARPORT_MODULE)
+	if(parport_enumerate() && !parport_enumerate()->probe_info.model) {
+		request_module("parport_probe");
+	}
+#endif
+	return cpia_pp_init();
+}
+
+void cleanup_module(void)
+{
+	parport_unregister_driver (&cpia_pp_driver);
+	return;
+}
+
+#else /* !MODULE */
+
+static int __init cpia_pp_setup(char *str)
+{
+#if 0
+	/* Is this only a 2.2ism? -jerdfelt */
+	if (!str) {
+		if (ints[0] == 0 || ints[1] == 0) {
+			/* disable driver on "cpia_pp=" or "cpia_pp=0" */
+			parport_nr[0] = PPCPIA_PARPORT_OFF;
+		}
+	} else
+#endif
+	if (!strncmp(str, "parport", 7)) {
+		int n = simple_strtoul(str + 7, NULL, 10);
+		if (parport_ptr < PARPORT_MAX) {
+			parport_nr[parport_ptr++] = n;
+		} else {
+			LOG("too many ports, %s ignored.\n", str);
+		}
+	} else if (!strcmp(str, "auto")) {
+		parport_nr[0] = PPCPIA_PARPORT_AUTO;
+	} else if (!strcmp(str, "none")) {
+		parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
+	}
+
+	return 0;
+}
+
+__setup("cpia_pp=", cpia_pp_setup);
+
+#endif /* !MODULE */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/cpia_usb.c linux/drivers/char/cpia_usb.c
--- v2.3.99-pre3/linux/drivers/char/cpia_usb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/cpia_usb.c	Thu Mar 30 18:00:01 2000
@@ -0,0 +1,626 @@
+/*
+ * cpia_usb CPiA USB driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * Copyright (C) 1999        Jochen Scharrlach <Jochen.Scharrlach@schwaben.de>
+ * Copyright (C) 1999, 2000  Johannes Erdfelt <jerdfelt@valinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/usb.h>
+
+#include "cpia.h"
+
+#define USB_REQ_CPIA_GRAB_FRAME			0xC1
+#define USB_REQ_CPIA_UPLOAD_FRAME		0xC2
+#define  WAIT_FOR_NEXT_FRAME			0
+#define  FORCE_FRAME_UPLOAD			1
+
+#define FRAMES_PER_DESC		10
+#define FRAME_SIZE_PER_DESC	960	/* Shouldn't be hardcoded */
+#define CPIA_NUMSBUF		2
+#define STREAM_BUF_SIZE		(PAGE_SIZE * 4)
+#define SCRATCH_BUF_SIZE	(STREAM_BUF_SIZE * 2)
+
+struct cpia_sbuf {
+	char *data;
+	urb_t *urb;
+};
+
+#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
+enum framebuf_status {
+	FRAME_EMPTY,
+	FRAME_READING,
+	FRAME_READY,
+	FRAME_ERROR,
+};
+
+struct framebuf {
+	int length;
+	enum framebuf_status status;
+	u8 data[FRAMEBUF_LEN];
+	struct framebuf *next;
+};
+
+struct usb_cpia {
+	/* Device structure */
+	struct usb_device *dev;
+
+	unsigned char iface;
+	wait_queue_head_t wq_stream;
+
+	int cursbuf;		/* Current receiving sbuf */
+	struct cpia_sbuf sbuf[CPIA_NUMSBUF];		/* Double buffering */
+
+	int streaming;
+	int open;
+	int present;
+	struct framebuf *buffers[3];
+	struct framebuf *curbuff, *workbuff;
+};
+
+static int cpia_usb_open(void *privdata);
+static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
+			             void *cbdata);
+static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data);
+static int cpia_usb_streamStart(void *privdata);
+static int cpia_usb_streamStop(void *privdata);
+static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock);
+static int cpia_usb_close(void *privdata);
+
+#define ABOUT "USB driver for Vision CPiA based cameras"
+
+static struct cpia_camera_ops cpia_usb_ops = {
+	cpia_usb_open,
+	cpia_usb_registerCallback,
+	cpia_usb_transferCmd,
+	cpia_usb_streamStart,
+	cpia_usb_streamStop,
+	cpia_usb_streamRead,
+	cpia_usb_close,
+	0
+};
+
+static struct cam_data *cam_list;
+
+static void cpia_usb_complete(struct urb *urb)
+{
+	int i;
+	char *cdata;
+	struct usb_cpia *ucpia;
+
+	if (!urb || !urb->context)
+		return;
+
+	ucpia = (struct usb_cpia *) urb->context;
+
+	if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open)
+		return;
+
+	if (ucpia->workbuff->status == FRAME_EMPTY) {
+		ucpia->workbuff->status = FRAME_READING;
+		ucpia->workbuff->length = 0;
+	}
+ 		  
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int n = urb->iso_frame_desc[i].actual_length;
+		int st = urb->iso_frame_desc[i].status;
+
+		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		if (st)
+			printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", i, n, st);
+
+		if (FRAMEBUF_LEN < ucpia->workbuff->length + n) {
+			printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n);
+			return;
+		}
+	    
+		if (n) {
+			if ((ucpia->workbuff->length > 0) || 
+			    (0x19 == cdata[0] && 0x68 == cdata[1])) {
+				memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n);
+				ucpia->workbuff->length += n;
+			} else
+				DBG("Ignoring packet!\n");
+		} else {
+			if (ucpia->workbuff->length > 4 &&
+			    0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] &&
+			    0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] &&
+			    0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] &&
+			    0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) {
+				ucpia->workbuff->status = FRAME_READY;
+				ucpia->curbuff = ucpia->workbuff;
+				ucpia->workbuff = ucpia->workbuff->next;
+				ucpia->workbuff->status = FRAME_EMPTY;
+				ucpia->workbuff->length = 0;
+		  
+				if (waitqueue_active(&ucpia->wq_stream))
+					wake_up_interruptible(&ucpia->wq_stream);
+			}
+		}
+	}
+}
+
+static int cpia_usb_open(void *privdata)
+{
+	struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+	urb_t *urb;
+	int ret, retval = 0, fx, err;
+  
+	if (!ucpia)
+		return -EINVAL;
+
+	ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+	if (!ucpia->sbuf[0].data)
+		return -EINVAL;
+
+	ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+	if (!ucpia->sbuf[1].data) {
+		retval = -EINVAL;
+		goto error_0;
+	}
+	
+	ret = usb_set_interface(ucpia->dev, ucpia->iface, 3);
+	if (ret < 0) {
+		printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret);
+		retval = -EBUSY;
+		goto error_all;
+	}
+
+	ucpia->buffers[0]->status = FRAME_EMPTY;
+	ucpia->buffers[0]->length = 0;
+	ucpia->buffers[1]->status = FRAME_EMPTY;
+	ucpia->buffers[1]->length = 0;
+	ucpia->buffers[2]->status = FRAME_EMPTY;
+	ucpia->buffers[2]->length = 0;
+	ucpia->curbuff = ucpia->buffers[0];
+	ucpia->workbuff = ucpia->buffers[1];
+
+	/* We double buffer the Iso lists */
+	urb = usb_alloc_urb(FRAMES_PER_DESC);
+	if (!urb) {
+		printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
+		retval = -ENOMEM;
+		goto error_all;
+	}
+
+	ucpia->sbuf[0].urb = urb;
+	urb->dev = ucpia->dev;
+	urb->context = ucpia;
+	urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
+	urb->transfer_flags = USB_ISO_ASAP;
+	urb->transfer_buffer = ucpia->sbuf[0].data;
+	urb->complete = cpia_usb_complete;
+	urb->number_of_packets = FRAMES_PER_DESC;
+	urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+		urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
+		urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+	}
+
+	urb = usb_alloc_urb(FRAMES_PER_DESC);
+	if (!urb) {
+		printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
+		retval = -ENOMEM;
+		goto error_all;
+	}
+
+	ucpia->sbuf[1].urb = urb;
+	urb->dev = ucpia->dev;
+	urb->context = ucpia;
+	urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
+	urb->transfer_flags = USB_ISO_ASAP;
+	urb->transfer_buffer = ucpia->sbuf[1].data;
+	urb->complete = cpia_usb_complete;
+	urb->number_of_packets = FRAMES_PER_DESC;
+	urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+		urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
+		urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+	}
+
+	ucpia->sbuf[1].urb->next = ucpia->sbuf[0].urb;
+	ucpia->sbuf[0].urb->next = ucpia->sbuf[1].urb;
+	
+	err = usb_submit_urb(ucpia->sbuf[0].urb);
+	if (err)
+		printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n",
+			err);
+	err = usb_submit_urb(ucpia->sbuf[1].urb);
+	if (err)
+		printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n",
+			err);
+
+	ucpia->streaming = 1;
+	ucpia->open = 1;
+
+	return 0;
+
+error_all:
+	kfree (ucpia->sbuf[1].data);
+error_0:
+	kfree (ucpia->sbuf[0].data);
+	
+	return retval;
+}
+
+//
+// convenience functions
+//
+
+/****************************************************************************
+ *
+ *  WritePacket
+ *
+ ***************************************************************************/
+static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t size)
+{
+	if (!packet)
+		return -EINVAL;
+
+	return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			 packet[1] + (packet[0] << 8),
+			 USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			 packet[2] + (packet[3] << 8), 
+			 packet[4] + (packet[5] << 8), buf, size, HZ);
+}
+
+/****************************************************************************
+ *
+ *  ReadPacket
+ *
+ ***************************************************************************/
+static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size)
+{
+	if (!packet || size <= 0)
+		return -EINVAL;
+
+	return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			 packet[1] + (packet[0] << 8),
+			 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			 packet[2] + (packet[3] << 8), 
+			 packet[4] + (packet[5] << 8), buf, size, HZ);
+}
+
+static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
+{
+	int err = 0;
+	int databytes;
+	struct usb_cpia *ucpia = (struct usb_cpia *)privdata;
+	struct usb_device *udev = ucpia->dev;
+
+	if (!udev) {
+		DBG("Internal driver error: udev is NULL\n");
+		return -EINVAL;
+	}
+
+	if (!command) {
+		DBG("Internal driver error: command is NULL\n");
+		return -EINVAL;
+	}
+
+	databytes = (((int)command[7])<<8) | command[6];
+
+	if (command[0] == DATA_IN) {
+		u8 buffer[8];
+
+		if (!data) {
+			DBG("Internal driver error: data is NULL\n");
+			return -EINVAL;
+		}
+
+		err = ReadPacket(udev, command, buffer, 8);
+		if (err < 0)
+			return err;
+
+		memcpy(data, buffer, databytes);
+	} else if(command[0] == DATA_OUT)
+		WritePacket(udev, command, data, databytes);
+	else {
+		DBG("Unexpected first byte of command: %x\n", command[0]);
+		err = -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
+	void *cbdata)
+{
+	return -ENODEV;
+}
+
+static int cpia_usb_streamStart(void *privdata)
+{
+	return -ENODEV;
+}
+
+static int cpia_usb_streamStop(void *privdata)
+{
+	return -ENODEV;
+}
+
+static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
+{
+	struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+	struct framebuf *mybuff;
+
+	if (!ucpia || !ucpia->present)
+		return -1;
+  
+	if (ucpia->curbuff->status != FRAME_READY)
+		interruptible_sleep_on(&ucpia->wq_stream);
+	else
+		DBG("Frame already waiting!\n");
+
+	mybuff = ucpia->curbuff;
+
+	if (!mybuff)
+		return -1;
+  
+	if (mybuff->status != FRAME_READY || mybuff->length < 4) {
+		DBG("Something went wrong!\n");
+		return -1;
+	}
+
+	memcpy(frame, mybuff->data, mybuff->length);
+	mybuff->status = FRAME_EMPTY;
+  
+/*   DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n",  */
+/*       mybuff->length, frame[0], frame[1], */
+/*       frame[mybuff->length-4], frame[mybuff->length-3],  */
+/*       frame[mybuff->length-2], frame[mybuff->length-1]); */
+
+	return mybuff->length;
+}
+
+static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try)
+{
+	if (!ucpia->streaming)
+		return;
+
+	ucpia->streaming = 0;
+
+	/* Set packet size to 0 */
+	if (try) {
+		int ret;
+
+		ret = usb_set_interface(ucpia->dev, ucpia->iface, 0);
+		if (ret < 0) {
+			printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret);
+			return;
+		}
+	}
+
+	/* Unschedule all of the iso td's */
+	if (ucpia->sbuf[1].urb) {
+		usb_unlink_urb(ucpia->sbuf[1].urb);
+		usb_free_urb(ucpia->sbuf[1].urb);
+		ucpia->sbuf[1].urb = NULL;
+	}
+
+	if (ucpia->sbuf[0].urb) {
+		usb_unlink_urb(ucpia->sbuf[0].urb);
+		usb_free_urb(ucpia->sbuf[0].urb);
+		ucpia->sbuf[0].urb = NULL;
+	}
+}
+
+static int cpia_usb_close(void *privdata)
+{
+	struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+
+	ucpia->open = 0;
+
+	cpia_usb_free_resources(ucpia, 1);
+
+	if (!ucpia->present)
+		kfree(ucpia);
+
+	return 0;
+}
+
+int cpia_usb_init(void)
+{
+	/* return -ENODEV; */
+	return 0;
+}
+
+/* Probing and initializing */
+
+static void *cpia_probe(struct usb_device *udev, unsigned int ifnum)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_cpia *ucpia;
+	struct cam_data *cam;
+	int ret;
+  
+	/* A multi-config CPiA camera? */
+	if (udev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	interface = &udev->actconfig->interface[ifnum].altsetting[0];
+
+	/* Is it a CPiA? */
+	if (udev->descriptor.idVendor != 0x0553)
+		return NULL;
+	if (udev->descriptor.idProduct != 0x0002)
+		return NULL;
+
+	/* We found a CPiA */
+	printk(KERN_INFO "USB CPiA camera found\n");
+
+	ucpia = kmalloc(sizeof(*ucpia), GFP_KERNEL);
+	if (!ucpia) {
+		printk(KERN_ERR "couldn't kmalloc cpia struct\n");
+		return NULL;
+	}
+
+	memset(ucpia, 0, sizeof(*ucpia));
+
+	ucpia->dev = udev;
+	ucpia->iface = interface->bInterfaceNumber;
+	init_waitqueue_head(&ucpia->wq_stream);
+
+	ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0]));
+	if (!ucpia->buffers[0]) {
+		printk(KERN_ERR "couldn't vmalloc frame buffer 0\n");
+		goto fail_alloc_0;
+	}
+
+	ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1]));
+	if (!ucpia->buffers[1]) {
+		printk(KERN_ERR "couldn't vmalloc frame buffer 1\n");
+		goto fail_alloc_1;
+	}
+
+	ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2]));
+	if (!ucpia->buffers[2]) {
+		printk(KERN_ERR "couldn't vmalloc frame buffer 2\n");
+		goto fail_alloc_2;
+	}
+
+	ucpia->buffers[0]->next = ucpia->buffers[1];
+	ucpia->buffers[1]->next = ucpia->buffers[2];
+	ucpia->buffers[2]->next = ucpia->buffers[0];
+
+	ret = usb_set_interface(udev, ucpia->iface, 0);
+	if (ret < 0) {
+		printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", ret);
+		/* goto fail_all; */
+	}
+
+	/* Before register_camera, important */
+	ucpia->present = 1;
+  
+	cam = cpia_register_camera(&cpia_usb_ops, ucpia);
+	if (!cam) {
+		LOG("failed to cpia_register_camera\n");
+		goto fail_all;
+	}
+
+	ADD_TO_LIST(cam_list, cam);
+
+	return cam;
+
+fail_all:
+	vfree(ucpia->buffers[2]);
+	ucpia->buffers[2] = NULL;
+fail_alloc_2:
+	vfree(ucpia->buffers[1]);
+	ucpia->buffers[1] = NULL;
+fail_alloc_1:
+	vfree(ucpia->buffers[0]);
+	ucpia->buffers[0] = NULL;
+fail_alloc_0:
+
+	return NULL;
+}
+
+static void cpia_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_driver cpia_driver = {
+	"cpia",
+	cpia_probe,
+	cpia_disconnect,
+	{ NULL, NULL }
+};
+
+/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */
+/* _disconnect from usb_cpia_cleanup is not necessary since usb_deregister */
+/* will do it for us as well as passing a udev structure - jerdfelt */
+static void cpia_disconnect(struct usb_device *udev, void *ptr)
+{
+	struct cam_data *cam = (struct cam_data *) ptr;
+	struct usb_cpia *ucpia = (struct usb_cpia *) cam->lowlevel_data;
+  
+	REMOVE_FROM_LIST(cam);
+
+	/* Don't even try to reset the altsetting if we're disconnected */
+	cpia_usb_free_resources(ucpia, 0);
+
+	ucpia->present = 0;
+
+	cpia_unregister_camera(cam);
+
+	ucpia->curbuff->status = FRAME_ERROR;
+
+	if (waitqueue_active(&ucpia->wq_stream))
+		wake_up_interruptible(&ucpia->wq_stream);
+
+	usb_driver_release_interface(&cpia_driver,
+				     &udev->actconfig->interface[0]);
+
+	ucpia->curbuff = ucpia->workbuff = NULL;
+
+	if (ucpia->buffers[2]) {
+		vfree(ucpia->buffers[2]);
+		ucpia->buffers[2] = NULL;
+	}
+
+	if (ucpia->buffers[1]) {
+		vfree(ucpia->buffers[1]);
+		ucpia->buffers[1] = NULL;
+	}
+
+	if (ucpia->buffers[0]) {
+		vfree(ucpia->buffers[0]);
+		ucpia->buffers[0] = NULL;
+	}
+
+	if (!ucpia->open)
+		kfree(ucpia);
+}
+
+int usb_cpia_init(void)
+{
+	cam_list = NULL;
+
+	return usb_register(&cpia_driver);
+}
+
+void usb_cpia_cleanup(void)
+{
+/*
+	struct cam_data *cam;
+
+	while ((cam = cam_list) != NULL)
+		cpia_disconnect(NULL, cam);
+*/
+
+	usb_deregister(&cpia_driver);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return usb_cpia_init();
+}
+
+void cleanup_module(void)
+{
+	usb_cpia_cleanup();
+}
+#endif /* !MODULE */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/joystick/joy-spaceball.c linux/drivers/char/joystick/joy-spaceball.c
--- v2.3.99-pre3/linux/drivers/char/joystick/joy-spaceball.c	Wed Dec  8 14:11:26 1999
+++ linux/drivers/char/joystick/joy-spaceball.c	Sun Apr  2 15:33:34 2000
@@ -207,6 +207,8 @@
 	struct js_sball_info iniinfo;
 	struct js_sball_info *info = &iniinfo;
 
+	MOD_INC_USE_COUNT;
+
 	info->tty = tty;
 	info->idx = 0;
 	info->used = 1;
@@ -221,8 +223,6 @@
 
 	js_sball_init_corr(js_sball_port->corr);
 
-	MOD_INC_USE_COUNT;
-
 	return 0;
 }
 
@@ -312,9 +312,7 @@
 
 static struct tty_ldisc js_sball_ldisc = {
 	magic:		TTY_LDISC_MAGIC,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 	name:		"spaceball",
-#endif
 	open:		js_sball_ldisc_open,
 	close:		js_sball_ldisc_close,
 	receive_buf:	js_sball_ldisc_receive,
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/joystick/joy-spaceorb.c linux/drivers/char/joystick/joy-spaceorb.c
--- v2.3.99-pre3/linux/drivers/char/joystick/joy-spaceorb.c	Wed Dec  8 14:11:26 1999
+++ linux/drivers/char/joystick/joy-spaceorb.c	Sun Apr  2 15:33:34 2000
@@ -199,6 +199,8 @@
 	struct js_orb_info iniinfo;
 	struct js_orb_info *info = &iniinfo;
 
+	MOD_INC_USE_COUNT;
+
 	info->tty = tty;
 	info->idx = 0;
 	info->used = 1;
@@ -213,8 +215,6 @@
 
 	js_orb_init_corr(js_orb_port->corr);
 
-	MOD_INC_USE_COUNT;
-
 	return 0;
 }
 
@@ -270,9 +270,7 @@
 
 static struct tty_ldisc js_orb_ldisc = {
 	magic:		TTY_LDISC_MAGIC,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 	name:		"spaceorb",
-#endif
 	open:		js_orb_ldisc_open,
 	close:		js_orb_ldisc_close,
 	receive_buf:	js_orb_ldisc_receive,
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/joystick/joy-warrior.c linux/drivers/char/joystick/joy-warrior.c
--- v2.3.99-pre3/linux/drivers/char/joystick/joy-warrior.c	Wed Dec  8 14:11:26 1999
+++ linux/drivers/char/joystick/joy-warrior.c	Sun Apr  2 15:33:34 2000
@@ -90,28 +90,12 @@
 			if (!info->port->devs[0]) return;
 			buttons[0][0] = ((data[3] & 0xa) >> 1) | ((data[3] & 0x5) << 1);
 			return;
-		case 2:					/* Static status (Send !S to get one) */
-#if 0
-			printk("joy-warrior: Static status:");
-			for (i = 0; i < 12; i++)
-				printk(" %02x", info->data[i]);
-			printk("\n");
-#endif
-			return;
 		case 3:					/* XY-axis info->data */
 			if (!info->port->devs[0]) return;
 			axes[0][0] = ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5));
 			axes[0][1] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7);
 			return;
 			break;
-		case 4:					/* Dynamic status */
-#if 0
-			printk("joy-warrior: Dynamic status:");
-			for (i = 0; i < 4; i++)
-				printk(" %02x", info->data[i]);
-			printk("\n");
-#endif
-			return;
 		case 5:					/* Throttle, spinner, hat info->data */
 			if (!info->port->devs[0]) return;
 			axes[0][2] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7);
@@ -119,6 +103,9 @@
 			axes[0][4] = (data[3] & 8 ? 1 : 0) - (info->data[3] & 4 ? 1 : 0);
 			axes[0][5] = (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5);
 			return;
+		case 2:					/* Static status (Send !S to get one) */
+		case 4:					/* Dynamic status */
+			return;
 		default:
 			printk("joy-warrior: Unknown packet %d length %d:", (data[0] >> 4) & 7, info->idx);
 			for (i = 0; i < info->idx; i++)
@@ -199,6 +186,8 @@
 	struct js_war_info iniinfo;
 	struct js_war_info *info = &iniinfo;
 
+	MOD_INC_USE_COUNT;
+
 	info->tty = tty;
 	info->idx = 0;
 	info->len = 0;
@@ -216,8 +205,6 @@
 
 	js_war_init_corr(js_war_port->corr);
 
-	MOD_INC_USE_COUNT;
-
 	return 0;
 }
 
@@ -283,9 +270,7 @@
 
 static struct tty_ldisc js_war_ldisc = {
         magic:          TTY_LDISC_MAGIC,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
         name:           "warrior",
-#endif
 	open:		js_war_ldisc_open,
 	close:		js_war_ldisc_close,
 	receive_buf:	js_war_ldisc_receive,
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/joystick/joystick.c linux/drivers/char/joystick/joystick.c
--- v2.3.99-pre3/linux/drivers/char/joystick/joystick.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/char/joystick/joystick.c	Sun Apr  2 15:33:34 2000
@@ -499,6 +499,7 @@
 	if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
 		return -EINVAL;
 
+
 	spin_lock_irqsave(&js_lock, flags);
 
 	while (i > 0 && jd) {
@@ -510,32 +511,32 @@
 
 	if (!jd) return -ENODEV;
 
-	if ((result = jd->open(jd))) return result;
-
-	if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) {
+	if ((result = jd->open(jd)))
+		return result;
 
-		MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 
-		spin_lock_irqsave(&js_lock, flags);
+	if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
 
-		curl = jd->list;
+	spin_lock_irqsave(&js_lock, flags);
 
-		jd->list = new;
-		jd->list->next = curl;
-		jd->list->dev = jd;
-		jd->list->startup = 0;
-		jd->list->tail = GOB(jd->bhead);
-		file->private_data = jd->list;
+	curl = jd->list;
 
-		spin_unlock_irqrestore(&js_lock, flags);
+	jd->list = new;
+	jd->list->next = curl;
+	jd->list->dev = jd;
+	jd->list->startup = 0;
+	jd->list->tail = GOB(jd->bhead);
+	file->private_data = jd->list;
 
-		if (!js_use_count++) js_do_timer(0);
+	spin_unlock_irqrestore(&js_lock, flags);
 
-	} else {
-		result = -ENOMEM;
-	}
+	if (!js_use_count++) js_do_timer(0);
 
-	return result;
+	return 0;
 }
 
 /*
@@ -573,10 +574,11 @@
 	kfree(file->private_data);
 
 	if (!--js_use_count) del_timer(&js_timer);
-	MOD_DEC_USE_COUNT;
 
 	jd->close(jd);
 
+	MOD_DEC_USE_COUNT;
+
 	return 0;
 }
 
@@ -584,50 +586,6 @@
  * js_dump_mem() dumps all data structures in memory.
  * It's used for debugging only.
  */
-
-#if 0
-static void js_dump_mem(void)
-{
-
-	struct js_port *curp = js_port;
-	struct js_dev *curd = js_dev;
-	int i;
-
-	printk(",--- Dumping Devices:\n");
-	printk("| js_dev = %x\n", (int) js_dev);
-
-	while (curd) {
-		printk("|  %s-device %x, next %x axes %d, buttons %d, port %x - %#x\n",
-			curd->next ? "|":"`",
-			(int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port, curd->port->io);
-		curd = curd->next;
-	}
-
-	printk(">--- Dumping ports:\n");
-	printk("| js_port = %x\n", (int) js_port);
-
-	while (curp) {
-		printk("|  %s-port %x, next %x, io %#x, devices %d\n",
-			curp->next ? "|":"`",
-			(int) curp, (int) curp->next, curp->io, curp->ndevs);
-		for (i = 0; i < curp->ndevs; i++) {
-			curd = curp->devs[i];
-			if (curd)
-			printk("|  %s %s-device %x, next %x axes %d, buttons %d, port %x\n",
-				curp->next ? "|":" ", (i < curp->ndevs-1) ? "|":"`",
-				(int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port);
-			else
-			printk("|  %s %s-device %x, not there\n",
-				curp->next ? "|":" ", (i < curp->ndevs-1) ? "|":"`", (int) curd);
-
-		}
-		curp = curp->next;
-	}
-
-	printk("`--- Done\n");
-}
-#endif
-
 
 struct js_port *js_register_port(struct js_port *port,
 				void *info, int devs, int infos, js_read_func read)
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.3.99-pre3/linux/drivers/char/mem.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/char/mem.c	Mon Apr 10 22:58:59 2000
@@ -34,9 +34,6 @@
 #ifdef CONFIG_SOUND_OSS
 void soundcard_init(void);
 #endif
-#ifdef CONFIG_DMASOUND
-void dmasound_init(void);
-#endif
 #endif
 #ifdef CONFIG_SPARCAUDIO
 extern int sparcaudio_init(void);
@@ -633,9 +630,6 @@
 	soundcore_init();
 #ifdef CONFIG_SOUND_OSS
 	soundcard_init();
-#endif
-#ifdef CONFIG_DMASOUND
-	dmasound_init();
 #endif
 #endif
 #ifdef CONFIG_SPARCAUDIO
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c
--- v2.3.99-pre3/linux/drivers/char/n_r3964.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/char/n_r3964.c	Sun Apr  2 15:38:53 2000
@@ -12,7 +12,10 @@
  * Author:
  * L. Haag
  *
- * $Log: r3964.c,v $
+ * $Log: n_r3964.c,v $
+ * Revision 1.8  2000/03/23 14:14:54  dwmw2
+ * Fix race in sleeping in r3964_read()
+ *
  * Revision 1.7  1999/28/08 11:41:50  dwmw2
  * Port to 2.3 kernel
  *
@@ -38,7 +41,6 @@
  *
  *
  */
-#define R3964_VERSION "1.7"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -224,7 +226,7 @@
 {
    int status;
    
-   printk ("r3964: Philips r3964 Driver V%s\n", R3964_VERSION);
+   printk ("r3964: Philips r3964 Driver $Revision: 1.8 $\n");
 
    /*
     * Register the tty line discipline
@@ -1280,8 +1282,8 @@
          /* block until there is a message: */
          add_wait_queue(&pInfo->read_wait, &wait);
 repeat:
-         pMsg = remove_msg(pInfo, pClient);
          current->state = TASK_INTERRUPTIBLE;
+         pMsg = remove_msg(pInfo, pClient);
 	 if (!pMsg && !signal_pending(current))
 		 {
             schedule();
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c
--- v2.3.99-pre3/linux/drivers/char/pcwd.c	Thu Feb 10 17:11:08 2000
+++ linux/drivers/char/pcwd.c	Tue Apr  4 19:25:14 2000
@@ -39,6 +39,7 @@
  * 990605	Made changes to code to support Firmware 1.22a, added
  *		fairly useless proc entry.
  * 990610	removed said useless proc code for the merge <alan>
+ * 000403	Removed last traces of proc code. <davej>
  */
 
 #include <linux/module.h>
@@ -539,38 +540,6 @@
 {
 	outb_p(0x00, current_readport + 2);
 	mode_debug = 0;
-}
-
-static int pcwd_proc_get_info(char *buffer, char **start, off_t offset,
-	int length, int inout)
-{
-	int len;
-	off_t begin = 0;
-	
-	revision = get_revision();
-	len = sprintf(buffer, "Version = " WD_VER "\n");
-	
-	if (revision == PCWD_REVISION_A)
-		len += sprintf(buffer + len, "Revision = A\n");
-	else
-		len += sprintf(buffer + len, "Revision = C\n");
-	
-	if (supports_temp) {
-		unsigned short c = inb(current_readport);
-		
-		len += sprintf(buffer + len, "Temp = Yes\n"
-			"Current temp = %d (Celsius)\n",
-			c);
-	} else
-		len += sprintf(buffer + len, "Temp = No\n");
-	
-	*start = buffer + (offset);
-	len -= offset;
-
-	if (len > length)
-		len = length;
-	
-	return len;
 }
 
 static struct file_operations pcwd_fops = {
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.3.99-pre3/linux/drivers/char/ppdev.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/char/ppdev.c	Mon Apr  3 13:24:05 2000
@@ -537,7 +537,7 @@
 	unsigned int minor = MINOR (inode->i_rdev);
 	struct pp_struct *pp = file->private_data;
 
-	if (pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT) {
+	if (pp->pdev && pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT) {
 		if (!(pp->flags & PP_CLAIMED)) {
 			parport_claim_or_block (pp->pdev);
 			pp->flags |= PP_CLAIMED;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v2.3.99-pre3/linux/drivers/char/pty.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/char/pty.c	Sun Apr  2 15:20:27 2000
@@ -29,10 +29,6 @@
 #define BUILDING_PTY_C 1
 #include <linux/devpts_fs.h>
 
-extern void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
-				unsigned int minor);
-extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
-
 struct pty_struct {
 	int	magic;
 	wait_queue_head_t open_wait;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.3.99-pre3/linux/drivers/char/serial.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/char/serial.c	Sun Apr  2 15:20:27 2000
@@ -220,10 +220,6 @@
 #define _INLINE_
 #endif
 
-extern void tty_register_devfs  (struct tty_driver *driver, unsigned int flags,
-				 unsigned int minor);
-extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
-
 static char *serial_name = "Serial driver";
 
 static DECLARE_TASK_QUEUE(tq_serial);
@@ -4359,6 +4355,9 @@
 		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
 	/* U.S. Robotics 56K FAX INT */
 	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Viking 56K FAX INT */
+	{	ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262), 0, 0,
 		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
 
 	/* These ID's are taken from M$ documentation */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c
--- v2.3.99-pre3/linux/drivers/char/sh-sci.c	Tue Mar  7 14:32:25 2000
+++ linux/drivers/char/sh-sci.c	Mon Mar 27 10:26:15 2000
@@ -1,9 +1,10 @@
-/* $Id: sh-sci.c,v 1.32 2000-03-05 13:56:18+09 gniibe Exp $
+/* $Id: sh-sci.c,v 1.36 2000/03/22 13:32:10 gniibe Exp $
  *
  *  linux/drivers/char/sh-sci.c
  *
  *  SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
  *  Copyright (C) 1999, 2000  Niibe Yutaka
+ *  Copyright (C) 2000  Sugioka Toshinobu
  *
  * TTY code is based on sx.c (Specialix SX driver) by:
  *
@@ -38,7 +39,7 @@
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 
-#include "generic_serial.h"
+#include <linux/generic_serial.h>
 #include "sh-sci.h"
 
 #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
@@ -54,7 +55,7 @@
 static void sci_enable_rx_interrupts(void *ptr);
 static int  sci_get_CD(void *ptr);
 static void sci_shutdown_port(void *ptr);
-static void sci_set_real_termios(void *ptr);
+static int sci_set_real_termios(void *ptr);
 static void sci_hungup(void *ptr);
 static void sci_close(void *ptr);
 static int sci_chars_in_buffer(void *ptr);
@@ -142,7 +143,11 @@
 	}
 
 	if (t > 0) {
-		sci_setsignals (port, 1, -1); 
+		sci_setsignals (port, 1, -1);
+		if(t >= 256) {
+			ctrl_out((ctrl_in(SCSMR) & ~3) | 1, SCSMR);
+			t >>= 2;
+		}
 		ctrl_outb(t, SCBRR);
 		ctrl_outw(0xa400, RFCR); /* Refresh counter clear */
 		while (ctrl_inw(RFCR) < WAIT_RFCR_COUNTER)
@@ -155,7 +160,7 @@
 static void sci_set_termios_cflag(struct sci_port *port)
 {
 	unsigned short status;
-	unsigned short smr_val=0;
+	unsigned short smr_val;
 #if defined(CONFIG_SH_SCIF_SERIAL)
 	unsigned short fcr_val=6; /* TFRST=1, RFRST=1 */
 #endif
@@ -172,6 +177,7 @@
 	fcr_val = 0;
 #endif
 
+	smr_val = ctrl_in(SCSMR) & 3;
 	if ((port->gs.tty->termios->c_cflag & CSIZE) == CS7)
 		smr_val |= 0x40;
 	if (C_PARENB(port->gs.tty))
@@ -196,7 +202,7 @@
 	sci_enable_rx_interrupts(port);
 }
 
-static void sci_set_real_termios(void *ptr)
+static int sci_set_real_termios(void *ptr)
 {
 	struct sci_port *port = ptr;
 
@@ -218,6 +224,8 @@
 		set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
 	else
 		clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
+
+	return 0;
 }
 
 /* ********************************************************************** *
@@ -352,10 +360,16 @@
 static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs)
 {
 	struct sci_port *port = ptr;
+	unsigned long flags;
 
 	if (port->gs.flags & GS_ACTIVE)
-		if (!(port->gs.flags & SCI_RX_THROTTLE))
+		if (!(port->gs.flags & SCI_RX_THROTTLE)) {
 			sci_receive_chars(port);
+			return;
+		}
+	save_and_cli(flags);
+	ctrl_out(ctrl_in(SCSCR) & ~SCI_CTRL_FLAGS_RIE, SCSCR);
+	restore_flags(flags);
 }
 
 static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
@@ -363,9 +377,14 @@
 	struct sci_port *port = ptr;
 
 	if (port->gs.flags & GS_ACTIVE)
-		if (port->gs.xmit_cnt) {
-			sci_transmit_chars(port);
-		}
+		sci_transmit_chars(port);
+	else {
+		unsigned long flags;
+
+		save_and_cli(flags);
+		ctrl_out(ctrl_in(SCSCR) & ~SCI_CTRL_FLAGS_TIE, SCSCR);
+		restore_flags(flags);
+	}
 }
 
 static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/sh-sci.h linux/drivers/char/sh-sci.h
--- v2.3.99-pre3/linux/drivers/char/sh-sci.h	Tue Mar  7 14:32:25 2000
+++ linux/drivers/char/sh-sci.h	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-/* $Id: sh-sci.h,v 1.5 2000-03-05 13:54:32+09 gniibe Exp $
+/* $Id: sh-sci.h,v 1.8 2000/03/08 15:19:39 gniibe Exp $
  *
  *  linux/drivers/char/sh-sci.h
  *
@@ -18,13 +18,18 @@
 #define SC_SR  (volatile unsigned char *)0xfffffe88
 #define SC_RDR  0xfffffe8a
 #define SCSPTR 0xffffff7c
-
-#define SCSCR_INIT	0x30	/* TIE=0,RIE=0,TE=1,RE=1 */
-
 #elif defined(__SH4__)
-Not yet.
+#define SCSMR	(volatile unsigned char *)0xffe00000
+#define SCBRR	0xffe00004
+#define SCSCR	(volatile unsigned char *)0xffe00008
+#define SC_TDR	0xffe0000c
+#define SC_SR	(volatile unsigned char *)0xffe00010
+#define SC_RDR	0xffe00014
+#define SCSPTR	0xffe0001c
 #endif
 
+#define SCSCR_INIT	0x30	/* TIE=0,RIE=0,TE=1,RE=1 */
+
 #define SCI_TD_E  0x80
 #define SCI_RD_F  0x40
 #define SCI_ORER  0x20
@@ -45,8 +50,6 @@
 #define SCI_CTRL_FLAGS_CKE1 0x02
 #define SCI_CTRL_FLAGS_CKE0 0x01
 
-#define RFCR    0xffffff74
-
 #define SCI_ERI_IRQ	23
 #define SCI_RXI_IRQ	24
 #define SCI_TXI_IRQ	25
@@ -69,8 +72,6 @@
 #undef  SCSPTR /* Is there any register for RTS?? */
 #undef  SCLSR
 
-#define RFCR   0xffffff74
-
 #define SCSCR_INIT	0x30	/* TIE=0,RIE=0,TE=1,RE=1 */
 				/* 0x33 when external clock is used */
 #define SCI_IPR_OFFSET	(64+4)
@@ -87,8 +88,6 @@
 #define SCSPTR 0xFFE80020
 #define SCLSR  0xFFE80024
 
-#define RFCR   0xFF800028
-
 #define SCSCR_INIT	0x0038	/* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
 #define SCI_IPR_OFFSET	(32+4)
 
@@ -131,6 +130,12 @@
 #endif
 #endif
 
+#if defined(__sh3__)
+#define RFCR   0xffffff74
+#elif defined(__SH4__)
+#define RFCR   0xFF800028
+#endif
+
 #define SCI_PRIORITY	3
 
 #define SCI_MINOR_START		64
@@ -183,14 +188,15 @@
  */
 
 #if defined(__sh3__)
-#define BPS_2400       191
-#define BPS_4800       95
-#define BPS_9600       47
-#define BPS_19200      23
-#define BPS_38400      11
-#define BPS_115200     3
+#define PCLK           14745600
 #elif defined(__SH4__)
-/* Values for SH-4 please! */
-
-#define BPS_115200     8
+#define PCLK           33333333
 #endif
+
+#define SCBRR_VALUE(bps) (PCLK/(32*bps)-1)
+#define BPS_2400       SCBRR_VALUE(2400)
+#define BPS_4800       SCBRR_VALUE(4800)
+#define BPS_9600       SCBRR_VALUE(9600)
+#define BPS_19200      SCBRR_VALUE(19200)
+#define BPS_38400      SCBRR_VALUE(38400)
+#define BPS_115200     SCBRR_VALUE(115200)
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.3.99-pre3/linux/drivers/char/tty_io.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/char/tty_io.c	Sun Apr  2 15:20:27 2000
@@ -99,9 +99,6 @@
 #ifdef CONFIG_VT
 extern void con_init_devfs (void);
 #endif
-void tty_register_devfs  (struct tty_driver *driver, unsigned int flags,
-			  unsigned minor);
-void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
 
 #define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
 #define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
@@ -153,6 +150,12 @@
 extern console_8xx_init(void);
 extern int rs_8xx_init(void);
 #endif /* CONFIG_8xx */
+#ifdef CONFIG_HWC
+extern void hwc_console_init(void);
+#endif
+#ifdef CONFIG_3215
+extern void con3215_init(void);
+#endif /* CONFIG_3215 */
 
 
 #ifndef MIN
@@ -2191,6 +2194,12 @@
 #if defined(CONFIG_SERIAL167)
 	serial167_console_init();
 #endif
+#endif
+#ifdef CONFIG_3215
+        con3215_init();
+#endif
+#ifdef CONFIG_HWC
+        hwc_console_init();
 #endif
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/tuner.c linux/drivers/char/tuner.c
--- v2.3.99-pre3/linux/drivers/char/tuner.c	Tue Mar  7 14:32:25 2000
+++ linux/drivers/char/tuner.c	Sun Apr  2 15:32:49 2000
@@ -97,7 +97,6 @@
 	{ "Temic NTSC", TEMIC, NTSC,
 	  16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
 	{ "Temic PAL_I", TEMIC, PAL_I,
-	  // 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, 
 	  16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
  	{ "Temic 4036 FY5 NTSC", TEMIC, NTSC,
 	  16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
@@ -111,6 +110,8 @@
 	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
         { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
 	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
+	{ "Temic 4006FH5", TEMIC, PAL_I,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, 
 };
 #define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/videodev.c linux/drivers/char/videodev.c
--- v2.3.99-pre3/linux/drivers/char/videodev.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/char/videodev.c	Mon Mar 27 10:29:41 2000
@@ -47,6 +47,9 @@
 #ifdef CONFIG_VIDEO_BWQCAM
 extern int init_bw_qcams(struct video_init *);
 #endif
+#ifdef CONFIG_VIDEO_CPIA
+extern int cpia_init(struct video_init *);
+#endif
 #ifdef CONFIG_VIDEO_PLANB
 extern int init_planbs(struct video_init *);
 #endif
@@ -62,6 +65,9 @@
 #ifdef CONFIG_VIDEO_BWQCAM
 	{"bw-qcam", init_bw_qcams},
 #endif	
+#ifdef CONFIG_VIDEO_CPIA
+	{"cpia", cpia_init},
+#endif	
 #ifdef CONFIG_VIDEO_PLANB
 	{"planb", init_planbs},
 #endif
@@ -133,9 +139,11 @@
 	if(vfl==NULL) {
 		char modname[20];
 
+		MOD_INC_USE_COUNT;
 		sprintf (modname, "char-major-%d-%d", VIDEO_MAJOR, minor);
 		request_module(modname);
 		vfl=video_device[minor];
+		MOD_DEC_USE_COUNT;
 		if (vfl==NULL)
 			return -ENODEV;
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/wd501p.h linux/drivers/char/wd501p.h
--- v2.3.99-pre3/linux/drivers/char/wd501p.h	Mon Jan 12 15:12:42 1998
+++ linux/drivers/char/wd501p.h	Sun Apr  2 15:38:53 2000
@@ -25,11 +25,21 @@
 #define WDT_COUNT1		(io+1)
 #define WDT_COUNT2		(io+2)
 #define WDT_CR			(io+3)
-#define WDT_SR			(io+4)
-#define WDT_RT			(io+5)
-#define WDT_UNUSED		(io+6)
+#define WDT_SR			(io+4)	/* Start buzzer on PCI write */
+#define WDT_RT			(io+5)	/* Stop buzzer on PCI write */
+#define WDT_BUZZER		(io+6)	/* PCI only: rd=disable, wr=enable */
 #define WDT_DC			(io+7)
 
+/* The following are only on the PCI card, they're outside of I/O space on
+ * the ISA card: */
+#define WDT_CLOCK		(io+12)	/* COUNT2: rd=16.67MHz, wr=2.0833MHz */
+/* inverted opto isolated reset output: */
+#define WDT_OPTONOTRST		(io+13)	/* wr=enable, rd=disable */
+/* opto isolated reset output: */
+#define WDT_OPTORST		(io+14)	/* wr=enable, rd=disable */
+/* programmable outputs: */
+#define WDT_PROGOUT		(io+15)	/* wr=enable, rd=disable */
+
 #define WDC_SR_WCCR		1	/* Active low */
 #define WDC_SR_TGOOD		2
 #define WDC_SR_ISOI0		4
@@ -39,6 +49,8 @@
 #define WDC_SR_PSUUNDR		64	/* Active low */
 #define WDC_SR_IRQ		128	/* Active low */
 
+#ifndef WDT_IS_PCI
+
 /*
  *	Feature Map 1 is the active high inputs not supported on your card.
  *	Feature Map 2 is the active low inputs not supported on your card.
@@ -62,6 +74,13 @@
 #endif
 
 #ifdef CONFIG_WDT_500		/* Minimal board */
+#define FEATUREMAP1		(WDC_SR_TGOOD|WDC_SR_FANGOOD)
+#define FEATUREMAP2		(WDC_SR_PSUOVER|WDC_SR_PSUUNDR)
+#define WDT_OPTION_MASK		(WDIOF_OVERHEAT)
+#endif
+
+#else
+
 #define FEATUREMAP1		(WDC_SR_TGOOD|WDC_SR_FANGOOD)
 #define FEATUREMAP2		(WDC_SR_PSUOVER|WDC_SR_PSUUNDR)
 #define WDT_OPTION_MASK		(WDIOF_OVERHEAT)
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/char/wdt_pci.c linux/drivers/char/wdt_pci.c
--- v2.3.99-pre3/linux/drivers/char/wdt_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/wdt_pci.c	Sun Apr  2 15:38:53 2000
@@ -0,0 +1,558 @@
+/*
+ *	Industrial Computer Source WDT500/501 driver for Linux 2.1.x
+ *
+ *	(c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.com
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *	
+ *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
+ *	warranty for any of this software. This material is provided 
+ *	"AS-IS" and at no charge.	
+ *
+ *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ *	Release 0.08.
+ *
+ *	Fixes
+ *		Dave Gregorich	:	Modularisation and minor bugs
+ *		Alan Cox	:	Added the watchdog ioctl() stuff
+ *		Alan Cox	:	Fixed the reboot problem (as noted by
+ *					Matt Crocker).
+ *		Alan Cox	:	Added wdt= boot option
+ *		Alan Cox	:	Cleaned up copy/user stuff
+ *		Tim Hockin	:	Added insmod parameters, comment cleanup
+ *					Parameterized timeout
+ *		JP Nollmann	:	Added support for PCI wdt501p
+ *		Alan Cox	:	Split ISA and PCI cards into two drivers
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#define WDT_IS_PCI
+#include "wd501p.h"
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <linux/pci.h>
+
+/*
+ * Until Access I/O gets their application for a PCI vendor ID approved,
+ * I don't think that it's appropriate to move these constants into the
+ * regular pci_ids.h file. -- JPN 2000/01/18
+ */
+
+#ifndef PCI_VENDOR_ID_ACCESSIO
+#define PCI_VENDOR_ID_ACCESSIO 0x494f
+#endif
+#ifndef PCI_DEVICE_ID_WDG_CSM
+#define PCI_DEVICE_ID_WDG_CSM 0x22c0
+#endif
+
+static int wdt_is_open=0;
+
+/*
+ *	You must set these - there is no sane way to probe for this board.
+ *	You can use wdt=x,y to set these now.
+ */
+ 
+static int io=0x240;
+static int irq=11;
+
+#define WD_TIMO (100*60)		/* 1 minute */
+
+#ifndef MODULE
+
+/**
+ *	wdtpci_setup:
+ *	@str: command line string
+ *
+ *	Setup options. The board isn't really probe-able so we have to
+ *	get the user to tell us the configuration. Sane people build it 
+ *	modular but the others come here.
+ */
+ 
+static int __init wdtpci_setup(char *str)
+{
+	int ints[4];
+
+	str = get_options (str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] > 0)
+	{
+		io = ints[1];
+		if(ints[0] > 1)
+			irq = ints[2];
+	}
+
+	return 1;
+}
+
+__setup("wdt=", wdtpci_setup);
+
+#endif /* !MODULE */
+ 
+/*
+ *	Programming support
+ */
+ 
+static void wdtpci_ctr_mode(int ctr, int mode)
+{
+	ctr<<=6;
+	ctr|=0x30;
+	ctr|=(mode<<1);
+	outb_p(ctr, WDT_CR);
+}
+
+static void wdtpci_ctr_load(int ctr, int val)
+{
+	outb_p(val&0xFF, WDT_COUNT0+ctr);
+	outb_p(val>>8, WDT_COUNT0+ctr);
+}
+
+/*
+ *	Kernel methods.
+ */
+ 
+ 
+/**
+ *	wdtpci_status:
+ *	
+ *	Extract the status information from a WDT watchdog device. There are
+ *	several board variants so we have to know which bits are valid. Some
+ *	bits default to one and some to zero in order to be maximally painful.
+ *
+ *	we then map the bits onto the status ioctl flags.
+ */
+ 
+static int wdtpci_status(void)
+{
+	/*
+	 *	Status register to bit flags
+	 */
+	 
+	int flag=0;
+	unsigned char status=inb_p(WDT_SR);
+	status|=FEATUREMAP1;
+	status&=~FEATUREMAP2;	
+	
+	if(!(status&WDC_SR_TGOOD))
+		flag|=WDIOF_OVERHEAT;
+	if(!(status&WDC_SR_PSUOVER))
+		flag|=WDIOF_POWEROVER;
+	if(!(status&WDC_SR_PSUUNDR))
+		flag|=WDIOF_POWERUNDER;
+	if(!(status&WDC_SR_FANGOOD))
+		flag|=WDIOF_FANFAULT;
+	if(status&WDC_SR_ISOI0)
+		flag|=WDIOF_EXTERN1;
+	if(status&WDC_SR_ISII1)
+		flag|=WDIOF_EXTERN2;
+	return flag;
+}
+
+/**
+ *	wdtpci_interrupt:
+ *	@irq:		Interrupt number
+ *	@dev_id:	Unused as we don't allow multiple devices.
+ *	@regs:		Unused.
+ *
+ *	Handle an interrupt from the board. These are raised when the status
+ *	map changes in what the board considers an interesting way. That means
+ *	a failure condition occuring.
+ */
+ 
+static void wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/*
+	 *	Read the status register see what is up and
+	 *	then printk it. 
+	 */
+	 
+	unsigned char status=inb_p(WDT_SR);
+	
+	status|=FEATUREMAP1;
+	status&=~FEATUREMAP2;	
+	
+	printk(KERN_CRIT "WDT status %d\n", status);
+	
+	if(!(status&WDC_SR_TGOOD))
+		printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT));
+	if(!(status&WDC_SR_PSUOVER))
+		printk(KERN_CRIT "PSU over voltage.\n");
+	if(!(status&WDC_SR_PSUUNDR))
+		printk(KERN_CRIT "PSU under voltage.\n");
+	if(!(status&WDC_SR_FANGOOD))
+		printk(KERN_CRIT "Possible fan fault.\n");
+	if(!(status&WDC_SR_WCCR))
+#ifdef SOFTWARE_REBOOT
+#ifdef ONLY_TESTING
+		printk(KERN_CRIT "Would Reboot.\n");
+#else		
+		printk(KERN_CRIT "Initiating system reboot.\n");
+		machine_restart(NULL);
+#endif		
+#else
+		printk(KERN_CRIT "Reset in 5ms.\n");
+#endif		
+}
+
+
+static long long wdtpci_llseek(struct file *file, long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+/**
+ *	wdtpci_ping:
+ *
+ *	Reload counter one with the watchdog timeout. We don't bother reloading
+ *	the cascade counter. 
+ */
+ 
+static void wdtpci_ping(void)
+{
+	/* Write a watchdog value */
+	inb_p(WDT_DC);
+	wdtpci_ctr_mode(1,2);
+	wdtpci_ctr_load(1,WD_TIMO);		/* Timeout */
+	outb_p(0, WDT_DC);
+}
+
+/**
+ *	wdtpci_write:
+ *	@file: file handle to the watchdog
+ *	@buf: buffer to write (unused as data does not matter here 
+ *	@count: count of bytes
+ *	@ppos: pointer to the position to write. No seeks allowed
+ *
+ *	A write to a watchdog device is defined as a keepalive signal. Any
+ *	write of data will do, as we we don't define content meaning.
+ */
+ 
+static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if(count)
+	{
+		wdtpci_ping();
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ *	wdtpci_read:
+ *	@file: file handle to the watchdog board
+ *	@buf: buffer to write 1 byte into
+ *	@count: length of buffer
+ *	@ptr: offset (no seek allowed)
+ *
+ *	Read reports the temperature in degrees Fahrenheit. The API is in
+ *	farenheit. It was designed by an imperial measurement luddite.
+ */
+ 
+static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+	unsigned short c=inb_p(WDT_RT);
+	unsigned char cp;
+	
+	/*  Can't seek (pread) on this device  */
+	if (ptr != &file->f_pos)
+		return -ESPIPE;
+
+	switch(MINOR(file->f_dentry->d_inode->i_rdev))
+	{
+		case TEMP_MINOR:
+			c*=11;
+			c/=15;
+			cp=c+7;
+			if(copy_to_user(buf,&cp,1))
+				return -EFAULT;
+			return 1;
+		default:
+			return -EINVAL;
+	}
+}
+
+/**
+ *	wdtpci_ioctl:
+ *	@inode: inode of the device
+ *	@file: file handle to the device
+ *	@cmd: watchdog command
+ *	@arg: argument pointer
+ *
+ *	The watchdog API defines a common set of functions for all watchdogs
+ *	according to their available features. We only actually usefully support
+ *	querying capabilities and current status. 
+ */
+ 
+static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	static struct watchdog_info ident=
+	{
+		WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER
+			|WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT,
+		1,
+		"WDT500/501PCI"
+	};
+	
+	ident.options&=WDT_OPTION_MASK;	/* Mask down to the card we have */
+	switch(cmd)
+	{
+		default:
+			return -ENOIOCTLCMD;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
+
+		case WDIOC_GETSTATUS:
+			return put_user(wdtpci_status(),(int *)arg);
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, (int *)arg);
+		case WDIOC_KEEPALIVE:
+			wdtpci_ping();
+			return 0;
+	}
+}
+
+/**
+ *	wdtpci_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ *	One of our two misc devices has been opened. The watchdog device is
+ *	single open and on opening we load the counters. Counter zero is a 
+ *	100Hz cascade, into counter 1 which downcounts to reboot. When the
+ *	counter triggers counter 2 downcounts the length of the reset pulse
+ *	which set set to be as long as possible. 
+ */
+ 
+static int wdtpci_open(struct inode *inode, struct file *file)
+{
+	switch(MINOR(inode->i_rdev))
+	{
+		case WATCHDOG_MINOR:
+			if(wdt_is_open)
+				return -EBUSY;
+			MOD_INC_USE_COUNT;
+			/*
+			 *	Activate 
+			 */
+	 
+			wdt_is_open=1;
+
+			inb_p(WDT_DC);		/* Disable */
+
+			/*
+			 * "pet" the watchdog, as Access says.
+			 * This resets the clock outputs.
+			 */
+				
+			wdtpci_ctr_mode(2,0);
+			outb_p(0, WDT_DC);
+
+			inb_p(WDT_DC);
+
+			outb_p(0, WDT_CLOCK);	/* 2.0833MHz clock */
+			inb_p(WDT_BUZZER);	/* disable */
+			inb_p(WDT_OPTONOTRST);	/* disable */
+			inb_p(WDT_OPTORST);	/* disable */
+			inb_p(WDT_PROGOUT);	/* disable */
+			wdtpci_ctr_mode(0,3);
+			wdtpci_ctr_mode(1,2);
+			wdtpci_ctr_mode(2,1);
+			wdtpci_ctr_load(0,20833);	/* count at 100Hz */
+			wdtpci_ctr_load(1,WD_TIMO);/* Timeout 60 seconds */
+			/* DO NOT LOAD CTR2 on PCI card! -- JPN */
+			outb_p(0, WDT_DC);	/* Enable */
+			return 0;
+		case TEMP_MINOR:
+			MOD_INC_USE_COUNT;
+			return 0;
+		default:
+			return -ENODEV;
+	}
+}
+
+/**
+ *	wdtpci_close:
+ *	@inode: inode to board
+ *	@file: file handle to board
+ *
+ *	The watchdog has a configurable API. There is a religious dispute 
+ *	between people who want their watchdog to be able to shut down and 
+ *	those who want to be sure if the watchdog manager dies the machine
+ *	reboots. In the former case we disable the counters, in the latter
+ *	case you have to open it again very soon.
+ */
+ 
+static int wdtpci_release(struct inode *inode, struct file *file)
+{
+	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+	{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT	
+		inb_p(WDT_DC);		/* Disable counters */
+		wdtpci_ctr_load(2,0);	/* 0 length reset pulses now */
+#endif		
+		wdt_is_open=0;
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	notify_sys:
+ *	@this: our notifier block
+ *	@code: the event being reported
+ *	@unused: unused
+ *
+ *	Our notifier is called on system shutdowns. We want to turn the card
+ *	off at reboot otherwise the machine will reboot again during memory
+ *	test or worse yet during the following fsck. This would suck, in fact
+ *	trust me - if it happens it does suck.
+ */
+
+static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT)
+	{
+		/* Turn the card off */
+		inb_p(WDT_DC);
+		wdtpci_ctr_load(2,0);
+	}
+	return NOTIFY_DONE;
+}
+ 
+/*
+ *	Kernel Interfaces
+ */
+ 
+ 
+static struct file_operations wdtpci_fops = {
+	llseek:		wdtpci_llseek,
+	read:		wdtpci_read,
+	write:		wdtpci_write,
+	ioctl:		wdtpci_ioctl,
+	open:		wdtpci_open,
+	release:	wdtpci_release,
+};
+
+static struct miscdevice wdtpci_miscdev=
+{
+	WATCHDOG_MINOR,
+	"watchdog",
+	&wdtpci_fops
+};
+
+#ifdef CONFIG_WDT_501
+static struct miscdevice temp_miscdev=
+{
+	TEMP_MINOR,
+	"temperature",
+	&wdtpci_fops
+};
+#endif
+
+/*
+ *	The WDT card needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off. 
+ */
+ 
+static struct notifier_block wdtpci_notifier=
+{
+	wdtpci_notify_sys,
+	NULL,
+	0
+};
+
+#ifdef MODULE
+
+#define wdtpci_init init_module
+
+/**
+ *	cleanup_module:
+ *
+ *	Unload the watchdog. You cannot do this with any file handles open.
+ *	If your watchdog is set to continue ticking on close and you unload
+ *	it, well it keeps ticking. We won't get the interrupt but the board
+ *	will not touch PC memory so all is fine. You just have to load a new
+ *	module in 60 seconds or reboot.
+ */
+ 
+void cleanup_module(void)
+{
+	misc_deregister(&wdtpci_miscdev);
+#ifdef CONFIG_WDT_501_PCI
+	misc_deregister(&temp_miscdev);
+#endif	
+	unregister_reboot_notifier(&wdtpci_notifier);
+	release_region(io,16);
+	free_irq(irq, &wdtpci_miscdev);
+}
+
+#endif
+
+/**
+ * 	wdtpci_init:
+ *
+ *	Set up the WDT watchdog board. All we have to do is grab the
+ *	resources we require and bitch if anyone beat us to them.
+ *	The open() function will actually kick the board off.
+ */
+ 
+int __init wdtpci_init(void)
+{
+ 	struct pci_dev *dev = NULL;
+ 
+ 	if (pci_present()) 
+ 	{
+ 		while ((dev = pci_find_device(PCI_VENDOR_ID_ACCESSIO,
+ 					     PCI_DEVICE_ID_WDG_CSM, dev))) {
+ 			/* See if we can do this device */
+ 			irq = dev->irq;
+			io = dev->resource[2].start;
+ 			printk("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X "
+			       "(Interrupt %d)\n", io, irq);
+ 		}
+ 	}
+	if(request_region(io, 16, "wdt-pci")==NULL)
+	{
+		printk(KERN_ERR "I/O %d is not free.\n", io);
+		return -EIO;
+	}
+	if(request_irq(irq, wdtpci_interrupt, SA_INTERRUPT|SA_SHIRQ, "wdt-pci", &wdtpci_miscdev))
+	{
+		printk(KERN_ERR "IRQ %d is not free.\n", irq);
+		release_region(io, 16);
+		return -EIO;
+	}
+	misc_register(&wdtpci_miscdev);
+#ifdef CONFIG_WDT_501	
+	misc_register(&temp_miscdev);
+#endif	
+	register_reboot_notifier(&wdtpci_notifier);
+	return 0;
+}
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/i2c/i2c-elektor.c linux/drivers/i2c/i2c-elektor.c
--- v2.3.99-pre3/linux/drivers/i2c/i2c-elektor.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/i2c/i2c-elektor.c	Mon Mar 27 10:28:55 2000
@@ -231,7 +231,7 @@
 	pcf_isa_unreg,
 };
 
-static int __init i2c_pcfisa_init(void) 
+int __init i2c_pcfisa_init(void) 
 {
 
 	struct i2c_pcf_isa *pisa = &gpi;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- v2.3.99-pre3/linux/drivers/ide/ide-disk.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide-disk.c	Mon Apr  3 13:30:00 2000
@@ -813,14 +813,18 @@
 	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
 		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
 
-#if 0	/* done instead for entire identify block in arch/ide.h stuff */
-	/* fix byte-ordering of buffer size field */
-	id->buf_size = le16_to_cpu(id->buf_size);
-#endif
-	printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d",
-			drive->name, id->model,
-			capacity/2048L, id->buf_size/2,
-			drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);
+
+	/* Give size in megabytes (MB), not mebibytes (MiB). */
+	/* We compute the exact rounded value, avoiding overflow. */
+	printk (" (%ld MB)", (capacity - capacity/625 + 974)/1950);
+
+	/* Only print cache size when it was specified */
+	if (id->buf_size)
+		printk (" w/%dKiB Cache", id->buf_size/2);
+
+	printk(", CHS=%d/%d/%d", 
+	       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
 		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
--- v2.3.99-pre3/linux/drivers/ide/ide-pci.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide-pci.c	Mon Mar 27 11:01:13 2000
@@ -603,6 +603,8 @@
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
 		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
 			unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
 			if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- v2.3.99-pre3/linux/drivers/ide/ide.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide.c	Tue Apr  4 19:25:14 2000
@@ -1662,6 +1662,7 @@
 	rq->cmd = IDE_DRIVE_CMD;
 	rq->sector = 0;
 	rq->nr_sectors = 0;
+	rq->nr_segments = 0;
 	rq->current_nr_sectors = 0;
 	rq->sem = NULL;
 	rq->bh = NULL;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.3.99-pre3/linux/drivers/net/8390.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/8390.c	Sun Apr  2 15:38:53 2000
@@ -114,8 +114,8 @@
 static void set_multicast_list(struct net_device *dev);
 static void do_set_multicast_list(struct net_device *dev);
 
-/**
- *	DOC: SMP and the 8390 setup.
+/*
+ *	SMP and the 8390 setup.
  *
  *	The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
  *	a page register that controls bank and packet buffer access. We guard
@@ -407,13 +407,16 @@
 }
 
 /**
- * ei_interrupt - 
- * @irq:
- * @dev_id:
- * @regs:
+ * ei_interrupt - handle the interrupts from an 8390
+ * @irq: interrupt number
+ * @dev_id: a pointer to the net_device
+ * @regs: unused
  *
- * The typical workload of the driver:
- * Handle the ether interface interrupts.
+ * Handle the ether interface interrupts. We pull packets from
+ * the 8390 via the card specific functions and fire them at the networking
+ * stack. We also handle transmit completions and wake the transmit path if
+ * neccessary. We also update the counters and do other housekeeping as
+ * needed
  */
 
 void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.99-pre3/linux/drivers/net/Config.in	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/Config.in	Sun Apr  2 15:38:53 2000
@@ -108,9 +108,7 @@
       tristate '    HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
       tristate '    HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
       tristate '    HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
-      if [ "$CONFIG_OBSOLETE" = "y" ]; then
-	 tristate '    ICL EtherTeam 16i/32 support' CONFIG_ETH16I
-      fi
+      tristate '    ICL EtherTeam 16i/32 support' CONFIG_ETH16I
       tristate '    NE2000/NE1000 support' CONFIG_NE2000
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
 	 tristate '    SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
@@ -194,7 +192,7 @@
 
 bool 'FDDI driver support' CONFIG_FDDI
 if [ "$CONFIG_FDDI" = "y" ]; then
-   bool '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+   dep_tristate '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX $CONFIG_FDDI
    tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP
 fi
 
@@ -216,6 +214,7 @@
 
 tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
+   dep_bool '  PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL
    dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
    dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
    dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.99-pre3/linux/drivers/net/Makefile	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/Makefile	Mon Mar 27 09:44:58 2000
@@ -324,7 +324,9 @@
 M_OBJS          := $(sort $(filter-out $(export-objs), $(obj-m)))
 MX_OBJS         := $(sort $(filter     $(export-objs), $(obj-m)))
 
+ifneq ($(ARCH),s390)
 O_OBJS += auto_irq.o
+endif
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.3.99-pre3/linux/drivers/net/Space.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/Space.c	Sun Apr  2 15:38:53 2000
@@ -119,7 +119,7 @@
 extern int de620_probe(struct net_device *);
 
 /* FDDI adapters */
-extern int dfx_probe(struct net_device *dev);
+extern int dfx_probe(void);
 extern int apfddi_init(struct net_device *dev);
 extern int skfp_probe(struct net_device *dev);
 
@@ -185,6 +185,9 @@
 #ifdef CONFIG_NE3210
 	{ne3210_probe, 0},
 #endif
+#ifdef CONFIG_DEFXX
+	{dfx_probe, 0}.
+#endif
 	{NULL, 0},
 };
 
@@ -469,9 +472,6 @@
 	    return 1;		/* ENXIO */
 
     if (1
-#ifdef CONFIG_DEFXX
-	&& dfx_probe(dev)
-#endif
 #ifdef CONFIG_APFDDI
 	&& apfddi_init(dev)
 #endif
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.3.99-pre3/linux/drivers/net/defxx.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/defxx.c	Mon Apr 10 23:09:01 2000
@@ -194,11 +194,12 @@
  *		12-Sep-96	LVS		Reset current address to factory address during
  *							device open.  Updated transmit path to post a
  *							single fragment which includes PRH->end of data.
+ *		Mar 2000	AC		Did various cleanups for 2.3.x
  */
 
 /* Version information string - should be updated prior to each new release!!! */
 
-static const char *version = "defxx.c:v1.04 09/16/96  Lawrence V. Stefani (stefani@lkg.dec.com)\n";
+static const char *version = "defxx.c:v1.05 2000/03/26  Lawrence V. Stefani (stefani@lkg.dec.com) and others\n";
 
 /* Include files */
 
@@ -236,11 +237,11 @@
 
 /* Define global routines */
 
-int	dfx_probe(struct net_device *dev);
+int	dfx_probe(void);
 
 /* Define module-wide (static) routines */
 
-static struct net_device *dfx_alloc_device(struct net_device *dev, u16 iobase);
+static struct net_device *dfx_alloc_device(u16 iobase);
 
 static void		dfx_bus_init(struct net_device *dev);
 static void		dfx_bus_config_check(DFX_board_t *bp);
@@ -402,29 +403,9 @@
  *   dev - pointer to device information
  *
  * Functional Description:
- *   This routine is called by the OS for each FDDI device name (fddi0,
- *   fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c.  Since
- *   the DEFXX.C driver currently does not support being loaded as a
- *   module, dfx_probe() will initialize all devices the first time
- *   it is called.
- *
- *   Let's say that dfx_probe() is getting called to initialize fddi0.
- *   Furthermore, let's say there are three supported controllers in the
- *   system.  Before dfx_probe() leaves, devices fddi0, fddi1, and fddi2
- *   will be initialized and a global flag will be set to indicate that
- *   dfx_probe() has already been called.
- *
- *   However...the OS doesn't know that we've already initialized
- *   devices fddi1 and fddi2 so dfx_probe() gets called again and again
- *   until it reaches the end of the device list for FDDI (presently,
- *   fddi7).  It's important that the driver "pretend" to probe for
- *   devices fddi1 and fddi2 and return success.  Devices fddi3
- *   through fddi7 will return failure since they weren't initialized.
- *
- *   This algorithm seems to work for the time being.  As other FDDI
- *   drivers are written for Linux, a more generic approach (perhaps
- *   similar to the Ethernet card approach) may need to be implemented.
- *   
+ *   This routine is called by the OS once at startup to scan for
+ *   DEFXX cards.
+ *
  * Return Codes:
  *   0		 - This device (fddi0, fddi1, etc) configured successfully
  *   -ENODEV - No devices present, or no Digital FDDI EISA or PCI device
@@ -446,7 +427,9 @@
  *   the device structure.
  */
 
-int __init dfx_probe(struct net_device *dev)
+static struct net_device *bp_root;
+
+int __init dfx_probe(void)
 {
 	int				i;				/* used in for loops */
 	int				version_disp;	/* was version info string already displayed? */
@@ -456,44 +439,26 @@
 	u16				command;		/* PCI Configuration space Command register val */
 	u32				slot_id;		/* EISA hardware (slot) ID read from adapter */
 	DFX_board_t		*bp;			/* board pointer */
+	struct net_device *dev;
 
 	DBG_printk("In dfx_probe...\n");
 
-	/*
-	 * Verify whether we're going through dfx_probe() again
-	 *
-	 * If so, see if we're going through for a subsequent fddi device that
-	 * we've already initialized.  If we are, return success (0).  If not,
-	 * return failure (-ENODEV).
-	 */
-
 	version_disp = 0;				/* default to version string not displayed */
-	if (already_probed)
-		{
-		DBG_printk("Already entered dfx_probe\n");
-		if (dev != NULL)
-			if ((strncmp(dev->name, "fddi", 4) == 0) && (dev->base_addr != 0))
-				{
-				DBG_printk("In dfx_probe for fddi adapter (%s) we've already initialized it, so return success\n", dev->name);
-				return(0);
-				}
-		return(-ENODEV);
-		}
-	already_probed = 1;			/* set global flag */
+	already_probed = 1;				/* set global flag */
 
 	/* Scan for FDDI EISA controllers */
 
 	for (i=0; i < DFX_MAX_EISA_SLOTS; i++)		/* only scan for up to 16 EISA slots */
-		{
+	{
 		port = (i << 12) + PI_ESIC_K_SLOT_ID;	/* port = I/O address for reading slot ID */
 		slot_id = inl(port);					/* read EISA HW (slot) ID */
 		if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID)
-			{
+		{
 			if (!version_disp)					/* display version info if adapter is found */
-				{
+			{
 				version_disp = 1;				/* set display flag to TRUE so that */
 				printk(version);				/* we only display this string ONCE */
-				}
+			}
 				
 			port = (i << 12);					/* recalc base addr */
 
@@ -501,46 +466,47 @@
 
 			port_len = PI_ESIC_K_CSR_IO_LEN;
 			if (check_region(port, port_len) == 0)
-				{
+			{
 				/* Allocate a new device structure for this adapter */
 
-				dev = dfx_alloc_device(dev, port);
+				dev = dfx_alloc_device(port);
 				if (dev != NULL)
-					{
+				{
 					/* Initialize board structure with bus-specific info */
-
 					bp = (DFX_board_t *) dev->priv;
+					bp->next = bp_root;
+					bp_root = dev;
 					bp->dev = dev;
 					bp->bus_type = DFX_BUS_TYPE_EISA;
 					if (dfx_driver_init(dev) == DFX_K_SUCCESS)
 						num_boards++;		/* only increment global board count on success */
 					else
 						dev->base_addr = 0;	/* clear port address field in device structure on failure */
-					}
 				}
+			}
 			else
 				printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1));
-			}
 		}
+	}
 
 	/* Scan for FDDI PCI controllers */
 
 	if (pci_present())						/* is PCI even present? */
 		while ((pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, pdev)))
-			{
+		{
 			if (!version_disp)					/* display version info if adapter is found */
-				{
+			{
 				version_disp = 1;				/* set display flag to TRUE so that */
 				printk(version);				/* we only display this string ONCE */
-				}
+			}
 
 			/* Verify that I/O enable bit is set (PCI slot is enabled) */
 
 			pci_read_config_word(pdev, PCI_COMMAND, &command);
 			if ((command & PCI_COMMAND_IO) == 0)
-				printk("I/O enable bit not set!  Verify that slot is enabled\n");
+				printk(KERN_ERR "defxx: I/O enable bit not set!  Verify that slot is enabled\n");
 			else
-				{
+			{
 				/* Turn off memory mapped space and enable mastering */
 
 				command |= PCI_COMMAND_MASTER;
@@ -556,28 +522,30 @@
 				port_len = PFI_K_CSR_IO_LEN;
 
 				if (check_region(port, port_len) == 0)
-					{
+				{
 					/* Allocate a new device structure for this adapter */
 
-					dev = dfx_alloc_device(dev, port);
+					dev = dfx_alloc_device(port);
 					if (dev != NULL)
-						{
+					{
 						/* Initialize board structure with bus-specific info */
 
 						bp = (DFX_board_t *) dev->priv;
 						bp->dev = dev;
+						bp->next = bp_root;
+						bp_root = dev;
 						bp->bus_type = DFX_BUS_TYPE_PCI;
 						bp->pci_dev = pdev;
 						if (dfx_driver_init(dev) == DFX_K_SUCCESS)
 							num_boards++;		/* only increment global board count on success */
 						else
 							dev->base_addr = 0;	/* clear port address field in device structure on failure */
-						}
 					}
-				else
-					printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1));
 				}
+				else
+					printk(KERN_ERR "defxx: I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1));
 			}
+		}
 
 	/*
 	 * If we're at this point we're going through dfx_probe() for the first
@@ -589,7 +557,7 @@
 		return(0);
 	else
 		return(-ENODEV);
-	}
+}
 
 
 /*
@@ -639,32 +607,32 @@
  *   None
  */
 
-struct net_device __init *dfx_alloc_device( struct net_device *dev, u16 iobase)
+struct net_device __init *dfx_alloc_device(u16 iobase)
 {
 	struct net_device *tmp_dev;		/* pointer to a device structure */
+	int err;
 
 	DBG_printk("In dfx_alloc_device...\n");
 
 	/* Find next free fddi entry */
 
-	for (tmp_dev = dev; tmp_dev != NULL; tmp_dev = tmp_dev->next)
-		if ((strncmp(tmp_dev->name, "fddi", 4) == 0) && (tmp_dev->base_addr == 0))
-			break;
+	tmp_dev = dev_alloc("fddi%d", &err);
 	if (tmp_dev == NULL)
-		{
-		printk("Could not find free FDDI device structure for this adapter!\n");
+	{
+		printk(KERN_ERR "Could not find free FDDI device structure for this adapter!\n");
 		return(NULL);
-		}
+	}
 	DBG_printk("Device entry free, device name = %s\n", tmp_dev->name);
 
 	/* Allocate space for private board structure */
 
 	tmp_dev->priv = (void *) kmalloc(sizeof(DFX_board_t), GFP_KERNEL);
 	if (tmp_dev->priv == NULL)
-		{
-		printk("Could not allocate memory for private board structure!\n");
+	{
+		printk(KERN_ERR "defxx: Could not allocate memory for private board structure!\n");
+		kfree(tmp_dev);
 		return(NULL);
-		}
+	}
 	memset(tmp_dev->priv, 0, sizeof(DFX_board_t));	/* clear structure */
 
 	/* Initialize new device structure */
@@ -696,7 +664,7 @@
 
 	fddi_setup(tmp_dev);
 	return(tmp_dev);
-	}
+}
 
 
 /*
@@ -1370,22 +1338,22 @@
  *   if the open is successful.
  */
 
-int dfx_open(
-	struct net_device *dev
-	)
-
-	{
+int dfx_open(struct net_device *dev)
+{
 	DFX_board_t	*bp = (DFX_board_t *)dev->priv;
 
 	DBG_printk("In dfx_open...\n");
+	
+	MOD_INC_USE_COUNT;
 
 	/* Register IRQ - support shared interrupts by passing device ptr */
 
 	if (request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev))
-		{
-		printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
-		return(-EAGAIN);
-		}
+	{
+		printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
+		MOD_DEC_USE_COUNT;
+		return -EAGAIN;
+	}
 
 	/*
 	 * Set current address to factory MAC address
@@ -1416,16 +1384,17 @@
 
 	bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST;	/* skip self-test */
 	if (dfx_adap_init(bp) != DFX_K_SUCCESS)
-		{
-		printk("%s: Adapter open failed!\n", dev->name);
-		return(-EAGAIN);
-		}
+	{
+		printk(KERN_ERR "%s: Adapter open failed!\n", dev->name);
+		free_irq(dev->irq, dev);
+		MOD_DEC_USE_COUNT;
+		return -EAGAIN;
+	}
 
 	/* Set device structure info */
-
 	netif_start_queue(dev);
 	return(0);
-	}
+}
 
 
 /*
@@ -1460,11 +1429,8 @@
  *   routine.
  */
 
-int dfx_close(
-	struct net_device *dev
-	)
-
-	{
+int dfx_close(struct net_device *dev)
+{
 	DFX_board_t	*bp = (DFX_board_t *)dev->priv;
 
 	DBG_printk("In dfx_close...\n");
@@ -1514,8 +1480,10 @@
 	/* Deregister (free) IRQ */
 
 	free_irq(dev->irq, dev);
+	
+	MOD_DEC_USE_COUNT;
 	return(0);
-	}
+}
 
 
 /*
@@ -3491,6 +3459,30 @@
 	bp->cons_block_virt->xmt_rcv_data = prod_cons;
 	return;
 	}
+
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	if(dfx_probe()<0)
+		return -ENODEV;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	while(bp_root!=NULL)
+	{
+		struct net_device *tmp=bp_root;
+		DFX_board_t *priv=tmp->priv;
+		bp_root=priv->next;
+		kfree(tmp->priv);
+		kfree(tmp);
+	}
+}
+
+#endif
 
 
 /*
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/defxx.h linux/drivers/net/defxx.h
--- v2.3.99-pre3/linux/drivers/net/defxx.h	Wed Aug 18 11:36:45 1999
+++ linux/drivers/net/defxx.h	Sun Apr  2 15:38:53 2000
@@ -1756,6 +1756,7 @@
 	/* Store device, bus-specific, and parameter information for this adapter */
 
 	struct net_device			*dev;							/* pointer to device structure */
+	struct net_device			*next;
 	u32						bus_type;						/* bus type (0 == PCI, 1 == EISA) */
 	u16						base_addr;						/* base I/O address (same as dev->base_addr) */
 	struct pci_dev *				pci_dev;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.3.99-pre3/linux/drivers/net/eepro100.c	Sat Feb 26 22:31:46 2000
+++ linux/drivers/net/eepro100.c	Thu Mar 30 18:00:01 2000
@@ -1,9 +1,8 @@
+/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
 /*
-
-	 drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux
-
+   NOTICE: For use with late 2.3 kernels only.
+   May not compile for kernels 2.3.43-47.
 	Written 1996-1999 by Donald Becker.
-	Modified 2000 by Linux Kernel Team
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
@@ -11,8 +10,6 @@
 	This driver is for the Intel EtherExpress Pro100 (Speedo3) design.
 	It should work with all i82557/558/559 boards.
 
-	To use as a module, use the compile-command at the end of the file.
-
 	The author may be reached as becker@CESDIS.usra.edu, or C/O
 	Center of Excellence in Space Data and Information Sciences
 	   Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
@@ -23,14 +20,211 @@
 	There is a Majordomo mailing list based at
 		linux-eepro100@cesdis.gsfc.nasa.gov
 
+	The driver also contains updates by different kernel developers
+	(see incomplete list below).
+	This driver clone is maintained by Andrey V. Savochkin <saw@saw.sw.com.sg>.
+	Please use this email address and linux-kernel mailing list for bug reports.
+
+	Version history:
+	1998 Apr - 2000 Feb  Andrey V. Savochkin <saw@saw.sw.com.sg>
+		Serious fixes for multicast filter list setting, TX timeout routine;
+		RX ring refilling logic;  other stuff
+	2000 Feb  Jeff Garzik <jgarzik@mandrakesoft.com>
+		Convert to new PCI driver interface
+	2000 Mar 24  Dragan Stancevic <visitor@valinux.com>
+		Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
+		Dragan Stancevic <visitor@valinux.com> March 24th, 2000.
+*/
 
+static const char *version =
+"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"
+"eepro100.c: $Revision: 1.29 $ 2000/03/30 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
 
-   Version history:
-   	v1.09j+LK1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
-		Convert to new PCI driver interface
+/* A few user-configurable values that apply to all boards.
+   First set is undocumented and spelled per Intel recommendations. */
+
+static int congenb = 0;		/* Enable congestion control in the DP83840. */
+static int txfifo = 8;		/* Tx FIFO threshold in 4 byte units, 0-15 */
+static int rxfifo = 8;		/* Rx FIFO threshold, default 32 bytes. */
+/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
+static int txdmacount = 128;
+static int rxdmacount = 0;
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
+   Lower values use more memory, but are faster. */
+static int rx_copybreak = 200;
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
+static int multicast_filter_limit = 64;
+
+/* 'options' is used to pass a transceiver override or full-duplex flag
+   e.g. "options=16" for FD, "options=32" for 100mbps-only. */
+static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int debug = -1;			/* The debug level */
 
+/* A few values that may be tweaked. */
+/* The ring sizes should be a power of two for efficiency. */
+#define TX_RING_SIZE	32
+#define RX_RING_SIZE	32
+/* How much slots multicast filter setup may take.
+   Do not descrease without changing set_rx_mode() implementaion. */
+#define TX_MULTICAST_SIZE   2
+#define TX_MULTICAST_RESERV (TX_MULTICAST_SIZE*2)
+/* Actual number of TX packets queued, must be
+   <= TX_RING_SIZE-TX_MULTICAST_RESERV. */
+#define TX_QUEUE_LIMIT  (TX_RING_SIZE-TX_MULTICAST_RESERV)
+/* Hysteresis marking queue as no longer full. */
+#define TX_QUEUE_UNFULL (TX_QUEUE_LIMIT-4)
 
+/* Operational parameters that usually are not changed. */
 
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT		(2*HZ)
+/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
+#define PKT_BUF_SZ		1536
+
+#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>");
+MODULE_DESCRIPTION("Intel i82557/i82558/i82559 PCI EtherExpressPro driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(congenb, "i");
+MODULE_PARM(txfifo, "i");
+MODULE_PARM(rxfifo, "i");
+MODULE_PARM(txdmacount, "i");
+MODULE_PARM(rxdmacount, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(multicast_filter_limit, "i");
+
+#define RUN_AT(x) (jiffies + (x))
+
+/* ACPI power states don't universally work (yet) */
+#ifndef CONFIG_EEPRO100_PM
+#undef pci_set_power_state
+#define pci_set_power_state null_set_power_state
+static inline int null_set_power_state(struct pci_dev *dev, int state)
+{
+	return 0;
+}
+#endif /* CONFIG_EEPRO100_PM */
+
+#ifndef pci_resource_start
+#define pci_resource_start(p, n) (p)->resource[n].start
+#define pci_resource_len(p, n) ((p)->resource[n].end - (p)->resource[n].start)
+#endif
+
+/* Because of changes in this area the driver may not compile for kernels
+   2.3.43 - 2.3.47.  --SAW */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
+#define netif_wake_queue(dev)	do { \
+									clear_bit(0, (void*)&dev->tbusy); \
+									mark_bh(NET_BH); \
+								} while(0)
+#define netif_start_queue(dev)	clear_bit(0, (void*)&dev->tbusy)
+#define netif_stop_queue(dev)	set_bit(0, (void*)&dev->tbusy)
+#define netif_running(dev)		dev->start
+#define netdevice_start(dev)	dev->start = 1
+#define netdevice_stop(dev)		dev->start = 0
+#define netif_set_tx_timeout(dev, tf, tm)
+#define dev_kfree_skb_irq(x)	dev_kfree_skb(x)
+#else
+#define netdevice_start(dev)
+#define netdevice_stop(dev)
+#define netif_set_tx_timeout(dev, tf, tm) \
+								do { \
+									(dev)->tx_timeout = (tf); \
+									(dev)->watchdog_timeo = (tm); \
+								} while(0)
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,47)
+#define netif_device_attach(dev) netif_start_queue(dev)
+#define netif_device_detach(dev) netif_stop_queue(dev)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
+typedef u32 dma_addr_t;
+static void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+								  dma_addr_t *dma_handle)
+{
+	void *ret;
+	ret = kmalloc(size, GFP_ATOMIC);
+	if (ret != NULL) {
+		*dma_handle = virt_to_bus(ret);
+	}
+	return ret;
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+						 void *vaddr, dma_addr_t dma_handle)
+{
+	kfree(vaddr);
+}
+
+#define PCI_DMA_FROMDEVICE 0
+#define PCI_DMA_TODEVICE 0
+
+extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+										size_t size, int direction)
+{
+	return virt_to_bus(ptr);
+}
+
+extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+									size_t size, int direction)
+{
+}
+
+extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+				       dma_addr_t dma_handle,
+				       size_t size, int direction)
+{
+}
+#endif
+
+/* The total I/O port extent of the board.
+   The registers beyond 0x18 only exist on the i82558. */
+#define SPEEDO3_TOTAL_SIZE 0x20
+
+int speedo_debug = 1;
+
+/*
 				Theory of Operation
 
 I. Board Compatibility
@@ -136,24 +330,6 @@
 is non-trivial, and the larger copy might flush the cache of useful data, so
 we pass up the skbuff the packet was received into.
 
-IIID. Synchronization
-The driver runs as two independent, single-threaded flows of control.  One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag.  The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-the 'sp->tx_full' flag.
-
-The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
-we can't avoid the interrupt overhead by having the Tx routine reap the Tx
-stats.)	 After reaping the stats, it marks the queue entry as empty by setting
-the 'base' to zero.	 Iff the 'sp->tx_full' flag is set, it clears both the
-tx_full and tbusy flags.
-
 IV. Notes
 
 Thanks to Steve Williams of Intel for arranging the non-disclosure agreement
@@ -162,120 +338,30 @@
 
 */
 
+static int speedo_found1(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt, int acpi_idle_state);
 
-static const char *version =
-"eepro100.c:v1.09j+LK1.0 Feb 13, 2000  Linux Kernel Team  http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
-
-/* A few user-configurable values that apply to all boards.
-   First set is undocumented and spelled per Intel recommendations. */
-
-static int congenb = 0;		/* Enable congestion control in the DP83840. */
-static int txfifo = 8;		/* Tx FIFO threshold in 4 byte units, 0-15 */
-static int rxfifo = 8;		/* Rx FIFO threshold, default 32 bytes. */
-/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
-static int txdmacount = 128;
-static int rxdmacount = 0;
-
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
-   Lower values use more memory, but are faster. */
-static int rx_copybreak = 200;
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-
-/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
-static int multicast_filter_limit = 64;
-
-/* 'options' is used to pass a transceiver override or full-duplex flag
-   e.g. "options=16" for FD, "options=32" for 100mbps-only. */
-static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int debug = -1;			/* The debug level */
-
-/* A few values that may be tweaked. */
-/* The ring sizes should be a power of two for efficiency. */
-#define TX_RING_SIZE	32		/* Effectively 2 entries fewer. */
-#define RX_RING_SIZE	32
-/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */
-#define TX_QUEUE_LIMIT  12
-
-/* Operational parameters that usually are not changed. */
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (2*HZ)
-/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
-#define PKT_BUF_SZ		1536
-
-#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
-#warning  You must compile this file with the correct options!
-#warning  See the last lines of the source file.
-#error You must compile this driver with "-O".
+#ifdef USE_IO
+#define SPEEDO_IOTYPE   PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1
+#define SPEEDO_SIZE		32
+#else
+#define SPEEDO_IOTYPE   PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR0
+#define SPEEDO_SIZE		0x1000
 #endif
 
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(congenb, "i");
-MODULE_PARM(txfifo, "i");
-MODULE_PARM(rxfifo, "i");
-MODULE_PARM(txdmacount, "i");
-MODULE_PARM(rxdmacount, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(multicast_filter_limit, "i");
-
-#define EEPRO100_MODULE_NAME "eepro100"
-#define PFX EEPRO100_MODULE_NAME ": "
-
-#define RUN_AT(x) (jiffies + (x))
-
-/* ACPI power states don't universally work (yet) */
-#ifndef CONFIG_EEPRO100_PM
-#undef pci_set_power_state
-#define pci_set_power_state null_set_power_state
-static inline int null_set_power_state(struct pci_dev *dev, int state)
-{
-	return 0;
-}
-#endif /* CONFIG_EEPRO100_PM */
-
-
-/* compile-time switch to en/disable slow PIO */
-#undef USE_IO
-
-
-int speedo_debug = 1;
-
-
 enum pci_flags_bit {
 	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
 	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
 
 #ifndef USE_IO
+/* Currently alpha headers define in/out macros.
+   Undefine them.  2000/03/30  SAW */
+#undef inb
+#undef inw
+#undef inl
+#undef outb
+#undef outw
+#undef outl
 #define inb readb
 #define inw readw
 #define inl readl
@@ -284,127 +370,106 @@
 #define outl writel
 #endif
 
-
 /* How to wait for the command unit to accept a command.
    Typically this takes 0 ticks. */
-static inline void wait_for_cmd_done (long cmd_ioaddr)
+static inline void wait_for_cmd_done(long cmd_ioaddr)
 {
-	int wait = 100;
-	do;
-	while (inb (cmd_ioaddr) && --wait >= 0);
+	int wait = 1000;
+	do   ;
+	while(inb(cmd_ioaddr) && --wait >= 0);
 }
 
-
 /* Offsets to the various registers.
    All accesses need not be longword aligned. */
 enum speedo_offsets {
 	SCBStatus = 0, SCBCmd = 2,	/* Rx/Command Unit command and status. */
-	SCBPointer = 4,			/* General purpose pointer. */
-	SCBPort = 8,			/* Misc. commands and operands.  */
-	SCBflash = 12, SCBeeprom = 14, 	/* EEPROM and flash memory control. */
-	SCBCtrlMDI = 16,		/* MDI interface control. */
-	SCBEarlyRx = 20,		/* Early receive byte count. */
+	SCBPointer = 4,				/* General purpose pointer. */
+	SCBPort = 8,				/* Misc. commands and operands.  */
+	SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
+	SCBCtrlMDI = 16,			/* MDI interface control. */
+	SCBEarlyRx = 20,			/* Early receive byte count. */
 };
-
-
 /* Commands that can be put in a command list entry. */
 enum commands {
-	CmdNOp = 0,
-	CmdIASetup = 0x10000,
-	CmdConfigure = 0x20000,
-	CmdMulticastList = 0x30000,
-	CmdTx = 0x40000,
-	CmdTDR = 0x50000,
-	CmdDump = 0x60000,
-	CmdDiagnose = 0x70000,
+	CmdNOp = 0, CmdIASetup = 0x10000, CmdConfigure = 0x20000,
+	CmdMulticastList = 0x30000, CmdTx = 0x40000, CmdTDR = 0x50000,
+	CmdDump = 0x60000, CmdDiagnose = 0x70000,
 	CmdSuspend = 0x40000000,	/* Suspend after completion. */
 	CmdIntr = 0x20000000,		/* Interrupt after completion. */
 	CmdTxFlex = 0x00080000,		/* Use "Flexible mode" for CmdTx command. */
 };
-
-
-/* Do atomically if possible. */
-#if defined(__i386__) || defined(__alpha__) || defined(__ia64__)
-#define clear_suspend(cmd)	clear_bit(30, &(cmd)->cmd_status)
-#elif defined(__powerpc__)
-#define clear_suspend(cmd)	clear_bit(6, &(cmd)->cmd_status)
+/* Clear CmdSuspend (1<<30) avoiding interference with the card access to the
+   status bits.  Previous driver versions used separate 16 bit fields for
+   commands and statuses.  --SAW
+   FIXME: it may not work on non-IA32 architectures.
+ */
+#if defined(__LITTLE_ENDIAN)
+#define clear_suspend(cmd)  ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x4000
+#elif defined(__BIG_ENDIAN)
+#define clear_suspend(cmd)  ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x0040
 #else
-#if 0
-# error You are probably in trouble: clear_suspend() MUST be atomic.
-#endif
-# define clear_suspend(cmd)	(cmd)->cmd_status &= cpu_to_le32(~CmdSuspend)
+#error Unsupported byteorder
 #endif
 
 enum SCBCmdBits {
-	SCBMaskCmdDone = 0x8000,
-	SCBMaskRxDone = 0x4000,
-	SCBMaskCmdIdle = 0x2000,
-	SCBMaskRxSuspend = 0x1000,
-	SCBMaskEarlyRx = 0x0800,
-	SCBMaskFlowCtl = 0x0400,
-	SCBTriggerIntr = 0x0200,
-	SCBMaskAll = 0x0100,
-	/* The rest are Rx and Tx commands. */
-	CUStart = 0x0010,
-	CUResume = 0x0020,
-	CUStatsAddr = 0x0040,
-	CUShowStats = 0x0050,
-	CUCmdBase = 0x0060,	/* CU Base address (set to zero) . */
-	CUDumpStats = 0x0070,	/* Dump then reset stats counters. */
-	RxStart = 0x0001,
-	RxResume = 0x0002,
-	RxAbort = 0x0004,
-	RxAddrLoad = 0x0006,
-	RxResumeNoResources = 0x0007,
+     SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
+     SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
+     SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
+     /* The rest are Rx and Tx commands. */
+     CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050,
+     CUCmdBase=0x0060,  /* CU Base address (set to zero) . */
+     CUDumpStats=0x0070, /* Dump then reset stats counters. */
+     RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
+     RxResumeNoResources=0x0007,
 };
 
 enum SCBPort_cmds {
-	PortReset = 0,
-	PortSelfTest = 1,
-	PortPartialReset = 2,
-	PortDump = 3,
+	PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3,
 };
 
 /* The Speedo3 Rx and Tx frame/buffer descriptors. */
-struct descriptor {		/* A generic descriptor. */
-	s32 cmd_status;		/* All command and status fields. */
-	u32 link;		/* struct descriptor *  */
+struct descriptor {			    /* A generic descriptor. */
+	s32 cmd_status;				/* All command and status fields. */
+	u32 link;				    /* struct descriptor *  */
 	unsigned char params[0];
 };
 
 /* The Speedo3 Rx and Tx buffer descriptors. */
-struct RxFD {			/* Receive frame descriptor. */
+struct RxFD {					/* Receive frame descriptor. */
 	s32 status;
-	u32 link;		/* struct RxFD * */
-	u32 rx_buf_addr;	/* void * */
+	u32 link;					/* struct RxFD * */
+	u32 rx_buf_addr;			/* void * */
 	u32 count;
 };
 
 /* Selected elements of the Tx/RxFD.status word. */
 enum RxFD_bits {
-	RxComplete = 0x8000,
-	RxOK = 0x2000,
-	RxErrCRC = 0x0800,
-	RxErrAlign = 0x0400,
-	RxErrTooBig = 0x0200,
-	RxErrSymbol = 0x0010,
-	RxEth2Type = 0x0020,
-	RxNoMatch = 0x0004,
-	RxNoIAMatch = 0x0002,
-	TxUnderrun = 0x1000,
-	StatusComplete = 0x8000,
+	RxComplete=0x8000, RxOK=0x2000,
+	RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
+	RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
+	TxUnderrun=0x1000,  StatusComplete=0x8000,
 };
 
-struct TxFD {			/* Transmit frame descriptor set. */
+struct TxFD {					/* Transmit frame descriptor set. */
 	s32 status;
-	u32 link;		/* void * */
-	u32 tx_desc_addr;	/* Always points to the tx_buf_addr element. */
-	s32 count;		/* # of TBD (=1), Tx start thresh., etc. */
+	u32 link;					/* void * */
+	u32 tx_desc_addr;			/* Always points to the tx_buf_addr element. */
+	s32 count;					/* # of TBD (=1), Tx start thresh., etc. */
 	/* This constitutes two "TBD" entries -- we only use one. */
-	u32 tx_buf_addr0;	/* void *, frame to be transmitted.  */
-	s32 tx_buf_size0;	/* Length of Tx frame. */
-	u32 tx_buf_addr1;	/* void *, frame to be transmitted.  */
-	s32 tx_buf_size1;	/* Length of Tx frame. */
+#define TX_DESCR_BUF_OFFSET 16
+	u32 tx_buf_addr0;			/* void *, frame to be transmitted.  */
+	s32 tx_buf_size0;			/* Length of Tx frame. */
+	u32 tx_buf_addr1;			/* void *, frame to be transmitted.  */
+	s32 tx_buf_size1;			/* Length of Tx frame. */
+};
+
+/* Multicast filter setting block.  --SAW */
+struct speedo_mc_block {
+	struct speedo_mc_block *next;
+	unsigned int tx;
+	dma_addr_t frame_dma;
+	unsigned int len;
+	struct descriptor frame __attribute__ ((__aligned__(16)));
 };
 
 /* Elements of the dump_statistics block. This block must be lword aligned. */
@@ -428,46 +493,55 @@
 	u32 done_marker;
 };
 
+enum Rx_ring_state_bits {
+	RrNoMem=1, RrPostponed=2, RrNoResources=4, RrOOMReported=8,
+};
+
 /* Do not change the position (alignment) of the first few elements!
-   The later elements are grouped for cache locality. */
+   The later elements are grouped for cache locality.
+
+   Unfortunately, all the positions have been shifted since there.
+   A new re-alignment is required.  2000/03/06  SAW */
 struct speedo_private {
-	struct TxFD *tx_ring;		/* Commands (usually CmdTxPacket). */
+	struct TxFD	*tx_ring;				/* Commands (usually CmdTxPacket). */
 	struct RxFD *rx_ringp[RX_RING_SIZE];/* Rx descriptor, used as ring. */
 	/* The addresses of a Tx/Rx-in-place packets/buffers. */
 	struct sk_buff *tx_skbuff[TX_RING_SIZE];
 	struct sk_buff *rx_skbuff[RX_RING_SIZE];
-	dma_addr_t rx_ring_dma[RX_RING_SIZE];
+	/* Mapped addresses of the rings. */
 	dma_addr_t tx_ring_dma;
-	struct descriptor *last_cmd;	/* Last command sent. */
-	unsigned int cur_tx, dirty_tx;	/* The ring entries to be free()ed. */
-	spinlock_t lock;		/* Group with Tx control cache line. */
-	u32 tx_threshold;		/* The value for txdesc.count. */
-	struct RxFD *last_rxf;		/* Last command sent. */
-	unsigned int cur_rx, dirty_rx;	/* The next free ring entry */
-	long last_rx_time;		/* Last Rx, in jiffies, to handle Rx hang. */
+#define TX_RING_ELEM_DMA(sp, n) ((sp)->tx_ring_dma + (n)*sizeof(struct TxFD))
+	dma_addr_t rx_ring_dma[RX_RING_SIZE];
+	struct descriptor *last_cmd;		/* Last command sent. */
+	unsigned int cur_tx, dirty_tx;		/* The ring entries to be free()ed. */
+	spinlock_t lock;					/* Group with Tx control cache line. */
+	u32 tx_threshold;					/* The value for txdesc.count. */
+	struct RxFD *last_rxf;				/* Last filled RX buffer. */
+	unsigned int cur_rx, dirty_rx;		/* The next free ring entry */
+	long last_rx_time;			/* Last Rx, in jiffies, to handle Rx hang. */
 	const char *product_name;
 	struct enet_statistics stats;
 	struct speedo_stats *lstats;
+	dma_addr_t lstats_dma;
 	int chip_id;
-	unsigned char acpi_pwr;
 	struct pci_dev *pdev;
-	struct timer_list timer;	/* Media selection timer. */
-	int mc_setup_frm_len;		/* The length of an allocated.. */
-	struct descriptor *mc_setup_frm;/* ..multicast setup frame. */
-	int mc_setup_busy;		/* Avoid double-use of setup frame. */
-	dma_addr_t mc_setup_dma;
-	char rx_mode;			/* Current PROMISC/ALLMULTI setting. */
-	unsigned int tx_full:1;		/* The Tx queue is full. */
-	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
-	unsigned int flow_ctrl:1;	/* Use 802.3x flow control. */
-	unsigned int rx_bug:1;		/* Work around receiver hang errata. */
-	unsigned int rx_bug10:1;	/* Receiver might hang at 10mbps. */
-	unsigned int rx_bug100:1;	/* Receiver might hang at 100mbps. */
-	unsigned char default_port:8;	/* Last dev->if_port value. */
-	unsigned short phy[2];		/* PHY media interfaces available. */
-	unsigned short advertising;	/* Current PHY advertised caps. */
-	unsigned short partner;		/* Link partner caps. */
+	struct timer_list timer;			/* Media selection timer. */
+	struct speedo_mc_block *mc_setup_head;/* Multicast setup frame list head. */
+	struct speedo_mc_block *mc_setup_tail;/* Multicast setup frame list tail. */
+	int in_interrupt;					/* Word-aligned dev->interrupt */
+	unsigned char acpi_pwr;
+	char rx_mode;						/* Current PROMISC/ALLMULTI setting. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int flow_ctrl:1;			/* Use 802.3x flow control. */
+	unsigned int rx_bug:1;				/* Work around receiver hang errata. */
+	unsigned char default_port:8;		/* Last dev->if_port value. */
+	unsigned char rx_ring_state;		/* RX ring status flags. */
+	unsigned short phy[2];				/* PHY media interfaces available. */
+	unsigned short advertising;			/* Current PHY advertised caps. */
+	unsigned short partner;				/* Link partner caps. */
 };
+
 /* The parameters for a CmdConfigure operation.
    There are so many options that it would be difficult to document each bit.
    We mostly use the default or recommended settings. */
@@ -479,7 +553,7 @@
 const char i82558_config_cmd[22] = {
 	22, 0x08, 0, 1,  0, 0, 0x22, 0x03,  1, /* 1=Use MII  0=Use AUI */
 	0, 0x2E, 0,  0x60, 0x08, 0x88,
-	0x68, 0, 0x40, 0xf2, 0xBD, 		/* 0xBD->0xFD=Force full-duplex */
+	0x68, 0, 0x40, 0xf2, 0x84,		/* Disable FC */
 	0x31, 0x05, };
 
 /* PHY media interface chips. */
@@ -493,6 +567,12 @@
 static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
 #define EE_READ_CMD		(6)
 
+static int eepro100_init_one(struct pci_dev *pdev,
+		const struct pci_device_id *ent);
+static void eepro100_remove_one (struct pci_dev *pdev);
+static void eepro100_suspend (struct pci_dev *pdev);
+static void eepro100_resume (struct pci_dev *pdev);
+
 static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
 static int mdio_read(long ioaddr, int phy_id, int location);
 static int mdio_write(long ioaddr, int phy_id, int location, int value);
@@ -502,12 +582,15 @@
 static void speedo_init_rx_ring(struct net_device *dev);
 static void speedo_tx_timeout(struct net_device *dev);
 static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void speedo_refill_rx_buffers(struct net_device *dev, int force);
 static int speedo_rx(struct net_device *dev);
+static void speedo_tx_buffer_gc(struct net_device *dev);
 static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static int speedo_close(struct net_device *dev);
 static struct enet_statistics *speedo_get_stats(struct net_device *dev);
 static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void set_rx_mode(struct net_device *dev);
+static void speedo_show_state(struct net_device *dev);
 
 
 
@@ -518,75 +601,104 @@
 						   0x2000, 0x2100, 0x0400, 0x3100};
 #endif
 
+static int __devinit eepro100_init_one (struct pci_dev *pdev,
+		const struct pci_device_id *ent)
+{
+	unsigned long ioaddr;
+	int irq;
+	int acpi_idle_state = 0, pm;
+	static int cards_found = 0;
+
+	static int did_version = 0;			/* Already printed version info. */
+	if (speedo_debug > 0  &&  did_version++ == 0)
+		printk(version);
+
+	if (!request_region(pci_resource_start(pdev, 1),
+			pci_resource_len(pdev, 1), "eepro100")) {
+		printk (KERN_ERR "eepro100: cannot reserve I/O ports\n");
+		goto err_out_none;
+	}
+	if (!request_mem_region(pci_resource_start(pdev, 0),
+			pci_resource_len(pdev, 0), "eepro100")) {
+		printk (KERN_ERR "eepro100: cannot reserve MMIO region\n");
+		goto err_out_free_pio_region;
+	}
+
+	irq = pdev->irq;
+#ifdef USE_IO
+	ioaddr = pci_resource_start(pdev, 1);
+	if (speedo_debug > 2)
+		printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
+			   ioaddr, irq);
+#else
+	ioaddr = (unsigned long)ioremap(pci_resource_start(pdev, 0),
+									pci_resource_len(pdev, 0));
+	if (!ioaddr) {
+		printk (KERN_ERR "eepro100: cannot remap MMIO region %lx @ %lx\n",
+				pci_resource_len(pdev, 0), pci_resource_start(pdev, 0));
+		goto err_out_free_mmio_region;
+	}
+	if (speedo_debug > 2)
+		printk("Found Intel i82557 PCI Speedo, MMIO at %#lx, IRQ %d.\n",
+			   pci_resource_start(pdev, 0), irq);
+#endif
+
+	/* save power state b4 pci_enable_device overwrites it */
+	pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (pm) {
+		u16 pwr_command;
+		pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
+		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
+	}
 
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR "eepro100: Could not enable PCI device\n");
+		goto err_out_free_mmio_region;
+	}
+
+	pci_set_master(pdev);
+
+	if (speedo_found1(pdev, ioaddr, irq, 0, cards_found, acpi_idle_state) == 0)
+		cards_found++;
+	else
+		goto err_out_iounmap;
+
+	return 0;
+
+err_out_iounmap: ;
+#ifndef USE_IO
+	iounmap ((void *)ioaddr);
+#endif
+err_out_free_mmio_region:
+	release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+err_out_free_pio_region:
+	release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+err_out_none:
+	return -ENODEV;
+}
 
-static int __devinit eepro100_init_one (struct pci_dev *pdev,
-				        const struct pci_device_id *ent)
+static int speedo_found1(struct pci_dev *pdev,
+		long ioaddr, int irq, int chip_idx, int card_idx, int acpi_idle_state)
 {
 	struct net_device *dev;
 	struct speedo_private *sp;
-	unsigned char *tx_ring;
-	dma_addr_t tx_ring_dma;
 	const char *product;
 	int i, option;
 	u16 eeprom[0x100];
-	int acpi_idle_state = 0, pm, irq;
-	unsigned long ioaddr;
-	static int card_idx = -1;
-
-	static int did_version = 0;			/* Already printed version info. */
-
-	if (speedo_debug > 0  &&  did_version++ == 0)
-		printk(version);
-
-#ifdef USE_IO
-	ioaddr = pci_resource_start (pdev, 0);
-#else
-	ioaddr = pci_resource_start (pdev, 1);
-#endif
-	irq = pdev->irq;
-
-	card_idx++;
-	
-	if (!request_region (pci_resource_start (pdev, 1),
-			     pci_resource_len (pdev, 1),
-			     EEPRO100_MODULE_NAME)) {
-		printk (KERN_ERR PFX "cannot reserve I/O ports\n");
-		goto err_out_none;
-	}
-	if (!request_mem_region (pci_resource_start (pdev, 0),
-				 pci_resource_len (pdev, 0),
-				 EEPRO100_MODULE_NAME)) {
-		printk (KERN_ERR PFX "cannot reserve MMIO region\n");
-		goto err_out_free_pio_region;
-	}
-	
-#ifndef USE_IO
-	ioaddr = (unsigned long) ioremap (pci_resource_start (pdev, 0),
-					  pci_resource_len (pdev, 0));
-	if (!ioaddr) {
-		printk (KERN_ERR PFX "cannot remap MMIO region %lx @ %lx\n",
-			pci_resource_len (pdev, 0),
-			pci_resource_start (pdev, 0));
-		goto err_out_free_mmio_region;
-	}
-#endif
+	int size;
+	void *tx_ring_space;
+	dma_addr_t tx_ring_dma;
 
-	tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
-					     + sizeof(struct speedo_stats), &tx_ring_dma);
-	if (!tx_ring) {
-		printk(KERN_ERR PFX "Could not allocate DMA memory.\n");
-		goto err_out_iounmap;
-	}
+	size = TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats);
+	tx_ring_space = pci_alloc_consistent(pdev, size, &tx_ring_dma);
+	if (tx_ring_space == NULL)
+		return -1;
 
 	dev = init_etherdev(NULL, sizeof(struct speedo_private));
 	if (dev == NULL) {
-		printk(KERN_ERR PFX "Could not allocate ethernet device.\n");
-		goto err_out_free_tx_ring;
-	}
-	if (dev->priv == NULL) {
-		printk(KERN_ERR PFX "Could not allocate ethernet device private info.\n");
-		goto err_out_free_netdev;
+		printk(KERN_ERR "eepro100: Could not allocate ethernet device.\n");
+		pci_free_consistent(pdev, size, tx_ring_space, tx_ring_dma);
+		return -1;
 	}
 
 	if (dev->mem_start > 0)
@@ -596,21 +708,6 @@
 	else
 		option = 0;
 
-	/* save power state b4 pci_enable_device overwrites it */
-	pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
-	if (pm) {
-		u16 pwr_command;
-		pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
-		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
-	}
-
-	if (pci_enable_device (pdev)) {
-		printk(KERN_ERR PFX "Could not enable PCI device\n");
-		goto err_out_free_netdev;
-	}
-
-	pci_set_master (pdev);
-
 	/* Read the station address EEPROM before doing the reset.
 	   Nominally his should even be done before accepting the device, but
 	   then we wouldn't have a device name with which to report the error.
@@ -655,22 +752,26 @@
 	if (eeprom[3] & 0x0100)
 		product = "OEM i82557/i82558 10/100 Ethernet";
 	else
-		product = "Intel PCI EtherExpress Pro100";
+		product = pdev->name;
 
-	printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
+	printk(KERN_INFO "%s: %s, ", dev->name, product);
 
 	for (i = 0; i < 5; i++)
 		printk("%2.2X:", dev->dev_addr[i]);
-	printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq);
+	printk("%2.2X, ", dev->dev_addr[i]);
+#ifdef USE_IO
+	printk("I/O at %#3lx, ", ioaddr);
+#endif
+	printk("IRQ %d.\n", irq);
 
-#if 1
+#if 1 || defined(kernel_bloat)
 	/* OK, this is pure kernel bloat.  I don't like it when other drivers
 	   waste non-pageable kernel space to emit similar messages, but I need
 	   them for bug reports. */
 	{
 		const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"};
 		/* The self-test results must be paragraph aligned. */
-		volatile s32 *self_test_results = (volatile s32 *)tx_ring;
+		volatile s32 *self_test_results;
 		int boguscnt = 16000;	/* Timeout for set-test. */
 		if (eeprom[3] & 0x03)
 			printk(KERN_INFO "  Receiver lock-up bug exists -- enabling"
@@ -704,7 +805,8 @@
 					   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
 		}
 
-		/* Perform a system self-test. Use the tx_ring consistent DMA mapping for it. */
+		/* Perform a system self-test. */
+		self_test_results = (s32*) ((((long) tx_ring_space) + 15) & ~0xf);
 		self_test_results[0] = 0;
 		self_test_results[1] = -1;
 		outl(tx_ring_dma | PortSelfTest, ioaddr + SCBPort);
@@ -734,7 +836,7 @@
 	outl(PortReset, ioaddr + SCBPort);
 
 	/* Return the chip to its original power state. */
-	pci_set_power_state (pdev, acpi_idle_state);
+	pci_set_power_state(pdev, acpi_idle_state);
 
 	pdev->driver_data = dev;
 
@@ -742,20 +844,18 @@
 	dev->irq = irq;
 
 	sp = dev->priv;
-
 	sp->pdev = pdev;
 	sp->acpi_pwr = acpi_idle_state;
-	sp->tx_ring = (struct TxFD *)tx_ring;
+	sp->tx_ring = tx_ring_space;
 	sp->tx_ring_dma = tx_ring_dma;
 	sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE);
-	
-	sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
+	sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE);
 
+	sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
 	if (card_idx >= 0) {
 		if (full_duplex[card_idx] >= 0)
 			sp->full_duplex = full_duplex[card_idx];
 	}
-
 	sp->default_port = option >= 0 ? (option & 0x0f) : 0;
 
 	sp->phy[0] = eeprom[6];
@@ -768,37 +868,15 @@
 	/* The Speedo-specific entries in the device structure. */
 	dev->open = &speedo_open;
 	dev->hard_start_xmit = &speedo_start_xmit;
-	dev->tx_timeout = &speedo_tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT;
+	netif_set_tx_timeout(dev, &speedo_tx_timeout, TX_TIMEOUT);
 	dev->stop = &speedo_close;
 	dev->get_stats = &speedo_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &speedo_ioctl;
 
 	return 0;
-
-err_out_free_netdev:
-	unregister_netdevice (dev);
-	kfree (dev);
-err_out_free_tx_ring:
-	pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
-				  + sizeof(struct speedo_stats),
-			    tx_ring, tx_ring_dma);
-err_out_iounmap:
-#ifndef USE_IO
-	iounmap ((void *)ioaddr);
-err_out_free_mmio_region:
-#endif
-	release_mem_region (pci_resource_start (pdev, 0),
-			    pci_resource_len (pdev, 0));
-err_out_free_pio_region:
-	release_region (pci_resource_start (pdev, 1),
-			pci_resource_len (pdev, 1));
-err_out_none:
-	return -ENODEV;
 }
-
-
+
 /* Serial EEPROM section.
    A "bit" grungy, but we work our way through bit-by-bit :->. */
 /*  EEPROM_Ctrl bits. */
@@ -887,6 +965,7 @@
 	sp->last_cmd = 0;
 	sp->tx_full = 0;
 	spin_lock_init(&sp->lock);
+	sp->in_interrupt = 0;
 
 	/* .. we can safely take handler calls during init. */
 	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
@@ -896,9 +975,8 @@
 
 	dev->if_port = sp->default_port;
 
-#if 0
-	/* With some transceivers we must retrigger negotiation to reset
-	   power-up errors. */
+#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us
+	/* Retrigger negotiation to reset previous errors. */
 	if ((sp->phy[0] & 0x8000) == 0) {
 		int phy_addr = sp->phy[0] & 0x1f ;
 		/* Use 0x3300 for restarting NWay, other values to force xcvr:
@@ -918,16 +996,17 @@
 	speedo_init_rx_ring(dev);
 
 	/* Fire up the hardware. */
+	outw(SCBMaskAll, ioaddr + SCBCmd);
 	speedo_resume(dev);
 
+	netdevice_start(dev);
 	netif_start_queue(dev);
 
 	/* Setup the chip and configure the multicast list. */
-	sp->mc_setup_frm = NULL;
-	sp->mc_setup_frm_len = 0;
-	sp->mc_setup_busy = 0;
-	sp->rx_mode = -1;			/* Invalid -> always reset the mode. */
+	sp->mc_setup_head = NULL;
+	sp->mc_setup_tail = NULL;
 	sp->flow_ctrl = sp->partner = 0;
+	sp->rx_mode = -1;			/* Invalid -> always reset the mode. */
 	set_rx_mode(dev);
 	if ((sp->phy[0] & 0x8000) == 0)
 		sp->advertising = mdio_read(ioaddr, sp->phy[0] & 0x1f, 4);
@@ -951,6 +1030,7 @@
 	/* No need to wait for the command unit to accept here. */
 	if ((sp->phy[0] & 0x8000) == 0)
 		mdio_read(ioaddr, sp->phy[0] & 0x1f, 0);
+
 	return 0;
 }
 
@@ -960,8 +1040,6 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	outw(SCBMaskAll, ioaddr + SCBCmd);
-
 	/* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */
 	sp->tx_threshold = 0x01208000;
 
@@ -974,42 +1052,45 @@
 	wait_for_cmd_done(ioaddr + SCBCmd);
 
 	/* Load the statistics block and rx ring addresses. */
-	outl(sp->tx_ring_dma + sizeof(struct TxFD) * TX_RING_SIZE, ioaddr + SCBPointer);
+	outl(sp->lstats_dma, ioaddr + SCBPointer);
 	outb(CUStatsAddr, ioaddr + SCBCmd);
 	sp->lstats->done_marker = 0;
 	wait_for_cmd_done(ioaddr + SCBCmd);
 
-	outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
-		 ioaddr + SCBPointer);
-	outb(RxStart, ioaddr + SCBCmd);
-	wait_for_cmd_done(ioaddr + SCBCmd);
+	if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) {
+		if (speedo_debug > 2)
+			printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n",
+					dev->name);
+	} else {
+		outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
+			 ioaddr + SCBPointer);
+		outb(RxStart, ioaddr + SCBCmd);
+		wait_for_cmd_done(ioaddr + SCBCmd);
+	}
 
 	outb(CUDumpStats, ioaddr + SCBCmd);
 
 	/* Fill the first command with our physical address. */
 	{
-		int entry = sp->cur_tx++ % TX_RING_SIZE;
-		struct descriptor *cur_cmd = (struct descriptor *)&sp->tx_ring[entry];
+		struct descriptor *ias_cmd;
 
+		ias_cmd =
+			(struct descriptor *)&sp->tx_ring[sp->cur_tx++ % TX_RING_SIZE];
 		/* Avoid a bug(?!) here by marking the command already completed. */
-		cur_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000);
-		cur_cmd->link =
-			cpu_to_le32(sp->tx_ring_dma + (sp->cur_tx % TX_RING_SIZE)
-						      * sizeof(struct TxFD));
-		memcpy(cur_cmd->params, dev->dev_addr, 6);
-		if (sp->last_cmd)
-			clear_suspend(sp->last_cmd);
-		sp->last_cmd = cur_cmd;
+		ias_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000);
+		ias_cmd->link =
+			cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE));
+		memcpy(ias_cmd->params, dev->dev_addr, 6);
+		sp->last_cmd = ias_cmd;
 	}
 
 	/* Start the chip's Tx process and unmask interrupts. */
 	wait_for_cmd_done(ioaddr + SCBCmd);
-	outl(sp->tx_ring_dma
-	     + (sp->dirty_tx % TX_RING_SIZE) * sizeof(struct TxFD),
+	outl(cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE)),
 		 ioaddr + SCBPointer);
-	outw(CUStart, ioaddr + SCBCmd);
-	
-	netif_start_queue (dev);
+	/* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
+	   remain masked --Dragan */
+	outw(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd);
 }
 
 /* Media monitoring and control. */
@@ -1025,6 +1106,8 @@
 		int partner = mdio_read(ioaddr, phy_num, 5);
 		if (partner != sp->partner) {
 			int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0;
+			if (speedo_debug > 2)
+				printk(KERN_DEBUG "%s: Link status change.\n", dev->name);
 			sp->partner = partner;
 			if (flow_ctrl != sp->flow_ctrl) {
 				sp->flow_ctrl = flow_ctrl;
@@ -1034,12 +1117,11 @@
 			mdio_read(ioaddr, phy_num, 1);
 			/* If link beat has returned... */
 			if (mdio_read(ioaddr, phy_num, 1) & 0x0004)
-				dev->flags |= IFF_RUNNING; 
+				dev->flags |= IFF_RUNNING;
 			else
 				dev->flags &= ~IFF_RUNNING;
 		}
 	}
-
 	if (speedo_debug > 3) {
 		printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
@@ -1049,6 +1131,9 @@
 		/* We haven't received a packet in a Long Time.  We might have been
 		   bitten by the receiver hang bug.  This can be cleared by sending
 		   a set multicast list command. */
+		if (speedo_debug > 2)
+			printk(KERN_DEBUG "%s: Sending a multicast list set command"
+				   " from a timer routine.\n", dev->name);
 		set_rx_mode(dev);
 	}
 	/* We must continue to monitor the media. */
@@ -1066,25 +1151,31 @@
 	/* Print a few items for debugging. */
 	if (speedo_debug > 0) {
 		int i;
-		printk(KERN_DEBUG "%s: Tx ring dump,  Tx queue %d / %d:\n", dev->name,
+		printk(KERN_DEBUG "%s: Tx ring dump,  Tx queue %u / %u:\n", dev->name,
 			   sp->cur_tx, sp->dirty_tx);
 		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(KERN_DEBUG "%s: %c%c%d %8.8x.\n", dev->name,
+			printk(KERN_DEBUG "%s:  %c%c%2d %8.8x.\n", dev->name,
 				   i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ',
 				   i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ',
 				   i, sp->tx_ring[i].status);
 	}
-	printk(KERN_DEBUG "%s:Printing Rx ring (next to receive into %d).\n",
-		   dev->name, sp->cur_rx);
+	printk(KERN_DEBUG "%s: Printing Rx ring"
+		   " (next to receive into %u, dirty index %u).\n",
+		   dev->name, sp->cur_rx, sp->dirty_rx);
 
 	for (i = 0; i < RX_RING_SIZE; i++)
-		printk(KERN_DEBUG "  Rx ring entry %d  %8.8x.\n",
-			   i, (int)sp->rx_ringp[i]->status);
+		printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name,
+			   sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ',
+			   i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ',
+			   i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ',
+			   i, (sp->rx_ringp[i] != NULL) ?
+					   (unsigned)sp->rx_ringp[i]->status : 0);
 
 	for (i = 0; i < 16; i++) {
+		/* FIXME: what does it mean?  --SAW */
 		if (i == 6) i = 21;
-		printk(KERN_DEBUG "  PHY index %d register %d is %4.4x.\n",
-			   phy_num, i, mdio_read(ioaddr, phy_num, i));
+		printk(KERN_DEBUG "%s:  PHY index %d register %d is %4.4x.\n",
+			   dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i));
 	}
 
 }
@@ -1126,55 +1217,124 @@
 	sp->last_rxf = last_rxf;
 }
 
+static void speedo_purge_tx(struct net_device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	int entry;
+
+	while ((int)(sp->cur_tx - sp->dirty_tx) > 0) {
+		entry = sp->dirty_tx % TX_RING_SIZE;
+		if (sp->tx_skbuff[entry]) {
+			sp->stats.tx_errors++;
+			pci_unmap_single(sp->pdev,
+					le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0),
+					sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+			dev_kfree_skb_irq(sp->tx_skbuff[entry]);
+			sp->tx_skbuff[entry] = 0;
+		}
+		sp->dirty_tx++;
+	}
+	while (sp->mc_setup_head != NULL) {
+		struct speedo_mc_block *t;
+		if (speedo_debug > 1)
+			printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
+		pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma,
+				sp->mc_setup_head->len, PCI_DMA_TODEVICE);
+		t = sp->mc_setup_head->next;
+		kfree(sp->mc_setup_head);
+		sp->mc_setup_head = t;
+	}
+	sp->mc_setup_tail = NULL;
+	sp->tx_full = 0;
+	netif_wake_queue(dev);
+}
+
 static void speedo_tx_timeout(struct net_device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int status = inw(ioaddr + SCBStatus);
-
-	/* Trigger a stats dump to give time before the reset. */
-	speedo_get_stats(dev);
+	unsigned long flags;
 
 	printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
 		   " %4.4x at %d/%d command %8.8x.\n",
 		   dev->name, status, inw(ioaddr + SCBCmd),
 		   sp->dirty_tx, sp->cur_tx,
 		   sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
+
+	/* Trigger a stats dump to give time before the reset. */
+	speedo_get_stats(dev);
+
 	speedo_show_state(dev);
+#if 0
 	if ((status & 0x00C0) != 0x0080
 		&&  (status & 0x003C) == 0x0010) {
 		/* Only the command unit has stopped. */
 		printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
 			   dev->name);
-		outl(sp->tx_ring_dma
-		     + (sp->dirty_tx % TX_RING_SIZE) * sizeof(struct TxFD),
+		outl(cpu_to_le32(TX_RING_ELEM_DMA(sp, dirty_tx % TX_RING_SIZE])),
 			 ioaddr + SCBPointer);
 		outw(CUStart, ioaddr + SCBCmd);
 	} else {
+#else
+	{
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
+		start_bh_atomic();
+		/* Ensure that timer routine doesn't run! */
+		del_timer(&sp->timer);
+		end_bh_atomic();
+#else /* LINUX_VERSION_CODE */
+#ifdef __SMP__
+		del_timer_sync(&sp->timer);
+#else /* SMP */
+		del_timer(&sp->timer);
+#endif /* SMP */
+#endif /* LINUX_VERSION_CODE */
 		/* Reset the Tx and Rx units. */
 		outl(PortReset, ioaddr + SCBPort);
-		if (speedo_debug > 0)
-			speedo_show_state(dev);
+		/* We may get spurious interrupts here.  But I don't think that they
+		   may do much harm.  1999/12/09 SAW */
 		udelay(10);
+		/* Disable interrupts. */
+		outw(SCBMaskAll, ioaddr + SCBCmd);
+		synchronize_irq();
+		speedo_tx_buffer_gc(dev);
+		/* Free as much as possible.
+		   It helps to recover from a hang because of out-of-memory.
+		   It also simplifies speedo_resume() in case TX ring is full or
+		   close-to-be full. */
+		speedo_purge_tx(dev);
+		speedo_refill_rx_buffers(dev, 1);
+		spin_lock_irqsave(&sp->lock, flags);
 		speedo_resume(dev);
+		sp->rx_mode = -1;
+		dev->trans_start = jiffies;
+		spin_unlock_irqrestore(&sp->lock, flags);
+		set_rx_mode(dev); /* it takes the spinlock itself --SAW */
+		sp->timer.expires = RUN_AT(2*HZ);
+		add_timer(&sp->timer);
 	}
 	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
 	if ((sp->phy[0] & 0x8000) == 0) {
 		int phy_addr = sp->phy[0] & 0x1f;
+		int advertising = mdio_read(ioaddr, phy_addr, 4);
+		int mii_bmcr = mdio_read(ioaddr, phy_addr, 0);
 		mdio_write(ioaddr, phy_addr, 0, 0x0400);
 		mdio_write(ioaddr, phy_addr, 1, 0x0000);
 		mdio_write(ioaddr, phy_addr, 4, 0x0000);
 		mdio_write(ioaddr, phy_addr, 0, 0x8000);
 #ifdef honor_default_port
 		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+#else
+		mdio_read(ioaddr, phy_addr, 0);
+		mdio_write(ioaddr, phy_addr, 0, mii_bmcr);
+		mdio_write(ioaddr, phy_addr, 4, advertising);
 #endif
 	}
-	sp->stats.tx_errors++;
-	dev->trans_start = jiffies;
-	netif_start_queue (dev);
+	return;
 }
 
-
 static int
 speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -1182,58 +1342,141 @@
 	long ioaddr = dev->base_addr;
 	int entry;
 
-	/* Caution: the write order is important here, set the base address
-	   with the "ownership" bits last. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
+	if (test_bit(0, (void*)&dev->tbusy) != 0) {
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < TX_TIMEOUT - 2)
+			return 1;
+		if (tickssofar < TX_TIMEOUT) {
+			/* Reap sent packets from the full Tx queue. */
+			unsigned long flags;
+			spin_lock_irqsave(&sp->lock, flags);
+			wait_for_cmd_done(ioaddr + SCBCmd);
+			outw(SCBTriggerIntr, ioaddr + SCBCmd);
+			spin_unlock_irqrestore(&sp->lock, flags);
+			return 1;
+		}
+		speedo_tx_timeout(dev);
+		return 1;
+	}
+#endif
 
 	{	/* Prevent interrupts from changing the Tx ring from underneath us. */
 		unsigned long flags;
 
 		spin_lock_irqsave(&sp->lock, flags);
+
+		/* Check if there are enough space. */
+		if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
+			printk(KERN_ERR "%s: incorrect tbusy state, fixed.\n", dev->name);
+			netif_stop_queue(dev);
+			sp->tx_full = 1;
+			spin_unlock_irqrestore(&sp->lock, flags);
+			return 1;
+		}
+
 		/* Calculate the Tx descriptor entry. */
 		entry = sp->cur_tx++ % TX_RING_SIZE;
 
 		sp->tx_skbuff[entry] = skb;
-		/* Todo: be a little more clever about setting the interrupt bit. */
 		sp->tx_ring[entry].status =
 			cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex);
+		if (!(entry & ((TX_RING_SIZE>>2)-1)))
+			sp->tx_ring[entry].status |= cpu_to_le32(CmdIntr);
 		sp->tx_ring[entry].link =
-			cpu_to_le32(sp->tx_ring_dma
-				    + (sp->cur_tx % TX_RING_SIZE)
-				    * sizeof(struct TxFD));
+			cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE));
 		sp->tx_ring[entry].tx_desc_addr =
-			cpu_to_le32(sp->tx_ring_dma
-				    + ((long)&sp->tx_ring[entry].tx_buf_addr0
-				       - (long)sp->tx_ring));
+			cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE) +
+					    TX_DESCR_BUF_OFFSET);
 		/* The data region is always in one buffer descriptor. */
 		sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold);
 		sp->tx_ring[entry].tx_buf_addr0 =
 			cpu_to_le32(pci_map_single(sp->pdev, skb->data,
 						   skb->len, PCI_DMA_TODEVICE));
 		sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len);
-		/* Todo: perhaps leave the interrupt bit set if the Tx queue is more
-		   than half full.  Argument against: we should be receiving packets
-		   and scavenging the queue.  Argument for: if so, it shouldn't
-		   matter. */
 		/* Trigger the command unit resume. */
-		{
-			struct descriptor *last_cmd = sp->last_cmd;
-			sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
-			last_cmd->cmd_status &= cpu_to_le32(~(CmdSuspend | CmdIntr));
-		}
-		if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) {
+		wait_for_cmd_done(ioaddr + SCBCmd);
+		clear_suspend(sp->last_cmd);
+		/* We want the time window between clearing suspend flag on the previous
+		   command and resuming CU to be as small as possible.
+		   Interrupts in between are very undesired.  --SAW */
+		outb(CUResume, ioaddr + SCBCmd);
+		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+
+		/* Leave room for set_rx_mode(). If there is no more space than reserved
+		   for multicast filter mark the ring as full. */
+		if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
+			netif_stop_queue(dev);
 			sp->tx_full = 1;
-			netif_stop_queue (dev);
 		}
+
 		spin_unlock_irqrestore(&sp->lock, flags);
 	}
 
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outw(CUResume, ioaddr + SCBCmd);
 	dev->trans_start = jiffies;
-	
+
 	return 0;
 }
 
+static void speedo_tx_buffer_gc(struct net_device *dev)
+{
+	unsigned int dirty_tx;
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+
+	dirty_tx = sp->dirty_tx;
+	while ((int)(sp->cur_tx - dirty_tx) > 0) {
+		int entry = dirty_tx % TX_RING_SIZE;
+		int status = le32_to_cpu(sp->tx_ring[entry].status);
+
+		if (speedo_debug > 5)
+			printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
+				   entry, status);
+		if ((status & StatusComplete) == 0)
+			break;			/* It still hasn't been processed. */
+		if (status & TxUnderrun)
+			if (sp->tx_threshold < 0x01e08000) {
+				if (speedo_debug > 2)
+					printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n",
+						   dev->name);
+				sp->tx_threshold += 0x00040000;
+			}
+		/* Free the original skb. */
+		if (sp->tx_skbuff[entry]) {
+			sp->stats.tx_packets++;	/* Count only user packets. */
+			sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
+			pci_unmap_single(sp->pdev,
+					le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0),
+					sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+			dev_kfree_skb_irq(sp->tx_skbuff[entry]);
+			sp->tx_skbuff[entry] = 0;
+		}
+		dirty_tx++;
+	}
+
+	if (speedo_debug && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) {
+		printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
+			   " full=%d.\n",
+			   dirty_tx, sp->cur_tx, sp->tx_full);
+		dirty_tx += TX_RING_SIZE;
+	}
+
+	while (sp->mc_setup_head != NULL
+		   && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) {
+		struct speedo_mc_block *t;
+		if (speedo_debug > 1)
+			printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
+		pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma,
+				sp->mc_setup_head->len, PCI_DMA_TODEVICE);
+		t = sp->mc_setup_head->next;
+		kfree(sp->mc_setup_head);
+		sp->mc_setup_head = t;
+	}
+	if (sp->mc_setup_head == NULL)
+		sp->mc_setup_tail = NULL;
+
+	sp->dirty_tx = dirty_tx;
+}
+
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
@@ -1253,11 +1496,21 @@
 	ioaddr = dev->base_addr;
 	sp = (struct speedo_private *)dev->priv;
 
-	spin_lock (&sp->lock);
+#ifndef final_version
+	/* A lock to prevent simultaneous entry on SMP machines. */
+	if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
+		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+			   dev->name);
+		sp->in_interrupt = 0;	/* Avoid halting machine. */
+		return;
+	}
+#endif
 
 	do {
 		status = inw(ioaddr + SCBStatus);
 		/* Acknowledge all of the current interrupt sources ASAP. */
+		/* Will change from 0xfc00 to 0xff00 when we start handling
+		   FCP and ER interrupts --Dragan */
 		outw(status & 0xfc00, ioaddr + SCBStatus);
 
 		if (speedo_debug > 4)
@@ -1267,90 +1520,194 @@
 		if ((status & 0xfc00) == 0)
 			break;
 
-		if (status & 0x4000)	 /* Packet received. */
+		/* Always check if all rx buffers are allocated.  --SAW */
+		speedo_refill_rx_buffers(dev, 0);
+
+		if ((status & 0x5000) ||	/* Packet received, or Rx error. */
+			(sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed)
+									/* Need to gather the postponed packet. */
 			speedo_rx(dev);
 
 		if (status & 0x1000) {
-			if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */
-				outw(RxResumeNoResources, ioaddr + SCBCmd);
-			else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */
-				/* No idea of what went wrong.  Restart the receiver. */
-				outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
-					 ioaddr + SCBPointer);
-				outw(RxStart, ioaddr + SCBCmd);
+			spin_lock(&sp->lock);
+			if ((status & 0x003c) == 0x0028) {		/* No more Rx buffers. */
+				struct RxFD *rxf;
+				printk(KERN_WARNING "%s: card reports no RX buffers.\n",
+						dev->name);
+				rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
+				if (rxf == NULL) {
+					if (speedo_debug > 2)
+						printk(KERN_DEBUG
+								"%s: NULL cur_rx in speedo_interrupt().\n",
+								dev->name);
+					sp->rx_ring_state |= RrNoMem|RrNoResources;
+				} else if (rxf == sp->last_rxf) {
+					if (speedo_debug > 2)
+						printk(KERN_DEBUG
+								"%s: cur_rx is last in speedo_interrupt().\n",
+								dev->name);
+					sp->rx_ring_state |= RrNoMem|RrNoResources;
+				} else
+					outb(RxResumeNoResources, ioaddr + SCBCmd);
+			} else if ((status & 0x003c) == 0x0008) { /* No resources. */
+				struct RxFD *rxf;
+				printk(KERN_WARNING "%s: card reports no resources.\n",
+						dev->name);
+				rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
+				if (rxf == NULL) {
+					if (speedo_debug > 2)
+						printk(KERN_DEBUG
+								"%s: NULL cur_rx in speedo_interrupt().\n",
+								dev->name);
+					sp->rx_ring_state |= RrNoMem|RrNoResources;
+				} else if (rxf == sp->last_rxf) {
+					if (speedo_debug > 2)
+						printk(KERN_DEBUG
+								"%s: cur_rx is last in speedo_interrupt().\n",
+								dev->name);
+					sp->rx_ring_state |= RrNoMem|RrNoResources;
+				} else {
+					/* Restart the receiver. */
+					outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
+						 ioaddr + SCBPointer);
+					outb(RxStart, ioaddr + SCBCmd);
+				}
 			}
 			sp->stats.rx_errors++;
+			spin_unlock(&sp->lock);
+		}
+
+		if ((sp->rx_ring_state&(RrNoMem|RrNoResources)) == RrNoResources) {
+			printk(KERN_WARNING
+					"%s: restart the receiver after a possible hang.\n",
+					dev->name);
+			spin_lock(&sp->lock);
+			/* Restart the receiver.
+			   I'm not sure if it's always right to restart the receiver
+			   here but I don't know another way to prevent receiver hangs.
+			   1999/12/25 SAW */
+			outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
+				 ioaddr + SCBPointer);
+			outb(RxStart, ioaddr + SCBCmd);
+			sp->rx_ring_state &= ~RrNoResources;
+			spin_unlock(&sp->lock);
 		}
 
 		/* User interrupt, Command/Tx unit interrupt or CU not active. */
 		if (status & 0xA400) {
-			unsigned int dirty_tx;
-
-			dirty_tx = sp->dirty_tx;
-			while (sp->cur_tx - dirty_tx > 0) {
-				int entry = dirty_tx % TX_RING_SIZE;
-				int status = le32_to_cpu(sp->tx_ring[entry].status);
-
-				if (speedo_debug > 5)
-					printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
-						   entry, status);
-				if ((status & StatusComplete) == 0)
-					break;			/* It still hasn't been processed. */
-				if (status & TxUnderrun)
-					if (sp->tx_threshold < 0x01e08000)
-						sp->tx_threshold += 0x00040000;
-				/* Free the original skb. */
-				if (sp->tx_skbuff[entry]) {
-					sp->stats.tx_packets++;	/* Count only user packets. */
-					sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
-					pci_unmap_single(sp->pdev,
-							 le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0),
-							 sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
-					dev_kfree_skb_irq(sp->tx_skbuff[entry]);
-					sp->tx_skbuff[entry] = 0;
-				} else if ((status & 0x70000) == CmdNOp) {
-					if (sp->mc_setup_busy)
-						pci_unmap_single(sp->pdev,
-								 sp->mc_setup_dma,
-								 sp->mc_setup_frm_len,
-								 PCI_DMA_TODEVICE);
-					sp->mc_setup_busy = 0;
-				}
-				dirty_tx++;
-			}
-
-#ifndef final_version
-			if (sp->cur_tx - dirty_tx > TX_RING_SIZE) {
-				printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
-					   " full=%d.\n",
-					   dirty_tx, sp->cur_tx, sp->tx_full);
-				dirty_tx += TX_RING_SIZE;
-			}
-#endif
-
-			sp->dirty_tx = dirty_tx;
+			spin_lock(&sp->lock);
+			speedo_tx_buffer_gc(dev);
 			if (sp->tx_full
-				&&  sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) {
-				/* The ring is no longer full, clear tbusy. */
+				&& (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) {
+				/* The ring is no longer full. */
 				sp->tx_full = 0;
-				netif_wake_queue (dev);
+				netif_wake_queue(dev); /* Attention: under a spinlock.  --SAW */
 			}
+			spin_unlock(&sp->lock);
 		}
 
-	} while (--boguscnt > 0);
-
-	if (boguscnt <= 0) {
-		printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
-			   dev->name, status);
-		/* Clear all interrupt sources. */
-		outl(0xfc00, ioaddr + SCBStatus);
-	}
+		if (--boguscnt < 0) {
+			printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
+				   dev->name, status);
+			/* Clear all interrupt sources. */
+			/* Will change from 0xfc00 to 0xff00 when we start handling
+			   FCP and ER interrupts --Dragan */
+			outl(0xfc00, ioaddr + SCBStatus);
+			break;
+		}
+	} while (1);
 
 	if (speedo_debug > 3)
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 
-	spin_unlock (&sp->lock);
+	clear_bit(0, (void*)&sp->in_interrupt);
+	return;
+}
+
+static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct RxFD *rxf;
+	struct sk_buff *skb;
+	/* Get a fresh skbuff to replace the consumed one. */
+	skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+	sp->rx_skbuff[entry] = skb;
+	if (skb == NULL) {
+		sp->rx_ringp[entry] = NULL;
+		return NULL;
+	}
+	rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
+	sp->rx_ring_dma[entry] =
+		pci_map_single(sp->pdev, rxf,
+					   PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+	skb->dev = dev;
+	skb_reserve(skb, sizeof(struct RxFD));
+	rxf->rx_buf_addr = 0xffffffff;
+	return rxf;
+}
+
+static inline void speedo_rx_link(struct net_device *dev, int entry,
+								  struct RxFD *rxf, dma_addr_t rxf_dma)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	rxf->status = cpu_to_le32(0xC0000001); 	/* '1' for driver use only. */
+	rxf->link = 0;			/* None yet. */
+	rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
+	sp->last_rxf->link = cpu_to_le32(rxf_dma);
+	sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
+	sp->last_rxf = rxf;
+}
+
+static int speedo_refill_rx_buf(struct net_device *dev, int force)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	int entry;
+	struct RxFD *rxf;
+
+	entry = sp->dirty_rx % RX_RING_SIZE;
+	if (sp->rx_skbuff[entry] == NULL) {
+		rxf = speedo_rx_alloc(dev, entry);
+		if (rxf == NULL) {
+			unsigned int forw;
+			int forw_entry;
+			if (speedo_debug > 2 || !(sp->rx_ring_state & RrOOMReported)) {
+				printk(KERN_WARNING "%s: can't fill rx buffer (force %d)!\n",
+						dev->name, force);
+				speedo_show_state(dev);
+				sp->rx_ring_state |= RrOOMReported;
+			}
+			if (!force)
+				return -1;	/* Better luck next time!  */
+			/* Borrow an skb from one of next entries. */
+			for (forw = sp->dirty_rx + 1; forw != sp->cur_rx; forw++)
+				if (sp->rx_skbuff[forw % RX_RING_SIZE] != NULL)
+					break;
+			if (forw == sp->cur_rx)
+				return -1;
+			forw_entry = forw % RX_RING_SIZE;
+			sp->rx_skbuff[entry] = sp->rx_skbuff[forw_entry];
+			sp->rx_skbuff[forw_entry] = NULL;
+			rxf = sp->rx_ringp[forw_entry];
+			sp->rx_ringp[forw_entry] = NULL;
+			sp->rx_ringp[entry] = rxf;
+		}
+	} else {
+		rxf = sp->rx_ringp[entry];
+	}
+	speedo_rx_link(dev, entry, rxf, sp->rx_ring_dma[entry]);
+	sp->dirty_rx++;
+	sp->rx_ring_state &= ~(RrNoMem|RrOOMReported); /* Mark the progress. */
+	return 0;
+}
+
+static void speedo_refill_rx_buffers(struct net_device *dev, int force)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+
+	/* Refill the RX ring. */
+	while ((int)(sp->cur_rx - sp->dirty_rx) > 0 &&
+			speedo_refill_rx_buf(dev, force) != -1);
 }
 
 static int
@@ -1360,6 +1717,7 @@
 	int entry = sp->cur_rx % RX_RING_SIZE;
 	int status;
 	int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
+	int alloc_ok = 1;
 
 	if (speedo_debug > 4)
 		printk(KERN_DEBUG " In speedo_rx().\n");
@@ -1370,6 +1728,19 @@
 
 		if (--rx_work_limit < 0)
 			break;
+
+		/* Check for a rare out-of-memory case: the current buffer is
+		   the last buffer allocated in the RX ring.  --SAW */
+		if (sp->last_rxf == sp->rx_ringp[entry]) {
+			/* Postpone the packet.  It'll be reaped at an interrupt when this
+			   packet is no longer the last packet in the ring. */
+			if (speedo_debug > 2)
+				printk(KERN_DEBUG "%s: RX packet postponed!\n",
+					   dev->name);
+			sp->rx_ring_state |= RrPostponed;
+			break;
+		}
+
 		if (speedo_debug > 4)
 			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,
 				   pkt_len);
@@ -1377,11 +1748,12 @@
 			if (status & RxErrTooBig)
 				printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
 					   "status %8.8x!\n", dev->name, status);
-			else if ( ! (status & RxOK)) {
+			else if (! (status & RxOK)) {
 				/* There was a fatal error.  This *should* be impossible. */
 				sp->stats.rx_errors++;
 				printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "
-					   "status %8.8x.\n", dev->name, status);
+					   "status %8.8x.\n",
+					   dev->name, status);
 			}
 		} else {
 			struct sk_buff *skb;
@@ -1394,7 +1766,7 @@
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
-						    PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+						PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
 #if 1 || USE_IP_CSUM
 				/* Packet is in one chunk -- we can copy + cksum. */
 				eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0);
@@ -1416,7 +1788,7 @@
 				temp = skb_put(skb, pkt_len);
 				sp->rx_ringp[entry] = NULL;
 				pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry],
-						 PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+						PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
@@ -1424,40 +1796,18 @@
 			sp->stats.rx_bytes += pkt_len;
 		}
 		entry = (++sp->cur_rx) % RX_RING_SIZE;
+		sp->rx_ring_state &= ~RrPostponed;
+		/* Refill the recently taken buffers.
+		   Do it one-by-one to handle traffic bursts better. */
+		if (alloc_ok && speedo_refill_rx_buf(dev, 0) == -1)
+			alloc_ok = 0;
 	}
 
-	/* Refill the Rx ring buffers. */
-	for (; sp->cur_rx - sp->dirty_rx > 0; sp->dirty_rx++) {
-		struct RxFD *rxf;
-		entry = sp->dirty_rx % RX_RING_SIZE;
-		if (sp->rx_skbuff[entry] == NULL) {
-			struct sk_buff *skb;
-			/* Get a fresh skbuff to replace the consumed one. */
-			skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-			sp->rx_skbuff[entry] = skb;
-			if (skb == NULL) {
-				sp->rx_ringp[entry] = NULL;
-				break;			/* Better luck next time!  */
-			}
-			rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
-			sp->rx_ring_dma[entry] =
-				pci_map_single(sp->pdev, rxf, PKT_BUF_SZ
-					       + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
-			skb->dev = dev;
-			skb_reserve(skb, sizeof(struct RxFD));
-			rxf->rx_buf_addr = 0xffffffff;
-		} else {
-			rxf = sp->rx_ringp[entry];
-		}
-		rxf->status = cpu_to_le32(0xC0000001); 	/* '1' for driver use only. */
-		rxf->link = 0;			/* None yet. */
-		rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
-		sp->last_rxf->link = cpu_to_le32(sp->rx_ring_dma[entry]);
-		sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
-		sp->last_rxf = rxf;
-	}
+	/* Try hard to refill the recently taken buffers. */
+	speedo_refill_rx_buffers(dev, 1);
 
 	sp->last_rx_time = jiffies;
+
 	return 0;
 }
 
@@ -1468,6 +1818,7 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	int i;
 
+	netdevice_stop(dev);
 	netif_stop_queue(dev);
 
 	if (speedo_debug > 1)
@@ -1477,13 +1828,16 @@
 	/* Shut off the media monitoring timer. */
 	del_timer(&sp->timer);
 
-	/* Disable interrupts, and stop the chip's Rx process. */
-	outw(SCBMaskAll, ioaddr + SCBCmd);
-	outw(SCBMaskAll | RxAbort, ioaddr + SCBCmd);
+	/* Shutting down the chip nicely fails to disable flow control. So.. */
+	outl(PortPartialReset, ioaddr + SCBPort);
 
 	free_irq(dev->irq, dev);
 
-	/* Free all the skbuffs in the Rx and Tx queues. */
+	/* Print a few items for debugging. */
+	if (speedo_debug > 3)
+		speedo_show_state(dev);
+
+    /* Free all the skbuffs in the Rx and Tx queues. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb = sp->rx_skbuff[i];
 		sp->rx_skbuff[i] = 0;
@@ -1499,7 +1853,6 @@
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		struct sk_buff *skb = sp->tx_skbuff[i];
 		sp->tx_skbuff[i] = 0;
-
 		/* Clear the Tx descriptors. */
 		if (skb) {
 			pci_unmap_single(sp->pdev,
@@ -1508,17 +1861,19 @@
 			dev_kfree_skb(skb);
 		}
 	}
-	if (sp->mc_setup_frm) {
-		kfree(sp->mc_setup_frm);
-		sp->mc_setup_frm_len = 0;
-	}
 
-	/* Print a few items for debugging. */
-	if (speedo_debug > 3)
-		speedo_show_state(dev);
+	/* Free multicast setting blocks. */
+	for (i = 0; sp->mc_setup_head != NULL; i++) {
+		struct speedo_mc_block *t;
+		t = sp->mc_setup_head->next;
+		kfree(sp->mc_setup_head);
+		sp->mc_setup_head = t;
+	}
+	sp->mc_setup_tail = NULL;
+	if (speedo_debug > 0)
+		printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i);
 
-	/* Alt: acpi_set_pwr_state(pci_bus, pci_devfn, sp->acpi_pwr); */
-	pci_set_power_state (sp->pdev, 2);
+	pci_set_power_state(sp->pdev, 2);
 
 	MOD_DEC_USE_COUNT;
 
@@ -1558,8 +1913,13 @@
 		sp->stats.rx_length_errors += le32_to_cpu(sp->lstats->rx_runt_errs);
 		sp->lstats->done_marker = 0x0000;
 		if (netif_running(dev)) {
+			unsigned long flags;
+			/* Take a spinlock to make wait_for_cmd_done and sending the
+			 * command atomic.  --SAW */
+			spin_lock_irqsave(&sp->lock, flags);
 			wait_for_cmd_done(ioaddr + SCBCmd);
-			outw(CUDumpStats, ioaddr + SCBCmd);
+			outb(CUDumpStats, ioaddr + SCBCmd);
+			spin_unlock_irqrestore(&sp->lock, flags);
 		}
 	}
 	return &sp->stats;
@@ -1577,9 +1937,11 @@
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = phy;
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-		saved_acpi = pci_set_power_state (sp->pdev, 0);
-		data[3] = mdio_read (ioaddr, data[0], data[1]);
-		pci_set_power_state (sp->pdev, saved_acpi);
+		/* FIXME: these operations probably need to be serialized with MDIO
+		   access from the timer routine and timeout handler.  2000/03/08 SAW */
+		saved_acpi = pci_set_power_state(sp->pdev, 0);
+		data[3] = mdio_read(ioaddr, data[0], data[1]);
+		pci_set_power_state(sp->pdev, saved_acpi);
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 		if (!capable(CAP_NET_ADMIN))
@@ -1619,9 +1981,13 @@
 	} else
 		new_rx_mode = 0;
 
-	if (sp->cur_tx - sp->dirty_tx >= TX_RING_SIZE - 1) {
-	  /* The Tx ring is full -- don't add anything!  Presumably the new mode
-		 is in config_cmd_data and will be added anyway. */
+	if (speedo_debug > 3)
+		printk(KERN_DEBUG "%s: set_rx_mode %d -> %d\n", dev->name,
+				sp->rx_mode, new_rx_mode);
+
+	if ((int)(sp->cur_tx - sp->dirty_tx) > TX_RING_SIZE - TX_MULTICAST_SIZE) {
+	    /* The Tx ring is full -- don't add anything!  Hope the mode will be
+		 * set again later. */
 		sp->rx_mode = -1;
 		return;
 	}
@@ -1637,8 +2003,7 @@
 		sp->tx_skbuff[entry] = 0;			/* Redundant. */
 		sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdConfigure);
 		sp->tx_ring[entry].link =
-			cpu_to_le32(sp->tx_ring_dma + ((entry + 1) % TX_RING_SIZE)
-				    * sizeof(struct TxFD));
+			cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
 		config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr;
 		/* Construct a full CmdConfig frame. */
 		memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd));
@@ -1646,7 +2011,10 @@
 		config_cmd_data[4] = rxdmacount;
 		config_cmd_data[5] = txdmacount + 0x80;
 		config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
-		config_cmd_data[19] = sp->flow_ctrl ? 0xBD : 0x80;
+		/* 0x80 doesn't disable FC 0x84 does.
+		   Disable Flow control since we are not ACK-ing any FC interrupts
+		   for now. --Dragan */
+		config_cmd_data[19] = 0x84;
 		config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
 		config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
 		if (sp->phy[0] & 0x8000) {			/* Use the AUI port instead. */
@@ -1656,7 +2024,11 @@
 		/* Trigger the command unit resume. */
 		wait_for_cmd_done(ioaddr + SCBCmd);
 		clear_suspend(last_cmd);
-		outw(CUResume, ioaddr + SCBCmd);
+		outb(CUResume, ioaddr + SCBCmd);
+		if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
+			netif_stop_queue(dev);
+			sp->tx_full = 1;
+		}
 		spin_unlock_irqrestore(&sp->lock, flags);
 	}
 
@@ -1674,8 +2046,7 @@
 		sp->tx_skbuff[entry] = 0;
 		sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdMulticastList);
 		sp->tx_ring[entry].link =
-			cpu_to_le32(sp->tx_ring_dma + ((entry + 1) % TX_RING_SIZE)
-				    * sizeof(struct TxFD));
+			cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
 		sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
 		setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr;
 		*setup_params++ = cpu_to_le16(dev->mc_count*6);
@@ -1691,40 +2062,39 @@
 		wait_for_cmd_done(ioaddr + SCBCmd);
 		clear_suspend(last_cmd);
 		/* Immediately trigger the command unit resume. */
-		outw(CUResume, ioaddr + SCBCmd);
+		outb(CUResume, ioaddr + SCBCmd);
+
+		if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
+			netif_stop_queue(dev);
+			sp->tx_full = 1;
+		}
 		spin_unlock_irqrestore(&sp->lock, flags);
 	} else if (new_rx_mode == 0) {
 		struct dev_mc_list *mclist;
 		u16 *setup_params, *eaddrs;
-		struct descriptor *mc_setup_frm = sp->mc_setup_frm;
+		struct speedo_mc_block *mc_blk;
+		struct descriptor *mc_setup_frm;
 		int i;
 
-		/* If we are busy, someone might be quickly adding to the MC list.
-		   Try again later when the list updates stop. */
-		if (sp->mc_setup_busy) {
-			sp->rx_mode = -1;
+		mc_blk = kmalloc(sizeof(*mc_blk) + 2 + multicast_filter_limit*6,
+						 GFP_ATOMIC);
+		if (mc_blk == NULL) {
+			printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
+				   dev->name);
+			sp->rx_mode = -1; /* We failed, try again. */
 			return;
 		}
-		if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
-			|| sp->mc_setup_frm == NULL) {
-			/* Allocate a full setup frame, 10bytes + <max addrs>. */
-			if (sp->mc_setup_frm)
-				kfree(sp->mc_setup_frm);
-			sp->mc_setup_frm_len = 10 + multicast_filter_limit*6;
-			sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC);
-			if (sp->mc_setup_frm == NULL) {
-				printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
-					   dev->name);
-				sp->rx_mode = -1; /* We failed, try again. */
-				return;
-			}
-		}
-		mc_setup_frm = sp->mc_setup_frm;
+		mc_blk->next = NULL;
+		mc_blk->len = 2 + multicast_filter_limit*6;
+		mc_blk->frame_dma =
+			pci_map_single(sp->pdev, &mc_blk->frame, mc_blk->len,
+					PCI_DMA_TODEVICE);
+		mc_setup_frm = &mc_blk->frame;
+
 		/* Fill the setup frame. */
 		if (speedo_debug > 1)
-			printk(KERN_DEBUG "%s: Constructing a setup frame at %p, "
-				   "%d bytes.\n",
-				   dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len);
+			printk(KERN_DEBUG "%s: Constructing a setup frame at %p.\n",
+				   dev->name, mc_setup_frm);
 		mc_setup_frm->cmd_status =
 			cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList);
 		/* Link set below. */
@@ -1741,27 +2111,38 @@
 
 		/* Disable interrupts while playing with the Tx Cmd list. */
 		spin_lock_irqsave(&sp->lock, flags);
+
+		if (sp->mc_setup_tail)
+			sp->mc_setup_tail->next = mc_blk;
+		else
+			sp->mc_setup_head = mc_blk;
+		sp->mc_setup_tail = mc_blk;
+		mc_blk->tx = sp->cur_tx;
+
 		entry = sp->cur_tx++ % TX_RING_SIZE;
 		last_cmd = sp->last_cmd;
 		sp->last_cmd = mc_setup_frm;
-		sp->mc_setup_busy = 1;
 
 		/* Change the command to a NoOp, pointing to the CmdMulti command. */
 		sp->tx_skbuff[entry] = 0;
 		sp->tx_ring[entry].status = cpu_to_le32(CmdNOp);
-		sp->mc_setup_dma = pci_map_single(sp->pdev, mc_setup_frm, sp->mc_setup_frm_len, PCI_DMA_TODEVICE);
-		sp->tx_ring[entry].link = cpu_to_le32(sp->mc_setup_dma);
+		sp->tx_ring[entry].link = cpu_to_le32(mc_blk->frame_dma);
 
 		/* Set the link in the setup frame. */
 		mc_setup_frm->link =
-			cpu_to_le32(sp->tx_ring_dma + ((entry + 1) % TX_RING_SIZE)
-				    * sizeof(struct TxFD));
+			cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
 
 		wait_for_cmd_done(ioaddr + SCBCmd);
 		clear_suspend(last_cmd);
 		/* Immediately trigger the command unit resume. */
-		outw(CUResume, ioaddr + SCBCmd);
+		outb(CUResume, ioaddr + SCBCmd);
+
+		if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
+			netif_stop_queue(dev);
+			sp->tx_full = 1;
+		}
 		spin_unlock_irqrestore(&sp->lock, flags);
+
 		if (speedo_debug > 5)
 			printk(" CmdMCSetup frame length %d in entry %d.\n",
 				   dev->mc_count, entry);
@@ -1769,9 +2150,8 @@
 
 	sp->rx_mode = new_rx_mode;
 }
-
-
-static void eepro100_suspend (struct pci_dev *pdev)
+
+static void eepro100_suspend(struct pci_dev *pdev)
 {
 	struct net_device *dev = pdev->driver_data;
 	long ioaddr = dev->base_addr;
@@ -1782,54 +2162,58 @@
 	/* XXX call pci_set_power_state ()? */
 }
 
-
-static void eepro100_resume (struct pci_dev *pdev)
+static void eepro100_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pdev->driver_data;
-	struct speedo_private *np = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	long ioaddr = dev->base_addr;
 
-	netif_device_attach(dev);
+	/* I'm absolutely uncertain if this part of code may work.
+	   The problems are:
+	    - correct hardware reinitialization;
+		- correct driver behavior between different steps of the
+		  reinitialization;
+		- serialization with other driver calls.
+	   2000/03/08  SAW */
+	outw(SCBMaskAll, ioaddr + SCBCmd);
 	speedo_resume(dev);
-	np->rx_mode = -1;
-	np->flow_ctrl = np->partner = 0;
+	netif_device_attach(dev);
+	sp->rx_mode = -1;
+	sp->flow_ctrl = sp->partner = 0;
 	set_rx_mode(dev);
 }
 
-
 static void __devexit eepro100_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pdev->driver_data;
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	
-	unregister_netdev (dev);
+	unregister_netdev(dev);
 
-	release_region (pci_resource_start (pdev, 1),
-			pci_resource_len (pdev, 1));
-	release_mem_region (pci_resource_start (pdev, 0),
-			    pci_resource_len (pdev, 0));
+	release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+	release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
 
 #ifndef USE_IO
-	iounmap ((char *) dev->base_addr);
+	iounmap((char *)dev->base_addr);
 #endif
 
 	pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
-				  + sizeof(struct speedo_stats),
-			    sp->tx_ring, sp->tx_ring_dma);
-
-	kfree (dev);
+								+ sizeof(struct speedo_stats),
+						sp->tx_ring, sp->tx_ring_dma);
+	kfree(dev);
 }
-
-
+
 static struct pci_device_id eepro100_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
 		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER,
+		PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0,},
 };
-MODULE_DEVICE_TABLE (pci, eepro100_pci_tbl);
-
+MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);
 	
 static struct pci_driver eepro100_driver = {
-	name:		EEPRO100_MODULE_NAME,
+	name:		"eepro100",
 	id_table:	eepro100_pci_tbl,
 	probe:		eepro100_init_one,
 	remove:		eepro100_remove_one,
@@ -1837,30 +2221,44 @@
 	resume:		eepro100_resume,
 };
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48)
+static int pci_module_init(struct pci_driver *pdev)
+{
+	int rc;
+
+	rc = pci_register_driver(pdev);
+	if (rc <= 0) {
+		printk(KERN_INFO "%s: No cards found, driver not installed.\n",
+			   pdev->name);
+		pci_unregister_driver(pdev);
+		return -ENODEV;
+	}
+	return 0;
+}
+#endif
 
 static int __init eepro100_init_module(void)
 {
+	if (debug >= 0 && speedo_debug != debug)
+		printk(KERN_INFO "eepro100.c: Debug level is %d.\n", debug);
 	if (debug >= 0)
 		speedo_debug = debug;
 
-	return pci_module_init (&eepro100_driver);
+	return pci_module_init(&eepro100_driver);
 }
 
-
 static void __exit eepro100_cleanup_module(void)
 {
-	pci_unregister_driver (&eepro100_driver);
+	pci_unregister_driver(&eepro100_driver);
 }
 
-
 module_init(eepro100_init_module);
 module_exit(eepro100_cleanup_module);
-
+
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` `[ -f ./pci-netif.h ] && echo -DHAS_PCI_NETIF`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c eepro100.c"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/loopback.c linux/drivers/net/loopback.c
--- v2.3.99-pre3/linux/drivers/net/loopback.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/loopback.c	Mon Mar 27 10:35:56 2000
@@ -52,7 +52,7 @@
 #include <linux/if_ether.h>	/* For the statistics structure. */
 #include <linux/if_arp.h>	/* For ARPHRD_ETHER */
 
-#define LOOPBACK_MTU	(PAGE_SIZE - 172)
+#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
 
 /*
  * The higher levels take care of making this non-reentrant (it's
@@ -63,13 +63,6 @@
 	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
 	/*
-	 *	Take this out if the debug says its ok
-	 */
-	   
-	if (skb == NULL || dev == NULL) 
-		printk(KERN_DEBUG "loopback fed NULL data - splat\n");
-
-	/*
 	 *	Optimise so buffers with skb->free=1 are not copied but
 	 *	instead are lobbed from tx queue to rx queue 
 	 */
@@ -110,7 +103,7 @@
 /* Initialize the rest of the LOOPBACK device. */
 int __init loopback_init(struct net_device *dev)
 {
-	dev->mtu		= LOOPBACK_MTU;
+	dev->mtu		= PAGE_SIZE - LOOPBACK_OVERHEAD;
 	dev->hard_start_xmit	= loopback_xmit;
 	dev->hard_header	= eth_header;
 	dev->hard_header_cache	= eth_header_cache;
@@ -126,6 +119,9 @@
 			return -ENOMEM;
 	memset(dev->priv, 0, sizeof(struct net_device_stats));
 	dev->get_stats = get_stats;
+
+	if (num_physpages >= ((128*1024*1024)>>PAGE_SHIFT))
+		dev->mtu = 4096*4 - LOOPBACK_OVERHEAD;
 
 	/*
 	 *	Fill in the generic fields of the device structure. 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- v2.3.99-pre3/linux/drivers/net/pcmcia/Config.in	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/pcmcia/Config.in	Sun Apr  2 15:38:53 2000
@@ -15,6 +15,7 @@
    dep_tristate '  SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA
    dep_tristate '  Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA
    dep_tristate '  COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA
+   dep_tristate '  IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
 
    if [ "$CONFIG_CARDBUS" = "y" ]; then
       dep_tristate '  3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile
--- v2.3.99-pre3/linux/drivers/net/pcmcia/Makefile	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/pcmcia/Makefile	Sun Apr  2 15:38:53 2000
@@ -39,9 +39,18 @@
 obj-$(CONFIG_PCMCIA_3C575)	+= 3c575_cb.o
 obj-$(CONFIG_PCMCIA_XIRTULIP)	+= xircom_tulip_cb.o
 
+obj-$(CONFIG_PCMCIA_IBMTR)	+= ibmtr_cs.o
+
 O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
 OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
 M_OBJS		:= $(filter-out $(export-objs), $(obj-m))
 MX_OBJS		:= $(filter     $(export-objs), $(obj-m))
 
 include $(TOPDIR)/Rules.make
+
+.ibmtr.o: ../tokenring/ibmtr.c
+	$(CC) $(CFLAGS) -D__NO_VERSION__ -DPCMCIA -c -o $@ ../tokenring/ibmtr.c
+
+ibmtr_cs.o: .ibmtr.o ibmtr_cs.c
+	$(CC) $(CFLAGS) -DPCMCIA -c -o .$@ ibmtr_cs.c
+	$(LD) -r -o $@ .$@ .ibmtr.o
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/pcmcia/ibmtr_cs.c linux/drivers/net/pcmcia/ibmtr_cs.c
--- v2.3.99-pre3/linux/drivers/net/pcmcia/ibmtr_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/ibmtr_cs.c	Sun Apr  2 15:38:53 2000
@@ -0,0 +1,635 @@
+/*======================================================================
+
+    A PCMCIA token-ring driver for IBM-based cards
+
+    This driver supports the IBM PCMCIA Token-Ring Card.
+    Written by Steve Kipisz, kipisz@vnet.ibm.com or
+                             bungy@ibm.net
+
+    Written 1995,1996.
+
+    This code is based on pcnet_cs.c from David Hinds.
+    
+    V2.2.0 February 1999 - Mike Phillips phillim@amtrak.com
+
+    Linux V2.2.x presented significant changes to the underlying
+    ibmtr.c code.  Mainly the code became a lot more organized and
+    modular.
+
+    This caused the old PCMCIA Token Ring driver to give up and go 
+    home early. Instead of just patching the old code to make it 
+    work, the PCMCIA code has been streamlined, updated and possibly
+    improved.
+
+    This code now only contains code required for the Card Services.
+    All we do here is set the card up enough so that the real ibmtr.c
+    driver can find it and work with it properly.
+
+    i.e. We set up the io port, irq, mmio memory and shared ram memory.
+    This enables ibmtr_probe in ibmtr.c to find the card and configure it
+    as though it was a normal ISA and/or PnP card.
+
+    There is some confusion with the difference between available shared
+    ram and the amount actually reserved from memory.  ibmtr.c sets up
+    several offsets depending upon the actual on-board memory, not the
+    reserved memory.  We need to get around this to allow the cards to 
+    work with other cards in restricted memory space.  Therefore the 
+    pcmcia_reality_check function.
+
+    TODO
+	- Write the suspend / resume functions. 
+	- Fix Kernel Oops when removing card before ifconfig down
+
+    CHANGES
+
+    v2.2.5 April 1999 Mike Phillips (phillim@amtrak.com)
+    Obscure bug fix, required changed to ibmtr.c not ibmtr_cs.c
+    
+    v2.2.7 May 1999 Mike Phillips (phillim@amtrak.com)
+    Updated to version 2.2.7 to match the first version of the kernel
+    that the modification to ibmtr.c were incorporated into.
+    
+	
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/trdevice.h>
+#include <linux/ibmtr.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#define PCMCIA_DEBUG 10
+#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 =
+"ibmtr_cs.c 1.10 1996/01/06 05:19:00 (Steve Kipisz)\n"
+"           2.2.7 1999/05/03 12:00:00 (Mike Phillips)\n" ;
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* MMIO base address */
+static u_long mmiobase = 0;
+
+/* SRAM base address */
+static u_long srambase = 0;
+
+/* SRAM size 8,16,32,64 */
+static u_long sramsize = 16;
+
+/* Ringspeed 4,16 */
+static int ringspeed = 16;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(mmiobase, "i");
+MODULE_PARM(srambase, "i");
+MODULE_PARM(sramsize, "i");
+MODULE_PARM(ringspeed, "i");
+
+/*====================================================================*/
+
+static void ibmtr_config(dev_link_t *link);
+static void ibmtr_hw_setup(struct net_device *dev);
+static void ibmtr_release(u_long arg);
+static int ibmtr_event(event_t event, int priority,
+                       event_callback_args_t *args);
+
+static dev_info_t dev_info = "ibmtr_cs";
+
+static dev_link_t *ibmtr_attach(void);
+static void ibmtr_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+extern int ibmtr_probe(struct net_device *dev);
+unsigned char pcmcia_reality_check(unsigned char gss);
+
+extern int trdev_init(struct net_device *dev);
+extern void tok_interrupt(int irq, struct pt_regs *regs);
+extern int tok_init_card(struct net_device *dev);
+extern unsigned char get_sram_size(struct tok_info *ti);
+
+/*====================================================================*/
+
+typedef struct ibmtr_dev_t {
+    dev_link_t		link;
+    struct net_device	*dev; /* Changed for 2.2.0 */
+    dev_node_t          node;
+    window_handle_t     sram_win_handle;
+    struct tok_info	ti;
+} ibmtr_dev_t;
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    ibmtr_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    ibmtr_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *ibmtr_attach(void)
+{
+    ibmtr_dev_t *info;
+    dev_link_t *link;
+    struct net_device *dev;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "ibmtr_attach()\n");
+    flush_stale_links();
+
+    /* Create new token-ring device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+
+    link->release.function = &ibmtr_release;
+    link->release.data = (u_long)link;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    link->io.NumPorts1 = 4;
+    link->io.IOAddrLines = 16;
+    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 = &tok_interrupt;
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.Present = PRESENT_OPTION;
+
+    dev = init_trdev(NULL,0);
+    dev->priv = &info->ti;
+    link->irq.Instance = info->dev = dev;
+    
+    if (dev == NULL) {
+	ibmtr_detach(link);
+        return NULL;
+    }
+
+    dev->init = &ibmtr_probe;
+
+#if 0
+    dev->tbusy = 1; 
+#endif
+
+    /* 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 = &ibmtr_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);
+        ibmtr_detach(link);
+        return NULL;
+    }
+
+    return link;
+} /* ibmtr_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void ibmtr_detach(dev_link_t *link)
+{
+    struct ibmtr_dev_t *info = link->priv;
+    dev_link_t **linkp;
+    struct net_device *dev; 
+    long flags;
+
+
+    DEBUG(0, "ibmtr_detach(0x%p)\n", link);
+
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+        if (*linkp == link) break;
+    if (*linkp == NULL)
+        return;
+
+    dev = info->dev;
+    
+    save_flags(flags);
+    cli();
+    {
+	struct tok_info *ti = (struct tok_info *)dev->priv;
+	if (ti->tr_timer.next) del_timer(&(ti->tr_timer));
+    }
+    if (link->state & DEV_RELEASE_PENDING) {
+        del_timer(&link->release);
+        link->state &= ~DEV_RELEASE_PENDING;
+    }
+    restore_flags(flags);
+
+    if (link->state & DEV_CONFIG) {
+        ibmtr_release((u_long)link);
+        if (link->state & DEV_STALE_CONFIG) {
+            link->state |= DEV_STALE_LINK;
+            return;
+        }
+    }
+
+    if (link->handle)
+        CardServices(DeregisterClient, link->handle);
+
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    if (link->dev)
+	unregister_trdev(info->dev);
+    kfree(info);
+
+} /* ibmtr_detach */
+
+/*======================================================================
+
+    ibmtr_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    token-ring device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void ibmtr_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    ibmtr_dev_t *info = link->priv;
+    struct net_device *dev = info->dev;
+    struct tok_info *ti = dev->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    win_req_t req;
+    memreq_t mem;
+    int i, last_ret, last_fn;
+    u_char buf[64];
+    unsigned char Shared_Ram_Base;
+
+    DEBUG(0, "ibmtr_config(0x%p)\n", link);
+
+    tuple.Attributes = 0;
+    tuple.TupleData = 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;
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    link->conf.ConfigIndex = 0x61;
+
+    /* Determine if this is PRIMARY or ALTERNATE. */
+
+    /* Try PRIMARY card at 0xA20-0xA23 */
+    link->io.BasePort1 = 0xA20;
+    i = CardServices(RequestIO, link->handle, &link->io);
+    if (i == CS_SUCCESS) {
+	memcpy(info->node.dev_name, "tr0\0", 4);
+    } else {
+	/* Couldn't get 0xA20-0xA23.  Try ALTERNATE at 0xA24-0xA27. */
+	link->io.BasePort1 = 0xA24;
+	CS_CHECK(RequestIO, link->handle, &link->io);
+	memcpy(info->node.dev_name, "tr1\0", 4);
+    }
+    dev->base_addr = link->io.BasePort1;
+
+    CS_CHECK(RequestIRQ, link->handle, &link->irq);
+    dev->irq = link->irq.AssignedIRQ;
+    ti->irq = link->irq.AssignedIRQ;
+    ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
+
+    /* Allocate the MMIO memory window */
+    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    req.Attributes |= WIN_USE_WAIT|WIN_STRICT_ALIGN;
+    req.Base = mmiobase;
+    req.Size = 0x2000;
+    req.AccessSpeed = 250;
+    link->win = (window_handle_t) link->handle;
+    CS_CHECK(RequestWindow, &link->win, &req);
+    mem.CardOffset = req.Base;
+    mem.Page = 0;
+    CS_CHECK(MapMemPage, link->win, &mem);
+    ti->mmio = (u_long)ioremap(req.Base, req.Size);
+
+    /* Allocate the SRAM memory window */
+    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    req.Attributes |= WIN_USE_WAIT|WIN_MAP_BELOW_1MB;
+    req.Base = srambase;
+    req.Size = sramsize * 1024;
+    req.AccessSpeed = 250;
+    info->sram_win_handle = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &info->sram_win_handle, &req);
+
+    mem.CardOffset = req.Base;
+    mem.Page = 0;
+    CS_CHECK(MapMemPage, info->sram_win_handle, &mem);
+    Shared_Ram_Base = req.Base >> 12;
+   
+    ti->sram = 0;
+    ti->sram_base = Shared_Ram_Base;
+    
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+    /*  Set up the Token-Ring Controller Configuration Register and
+        turn on the card.  Check the "Local Area Network Credit Card
+        Adapters Technical Reference"  SC30-3585 for this info.  */
+    ibmtr_hw_setup(dev);
+
+#if 0
+    dev->tbusy = 0;
+#endif
+
+    i = register_trdev(dev);
+    
+    if (i != 0) {
+	printk(KERN_NOTICE "ibmtr_cs: register_trdev() failed\n");
+	goto failed;
+    }
+
+    link->dev = &info->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    printk(KERN_INFO "%s: port %#3lx, irq %d,",
+           dev->name, dev->base_addr, dev->irq);
+    printk (" mmio %#5lx,", (u_long)ti->mmio);
+    printk (" sram %#5lx,", (u_long)ti->sram_base << 12);
+    printk ("\n" KERN_INFO "  hwaddr=");
+    for (i = 0; i < TR_ALEN; i++)
+        printk("%02X", dev->dev_addr[i]);
+    printk("\n");
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    ibmtr_release((u_long)link);
+} /* ibmtr_config */
+
+/*======================================================================
+
+    After a card is removed, ibmtr_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 ibmtr_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    ibmtr_dev_t *info = link->priv;
+    struct net_device *dev = info->dev;
+    struct tok_info *ti=(struct tok_info *) dev->priv;
+
+    DEBUG(0, "ibmtr_release(0x%p)\n", link);
+
+    if (link->open) {
+	DEBUG(1, "ibmtr_cs: release postponed, '%s' "
+	      "still open\n", info->node.dev_name);
+        link->state |= DEV_STALE_CONFIG;
+        return;
+    }
+
+    ti->open_status=CLOSED;
+
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    if (link->win) {
+	struct tok_info *ti = dev->priv;
+	iounmap((void *)ti->mmio);
+	CardServices(ReleaseWindow, link->win);
+	CardServices(ReleaseWindow, info->sram_win_handle);
+    }
+
+    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+
+} /* ibmtr_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+======================================================================*/
+
+static int ibmtr_event(event_t event, int priority,
+                       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    ibmtr_dev_t *info = link->priv;
+    struct net_device *dev = info->dev;
+
+    DEBUG(1, "ibmtr_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+        link->state &= ~DEV_PRESENT;
+        if (link->state & DEV_CONFIG) {
+#if 0
+            dev->tbusy = 1; dev->start = 0;
+#endif
+            link->release.expires = jiffies + HZ/20;
+            link->state |= DEV_RELEASE_PENDING;
+            add_timer(&link->release);
+        }
+        break;
+    case CS_EVENT_CARD_INSERTION:
+        link->state |= DEV_PRESENT;
+	ibmtr_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 0
+            if (link->open) {
+                dev->tbusy = 1; dev->start = 0;
+            }
+#endif
+            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) {
+		(dev->init)(dev);
+#if 0
+                dev->tbusy = 0; dev->start = 1;
+#endif
+            }
+        }
+        break;
+    }
+    return 0;
+} /* ibmtr_event */
+
+/*====================================================================*/
+
+static void ibmtr_hw_setup(struct net_device *dev)
+{
+    struct tok_info *ti = dev->priv;
+    int i; 
+
+    /* Bizarre IBM behavior, there are 16 bits of information we
+       need to set, but the card only allows us to send 4 bits at a 
+       time.  For each byte sent to base_addr, bits 7-4 tell the
+       card which part of the 16 bits we are setting, bits 3-0 contain 
+       the actual information */
+
+    /* First nibble provides 4 bits of mmio */
+    i = ((int)ti->mmio >> 16) & 0x0F;
+    outb(i, dev->base_addr);
+
+    /* Second nibble provides 3 bits of mmio */
+    i = 0x10 | (((int)ti->mmio >> 12) & 0x0E);
+    outb(i, dev->base_addr);
+
+    /* Third nibble, hard-coded values */
+    i = 0x26;
+    outb(i, dev->base_addr);
+
+    /* Fourth nibble sets shared ram page size */
+
+    /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */          
+        
+    i = (sramsize >> 4) & 0x07; 
+    i = ((i == 4) ? 3 : i) << 2;
+    i |= 0x30;
+
+    if (ringspeed == 16)
+	i |= 2;
+    if (dev->base_addr == 0xA24)
+	i |= 1;
+    outb(i, dev->base_addr);
+
+    /* X40 will release the card for use */
+
+    outb(0x40, dev->base_addr);
+    
+    return;
+}
+
+/*======================================================================
+  
+    A sweet little function that circumvents the problem with
+    ibmtr.c trying to use more memory than we can allocate for
+    the PCMCIA card.  ibmtr.c just assumes that if a card has 
+    64K of shared ram, the entire 64K must be mapped into memory,
+    whereas resources are sometimes a little tight in card services
+    so we fool ibmtr.c into thinking the card has less memory on
+    it than it has.
+    
+======================================================================*/
+
+unsigned char pcmcia_reality_check(unsigned char gss)
+{
+    return (gss < sramsize) ? sramsize : gss;
+}
+
+/*====================================================================*/
+
+static int __init init_ibmtr_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+        printk(KERN_NOTICE "ibmtr_cs: Card Services release "
+	       "does not match!\n");
+        return -1;
+    }
+    register_pccard_driver(&dev_info, &ibmtr_attach, &ibmtr_detach);
+    return 0;
+}
+
+static void __exit exit_ibmtr_cs(void)
+{
+    DEBUG(0, "ibmtr_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+        ibmtr_detach(dev_list);
+}
+
+module_init(init_ibmtr_cs);
+module_exit(exit_ibmtr_cs);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c
--- v2.3.99-pre3/linux/drivers/net/ppp_async.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/ppp_async.c	Mon Apr 10 23:05:35 2000
@@ -119,9 +119,11 @@
 	struct asyncppp *ap;
 	int err;
 
+	MOD_INC_USE_COUNT;
+	err = -ENOMEM;
 	ap = kmalloc(sizeof(*ap), GFP_KERNEL);
 	if (ap == 0)
-		return -ENOMEM;
+		goto out;
 
 	/* initialize the asyncppp structure */
 	memset(ap, 0, sizeof(*ap));
@@ -140,15 +142,18 @@
 	ap->chan.ops = &async_ops;
 	ap->chan.mtu = PPP_MRU;
 	err = ppp_register_channel(&ap->chan);
-	if (err) {
-		kfree(ap);
-		return err;
-	}
+	if (err)
+		goto out_free;
 
 	tty->disc_data = ap;
 
-	MOD_INC_USE_COUNT;
 	return 0;
+
+ out_free:
+	kfree(ap);
+ out:
+	MOD_DEC_USE_COUNT;
+	return err;
 }
 
 /*
@@ -215,6 +220,16 @@
 
 	err = -EFAULT;
 	switch (cmd) {
+	case PPPIOCGCHAN:
+		err = -ENXIO;
+		if (ap == 0)
+			break;
+		err = -EFAULT;
+		if (put_user(ppp_channel_index(&ap->chan), (int *) arg))
+			break;
+		err = 0;
+		break;
+
 	case PPPIOCGUNIT:
 		err = -ENXIO;
 		if (ap == 0)
@@ -257,10 +272,14 @@
 	case PPPIOCSXASYNCMAP:
 	case PPPIOCGMRU:
 	case PPPIOCSMRU:
+		err = -EPERM;
+		if (!capable(CAP_NET_ADMIN))
+			break;
 		err = ppp_async_ioctl(&ap->chan, cmd, arg);
 		break;
 
 	case PPPIOCATTACH:
+	case PPPIOCDETACH:
 		err = ppp_channel_ioctl(&ap->chan, cmd, arg);
 		break;
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
--- v2.3.99-pre3/linux/drivers/net/ppp_generic.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/ppp_generic.c	Mon Apr 10 23:05:35 2000
@@ -19,7 +19,7 @@
  * PPP driver, written by Michael Callahan and Al Longyear, and
  * subsequently hacked by Paul Mackerras.
  *
- * ==FILEVERSION 20000313==
+ * ==FILEVERSION 20000406==
  */
 
 #include <linux/config.h>
@@ -55,8 +55,8 @@
 #define NP_AT	3		/* Appletalk protocol */
 #define NUM_NP	4		/* Number of NPs. */
 
-#define MPHDRLEN	4	/* multilink protocol header length */
-#define MPHDRLEN_SSN	2	/* ditto with short sequence numbers */
+#define MPHDRLEN	6	/* multilink protocol header length */
+#define MPHDRLEN_SSN	4	/* ditto with short sequence numbers */
 #define MIN_FRAG_SIZE	64
 
 /*
@@ -125,12 +125,13 @@
 
 /*
  * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC,
- * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ.
+ * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP.
  * Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.
  * Bits in xstate: SC_COMP_RUN
  */
 #define SC_FLAG_BITS	(SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \
-			 |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ)
+			 |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \
+			 |SC_COMP_TCP|SC_REJ_COMP_TCP)
 
 /*
  * Private data structure for each channel.
@@ -182,6 +183,14 @@
 /* We limit the length of ppp->file.rq to this (arbitrary) value */
 #define PPP_MAX_RQLEN	32
 
+/*
+ * Maximum number of multilink fragments queued up.
+ * This has to be large enough to cope with the maximum latency of
+ * the slowest channel relative to the others.  Strictly it should
+ * depend on the number of channels and their characteristics.
+ */
+#define PPP_MP_MAX_QLEN	128
+
 /* Multilink header bits. */
 #define B	0x80		/* this fragment begins a packet */
 #define E	0x40		/* this fragment ends a packet */
@@ -351,10 +360,13 @@
 	add_wait_queue(&pf->rwait, &wait);
 	current->state = TASK_INTERRUPTIBLE;
 	for (;;) {
-		ret = -EAGAIN;
 		skb = skb_dequeue(&pf->rq);
 		if (skb)
 			break;
+		ret = 0;
+		if (pf->kind == CHANNEL && PF_TO_CHANNEL(pf)->chan == 0)
+			break;
+		ret = -EAGAIN;
 		if (file->f_flags & O_NONBLOCK)
 			break;
 		ret = -ERESTARTSYS;
@@ -487,7 +499,7 @@
 			spin_lock_bh(&pch->downl);
 			chan = pch->chan;
 			err = -ENOTTY;
-			if (chan->ops->ioctl)
+			if (chan && chan->ops->ioctl)
 				err = chan->ops->ioctl(chan, cmd, arg);
 			spin_unlock_bh(&pch->downl);
 		}
@@ -767,6 +779,7 @@
 
  outf:
 	kfree_skb(skb);
+	++ppp->stats.tx_dropped;
 	return 0;
 }
 
@@ -1003,8 +1016,15 @@
 		pch = list_entry(list, struct channel, clist);
 
 		spin_lock_bh(&pch->downl);
-		if (skb_queue_len(&pch->file.xq) == 0
-		    && pch->chan->ops->start_xmit(pch->chan, skb))
+		if (pch->chan) {
+			if (pch->chan->ops->start_xmit(pch->chan, skb))
+				skb = 0;
+		} else {
+			/* channel got unregistered */
+			kfree_skb(skb);
+			skb = 0;
+		}
+		if (skb_queue_len(&pch->file.xq) == 0 && skb == 0)
 			ppp->xmit_pending = 0;
 		spin_unlock_bh(&pch->downl);
 		return;
@@ -1029,7 +1049,8 @@
 static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
 {
 	int nch, len, fragsize;
-	int i, bits, hdrlen;
+	int i, bits, hdrlen, mtu;
+	int flen, fnb;
 	unsigned char *p, *q;
 	struct list_head *list;
 	struct channel *pch;
@@ -1037,6 +1058,7 @@
 	struct ppp_channel *chan;
 
 	nch = 0;
+	hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
 	list = &ppp->channels;
 	while ((list = list->next) != &ppp->channels) {
 		pch = list_entry(list, struct channel, clist);
@@ -1087,8 +1109,6 @@
 
 	/* create a fragment for each channel */
 	bits = B;
-	hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
-	/* XXX gotta do A/C and prot compression here */
 	do {
 		list = list->next;
 		if (list == &ppp->channels) {
@@ -1099,47 +1119,73 @@
 		++i;
 		if (!pch->avail)
 			continue;
-		if (fragsize >= len) {
-			fragsize = len;
-			bits |= E;
+
+		/* check the channel's mtu and whether it is still attached. */
+		spin_lock_bh(&pch->downl);
+		if (pch->chan == 0 || (mtu = pch->chan->mtu) < hdrlen) {
+			/* can't use this channel */
+			spin_unlock_bh(&pch->downl);
+			pch->avail = 0;
+			if (--nch == 0)
+				break;
+			continue;
 		}
-		frag = alloc_skb(fragsize + hdrlen, GFP_ATOMIC);
-		if (frag != 0) {
-			q = skb_put(frag, fragsize + hdrlen);
+
+		/*
+		 * We have to create multiple fragments for this channel
+		 * if fragsize is greater than the channel's mtu.
+		 */
+		if (fragsize > len)
+			fragsize = len;
+		for (flen = fragsize; flen > 0; flen -= fnb) {
+			fnb = flen;
+			if (fnb > mtu + 2 - hdrlen)
+				fnb = mtu + 2 - hdrlen;
+			if (fnb >= len)
+				bits |= E;
+			frag = alloc_skb(fnb + hdrlen, GFP_ATOMIC);
+			if (frag == 0)
+				goto noskb;
+			q = skb_put(frag, fnb + hdrlen);
 			/* make the MP header */
+			q[0] = PPP_MP >> 8;
+			q[1] = PPP_MP;
 			if (ppp->flags & SC_MP_XSHORTSEQ) {
-				q[0] = bits + ((ppp->nxseq >> 8) & 0xf);
-				q[1] = ppp->nxseq;
-			} else {
-				q[0] = bits;
-				q[1] = ppp->nxseq >> 16;
-				q[2] = ppp->nxseq >> 8;
+				q[2] = bits + ((ppp->nxseq >> 8) & 0xf);
 				q[3] = ppp->nxseq;
+			} else {
+				q[2] = bits;
+				q[3] = ppp->nxseq >> 16;
+				q[4] = ppp->nxseq >> 8;
+				q[5] = ppp->nxseq;
 			}
 
 			/* copy the data in */
-			memcpy(q + hdrlen, p, fragsize);
+			memcpy(q + hdrlen, p, fnb);
 
 			/* try to send it down the channel */
-			spin_lock_bh(&pch->downl);
 			chan = pch->chan;
-			if (chan != 0) {
-				if (!chan->ops->start_xmit(chan, frag))
-					skb_queue_tail(&pch->file.xq, frag);
-			} else {
-				/* channel got unregistered, too bad */
-				kfree_skb(skb);
-			}
-			spin_unlock_bh(&pch->downl);
+			if (!chan->ops->start_xmit(chan, frag))
+				skb_queue_tail(&pch->file.xq, frag);
+			pch->had_frag = 1;
+			p += fnb;
+			len -= fnb;
+			++ppp->nxseq;
+			bits = 0;
 		}
-		p += fragsize;
-		len -= fragsize;
-		++ppp->nxseq;
-		bits = 0;
+		spin_unlock_bh(&pch->downl);
 	} while (len > 0);
 	ppp->nxchan = i;
 
 	return 1;
+
+ noskb:
+	spin_unlock_bh(&pch->downl);
+	if (ppp->debug & 1)
+		printk(KERN_ERR "PPP: no memory (fragment)\n");
+	++ppp->stats.tx_errors;
+	++ppp->nxseq;
+	return 1;	/* abandon the frame */
 }
 #endif /* CONFIG_PPP_MULTILINK */
 
@@ -1201,7 +1247,7 @@
 
 	proto = PPP_PROTO(skb);
 	read_lock_bh(&pch->upl);
-	if (pch->ppp == 0 || proto == PPP_LCP || proto == 0x80fb) {
+	if (pch->ppp == 0 || proto >= 0xc000 || proto == PPP_CCPFRAG) {
 		/* put it on the channel queue */
 		skb_queue_tail(&pch->file.rq, skb);
 		/* drop old frames if queue too long */
@@ -1306,12 +1352,7 @@
 		}
 		len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2);
 		if (len <= 0) {
-			int i;
 			printk(KERN_DEBUG "PPP: VJ decompression error\n");
-			printk(KERN_DEBUG "PPP: len = %d data =", skb->len);
-			for (i = 0; i < 16 && i < skb->len; ++i)
-				printk(" %.2x", skb->data[i]);
-			printk("\n");
 			goto err;
 		}
 		len += 2;
@@ -1426,11 +1467,11 @@
 static void
 ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
 {
-	u32 mask, seq, minseq;
+	u32 mask, seq;
 	struct list_head *l;
-	int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? 2: 4;
+	int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
 
-	if (skb->len < mphdrlen + 3)
+	if (skb->len < mphdrlen + 1 || ppp->mrru == 0)
 		goto err;		/* no good, throw it away */
 
 	/* Decode sequence number and begin/end bits */
@@ -1442,22 +1483,38 @@
 		mask = 0xffffff;
 	}
 	skb->BEbits = skb->data[2];
-	skb_pull(skb, mphdrlen + 2);	/* pull off PPP and MP headers*/
+	skb_pull(skb, mphdrlen);	/* pull off PPP and MP headers */
 
-	/* Expand sequence number to 32 bits */
-	seq |= pch->lastseq & ~mask;
-	if (seq_before(seq, pch->lastseq)) {
-		if (seq_after(seq, pch->lastseq - 100)) {
-			printk(KERN_DEBUG "PPP: MP fragments out of order"
-			       " (%u, %u)\n", pch->lastseq, seq);
-			goto err;
-		}
+	/*
+	 * Do protocol ID decompression on the first fragment of each packet.
+	 */
+	if ((skb->BEbits & B) && (skb->data[0] & 1))
+		*skb_push(skb, 1) = 0;
+
+	/*
+	 * Expand sequence number to 32 bits, making it as close
+	 * as possible to ppp->minseq.
+	 */
+	seq |= ppp->minseq & ~mask;
+	if ((int)(ppp->minseq - seq) > (int)(mask >> 1))
 		seq += mask + 1;
-	}
+	else if ((int)(seq - ppp->minseq) > (int)(mask >> 1))
+		seq -= mask + 1;	/* should never happen */
 	skb->sequence = seq;
 	pch->lastseq = seq;
 
 	/*
+	 * If this packet comes before the next one we were expecting,
+	 * drop it.
+	 */
+	if (seq_before(seq, ppp->nextseq)) {
+		kfree_skb(skb);
+		++ppp->stats.rx_dropped;
+		ppp_receive_error(ppp);
+		return;
+	}
+
+	/*
 	 * Reevaluate minseq, the minimum over all channels of the
 	 * last sequence number received on each channel.  Because of
 	 * the increasing sequence number rule, we know that any fragment
@@ -1465,17 +1522,23 @@
 	 * The list of channels can't change because we have the receive
 	 * side of the ppp unit locked.
 	 */
-	minseq = seq;
 	for (l = ppp->channels.next; l != &ppp->channels; l = l->next) {
 		struct channel *ch = list_entry(l, struct channel, clist);
 		if (seq_before(ch->lastseq, seq))
 			seq = ch->lastseq;
 	}
-	ppp->minseq = minseq;
+	if (seq_before(ppp->minseq, seq))
+		ppp->minseq = seq;
 
 	/* Put the fragment on the reconstruction queue */
 	ppp_mp_insert(ppp, skb);
 
+	/* If the queue is getting long, don't wait any longer for packets
+	   before the start of the queue. */
+	if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN
+	    && seq_before(ppp->minseq, ppp->mrq.next->sequence))
+		ppp->minseq = ppp->mrq.next->sequence;
+
 	/* Pull completed packets off the queue and receive them. */
 	while ((skb = ppp_mp_reconstruct(ppp)) != 0)
 		ppp_receive_nonmp_frame(ppp, skb);
@@ -1523,16 +1586,17 @@
 	struct sk_buff *skb = NULL;
 	int lost = 0, len = 0;
 
+	if (ppp->mrru == 0)	/* do nothing until mrru is set */
+		return NULL;
 	head = list->next;
 	tail = NULL;
 	for (p = head; p != (struct sk_buff *) list; p = next) {
 		next = p->next;
 		if (seq_before(p->sequence, seq)) {
-			/* this can't happen, anyway toss the skb */
-			printk(KERN_ERR "ppp_mp_reconstruct bad seq %x < %x\n",
+			/* this can't happen, anyway ignore the skb */
+			printk(KERN_ERR "ppp_mp_reconstruct bad seq %u < %u\n",
 			       p->sequence, seq);
-			__skb_unlink(p, list);
-			kfree_skb(p);
+			head = next;
 			continue;
 		}
 		if (p->sequence != seq) {
@@ -1542,8 +1606,8 @@
 				break;
 			/* Fragment `seq' is lost, keep going. */
 			lost = 1;
-			seq = seq_before(p->sequence, minseq)?
-				p->sequence: minseq;
+			seq = seq_before(minseq, p->sequence)?
+				minseq + 1: p->sequence;
 			next = p;
 			continue;
 		}
@@ -1560,22 +1624,31 @@
 		if (p->BEbits & B) {
 			head = p;
 			lost = 0;
-			/* reset len, allow for protocol ID compression */
-			len = p->data[0] & 1;
+			len = 0;
 		}
 
 		len += p->len;
 
 		/* Got a complete packet yet? */
 		if (lost == 0 && (p->BEbits & E) && (head->BEbits & B)) {
-			if (len > ppp->mrru) {
+			if (len > ppp->mrru + 2) {
 				++ppp->stats.rx_length_errors;
+				printk(KERN_DEBUG "PPP: reconstructed packet"
+				       " is too long (%d)\n", len);
+			} else if (p == head) {
+				/* fragment is complete packet - reuse skb */
+				tail = p;
+				skb = skb_get(p);
+				break;
 			} else if ((skb = dev_alloc_skb(len)) == NULL) {
 				++ppp->stats.rx_missed_errors;
+				printk(KERN_DEBUG "PPP: no memory for "
+				       "reconstructed packet");
 			} else {
 				tail = p;
 				break;
 			}
+			ppp->nextseq = seq + 1;
 		}
 
 		/*
@@ -1593,19 +1666,18 @@
 	if (tail != NULL) {
 		/* If we have discarded any fragments,
 		   signal a receive error. */
-		if (head->sequence != ppp->nextseq)
+		if (head->sequence != ppp->nextseq) {
+			if (ppp->debug & 1)
+				printk(KERN_DEBUG "  missed pkts %u..%u\n",
+				       ppp->nextseq, head->sequence-1);
+			++ppp->stats.rx_dropped;
 			ppp_receive_error(ppp);
-
-		/* uncompress protocol ID */
-		if (head->data[0] & 1)
-			*skb_put(skb, 1) = 0;
-		p = head;
-		for (;;) {
-			memcpy(skb_put(skb, p->len), p->data, p->len);
-			if (p == tail)
-				break;
-			p = p->next;
 		}
+
+		if (head != tail)
+			/* copy to a single skb */
+			for (p = head; p != tail->next; p = p->next)
+				memcpy(skb_put(skb, p->len), p->data, p->len);
 		ppp->nextseq = tail->sequence + 1;
 		head = tail->next;
 	}
@@ -1642,6 +1714,9 @@
 	chan->ppp = pch;
 	init_ppp_file(&pch->file, CHANNEL);
 	pch->file.hdrlen = chan->hdrlen;
+#ifdef CONFIG_PPP_MULTILINK
+	pch->lastseq = -1;
+#endif /* CONFIG_PPP_MULTILINK */
 	spin_lock_init(&pch->downl);
 	pch->upl = RW_LOCK_UNLOCKED;
 	spin_lock_bh(&all_channels_lock);
@@ -1653,13 +1728,30 @@
 }
 
 /*
- * Return the unit number associated with a channel.
+ * Return the index of a channel.
+ */
+int ppp_channel_index(struct ppp_channel *chan)
+{
+	struct channel *pch = chan->ppp;
+
+	return pch->file.index;
+}
+
+/*
+ * Return the PPP unit number to which a channel is connected.
  */
 int ppp_unit_number(struct ppp_channel *chan)
 {
 	struct channel *pch = chan->ppp;
+	int unit = -1;
 
-	return pch->ppp->file.index;
+	if (pch != 0) {
+		read_lock_bh(&pch->upl);
+		if (pch->ppp != 0)
+			unit = pch->ppp->file.index;
+		read_unlock_bh(&pch->upl);
+	}
+	return unit;
 }
 
 /*
@@ -1760,6 +1852,8 @@
 	int err = -ENOTTY;
 	int unit;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
 	if (pch == 0)
 		return -EINVAL;
 	switch (cmd) {
@@ -2104,6 +2198,10 @@
 	INIT_LIST_HEAD(&ppp->channels);
 	spin_lock_init(&ppp->rlock);
 	spin_lock_init(&ppp->wlock);
+#ifdef CONFIG_PPP_MULTILINK
+	ppp->minseq = -1;
+	skb_queue_head_init(&ppp->mrq);
+#endif /* CONFIG_PPP_MULTILINK */
 
 	ppp->dev = dev;
 	dev->init = ppp_net_init;
@@ -2163,6 +2261,9 @@
 	}
 	skb_queue_purge(&ppp->file.xq);
 	skb_queue_purge(&ppp->file.rq);
+#ifdef CONFIG_PPP_MULTILINK
+	skb_queue_purge(&ppp->mrq);
+#endif /* CONFIG_PPP_MULTILINK */
 	dev = ppp->dev;
 	ppp->dev = 0;
 	ppp_unlock(ppp);
@@ -2247,10 +2348,12 @@
 	if (pch->chan == 0)		/* need to check this?? */
 		goto outr;
 
-	hdrlen = pch->chan->hdrlen + PPP_HDRLEN;
+	if (pch->file.hdrlen > ppp->file.hdrlen)
+		ppp->file.hdrlen = pch->file.hdrlen;
+	hdrlen = pch->file.hdrlen + 2;	/* for protocol bytes */
 	if (ppp->dev && hdrlen > ppp->dev->hard_header_len)
 		ppp->dev->hard_header_len = hdrlen;
-	list_add(&pch->clist, &ppp->channels);
+	list_add_tail(&pch->clist, &ppp->channels);
 	++ppp->n_channels;
 	pch->ppp = ppp;
 	ret = 0;
@@ -2319,6 +2422,7 @@
 
 EXPORT_SYMBOL(ppp_register_channel);
 EXPORT_SYMBOL(ppp_unregister_channel);
+EXPORT_SYMBOL(ppp_channel_index);
 EXPORT_SYMBOL(ppp_unit_number);
 EXPORT_SYMBOL(ppp_input);
 EXPORT_SYMBOL(ppp_input_error);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/ppp_synctty.c linux/drivers/net/ppp_synctty.c
--- v2.3.99-pre3/linux/drivers/net/ppp_synctty.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/ppp_synctty.c	Mon Apr 10 23:05:35 2000
@@ -29,11 +29,9 @@
  * PPP driver, written by Michael Callahan and Al Longyear, and
  * subsequently hacked by Paul Mackerras.
  *
- * ==FILEVERSION 991018==
+ * ==FILEVERSION 20000322==
  */
 
-/* $Id: ppp_synctty.c,v 1.3 1999/09/02 05:30:10 paulus Exp $ */
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
@@ -43,9 +41,17 @@
 #include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
 #include <linux/ppp_channel.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 
-#define PPP_VERSION	"2.4.0"
+#ifndef spin_trylock_bh
+#define spin_trylock_bh(lock)	({ int __r; local_bh_disable();	\
+				   __r = spin_trylock(lock);	\
+				   if (!__r) local_bh_enable();	\
+				   __r; })
+#endif
+
+#define PPP_VERSION	"2.4.1"
 
 /* Structure for storing local state. */
 struct syncppp {
@@ -53,29 +59,25 @@
 	unsigned int	flags;
 	unsigned int	rbits;
 	int		mru;
-	unsigned long	busy;
+	spinlock_t	xmit_lock;
+	spinlock_t	recv_lock;
+	unsigned long	xmit_flags;
 	u32		xaccm[8];
 	u32		raccm;
 	unsigned int	bytes_sent;
 	unsigned int	bytes_rcvd;
 
 	struct sk_buff	*tpkt;
-	struct sk_buff_head xq;
 	unsigned long	last_xmit;
 
 	struct sk_buff	*rpkt;
-	struct sk_buff_head rq;
-	wait_queue_head_t rwait;
 
 	struct ppp_channel chan;	/* interface to generic ppp layer */
-	int		connected;
 };
 
-/* Bit numbers in busy */
-#define XMIT_BUSY	0
-#define RECV_BUSY	1
-#define XMIT_WAKEUP	2
-#define XMIT_FULL	3
+/* Bit numbers in xmit_flags */
+#define XMIT_WAKEUP	0
+#define XMIT_FULL	1
 
 /* Bits in rbits */
 #define SC_RCV_BITS	(SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
@@ -85,15 +87,18 @@
 /*
  * Prototypes.
  */
-static struct sk_buff* ppp_sync_txdequeue(struct syncppp *ap);
+static struct sk_buff* ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *);
 static int ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb);
+static int ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd,
+			  unsigned long arg);
 static int ppp_sync_push(struct syncppp *ap);
 static void ppp_sync_flush_output(struct syncppp *ap);
 static void ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
-			    char *flags, int count);
+			   char *flags, int count);
 
 struct ppp_channel_ops sync_ops = {
-	ppp_sync_send
+	ppp_sync_send,
+	ppp_sync_ioctl
 };
 
 /*
@@ -157,50 +162,6 @@
 	}
 }
 
-/*
- * Routines for locking and unlocking the transmit and receive paths.
- */
-static inline void
-lock_path(struct syncppp *ap, int bit)
-{
-	do {
-		while (test_bit(bit, &ap->busy))
-		       mb();
-	} while (test_and_set_bit(bit, &ap->busy));
-	mb();
-}
-
-static inline int
-trylock_path(struct syncppp *ap, int bit)
-{
-	if (test_and_set_bit(bit, &ap->busy))
-		return 0;
-	mb();
-	return 1;
-}
-
-static inline void
-unlock_path(struct syncppp *ap, int bit)
-{
-	mb();
-	clear_bit(bit, &ap->busy);
-}
-
-#define lock_xmit_path(ap)	lock_path(ap, XMIT_BUSY)
-#define trylock_xmit_path(ap)	trylock_path(ap, XMIT_BUSY)
-#define unlock_xmit_path(ap)	unlock_path(ap, XMIT_BUSY)
-#define lock_recv_path(ap)	lock_path(ap, RECV_BUSY)
-#define trylock_recv_path(ap)	trylock_path(ap, RECV_BUSY)
-#define unlock_recv_path(ap)	unlock_path(ap, RECV_BUSY)
-
-static inline void
-flush_skb_queue(struct sk_buff_head *q)
-{
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(q)) != 0)
-		kfree_skb(skb);
-}
 
 /*
  * Routines implementing the synchronous PPP line discipline.
@@ -213,27 +174,41 @@
 ppp_sync_open(struct tty_struct *tty)
 {
 	struct syncppp *ap;
+	int err;
 
+	MOD_INC_USE_COUNT;
 	ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+	err = -ENOMEM;
 	if (ap == 0)
-		return -ENOMEM;
-
-	MOD_INC_USE_COUNT;
+		goto out;
 
 	/* initialize the syncppp structure */
 	memset(ap, 0, sizeof(*ap));
 	ap->tty = tty;
 	ap->mru = PPP_MRU;
+	spin_lock_init(&ap->xmit_lock);
+	spin_lock_init(&ap->recv_lock);
 	ap->xaccm[0] = ~0U;
 	ap->xaccm[3] = 0x60000000U;
 	ap->raccm = ~0U;
-	skb_queue_head_init(&ap->xq);
-	skb_queue_head_init(&ap->rq);
-	init_waitqueue_head(&ap->rwait);
+
+	ap->chan.private = ap;
+	ap->chan.ops = &sync_ops;
+	ap->chan.mtu = PPP_MRU;
+	ap->chan.hdrlen = 2;	/* for A/C bytes */
+	err = ppp_register_channel(&ap->chan);
+	if (err)
+		goto out_free;
 
 	tty->disc_data = ap;
 
 	return 0;
+
+ out_free:
+	kfree(ap);
+ out:
+	MOD_DEC_USE_COUNT;
+	return err;
 }
 
 /*
@@ -248,208 +223,59 @@
 	if (ap == 0)
 		return;
 	tty->disc_data = 0;
-	lock_xmit_path(ap);
-	lock_recv_path(ap);
+	ppp_unregister_channel(&ap->chan);
 	if (ap->rpkt != 0)
 		kfree_skb(ap->rpkt);
-	flush_skb_queue(&ap->rq);
 	if (ap->tpkt != 0)
 		kfree_skb(ap->tpkt);
-	flush_skb_queue(&ap->xq);
-	if (ap->connected)
-		ppp_unregister_channel(&ap->chan);
 	kfree(ap);
 	MOD_DEC_USE_COUNT;
 }
 
 /*
- * Read a PPP frame.  pppd can use this to negotiate over the
- * channel before it joins it to a bundle.
+ * Read a PPP frame, for compatibility until pppd is updated.
  */
 static ssize_t
 ppp_sync_read(struct tty_struct *tty, struct file *file,
 	       unsigned char *buf, size_t count)
 {
 	struct syncppp *ap = tty->disc_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	struct sk_buff *skb = 0;
 
-	ret = -ENXIO;
 	if (ap == 0)
-		goto out;		/* should never happen */
-
-	add_wait_queue(&ap->rwait, &wait);
-	current->state = TASK_INTERRUPTIBLE;
-	for (;;) {
-		ret = -EAGAIN;
-		skb = skb_dequeue(&ap->rq);
-		if (skb)
-			break;
-		if (file->f_flags & O_NONBLOCK)
-			break;
-		ret = -ERESTARTSYS;
-		if (signal_pending(current))
-			break;
-		schedule();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&ap->rwait, &wait);
-
-	if (skb == 0)
-		goto out;
-
-	ret = -EOVERFLOW;
-	if (skb->len > count)
-		goto outf;
-	ret = -EFAULT;
-	if (copy_to_user(buf, skb->data, skb->len))
-		goto outf;
-	ret = skb->len;
-
- outf:
-	kfree_skb(skb);
- out:
-	return ret;
+		return -ENXIO;
+	return ppp_channel_read(&ap->chan, file, buf, count);
 }
 
 /*
- * Write a ppp frame.  pppd can use this to send frames over
- * this particular channel.
+ * Write a ppp frame, for compatibility until pppd is updated.
  */
 static ssize_t
 ppp_sync_write(struct tty_struct *tty, struct file *file,
 		const unsigned char *buf, size_t count)
 {
 	struct syncppp *ap = tty->disc_data;
-	struct sk_buff *skb;
-	ssize_t ret;
 
-	ret = -ENXIO;
 	if (ap == 0)
-		goto out;	/* should never happen */
-
-	ret = -ENOMEM;
-	skb = alloc_skb(count + 2, GFP_KERNEL);
-	if (skb == 0)
-		goto out;
-	skb_reserve(skb, 2);
-	ret = -EFAULT;
-	if (copy_from_user(skb_put(skb, count), buf, count)) {
-		kfree_skb(skb);
-		goto out;
-	}
-
-	skb_queue_tail(&ap->xq, skb);
-	ppp_sync_push(ap);
-
-	ret = count;
-
- out:
-	return ret;
+		return -ENXIO;
+	return ppp_channel_write(&ap->chan, buf, count);
 }
 
 static int
-ppp_sync_ioctl(struct tty_struct *tty, struct file *file,
-		unsigned int cmd, unsigned long arg)
+ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
+		  unsigned int cmd, unsigned long arg)
 {
 	struct syncppp *ap = tty->disc_data;
 	int err, val;
-	u32 accm[8];
-	struct sk_buff *skb;
-
-	err = -ENXIO;
-	if (ap == 0)
-		goto out;	/* should never happen */
-	err = -EPERM;
-	if (!capable(CAP_NET_ADMIN))
-		goto out;
 
 	err = -EFAULT;
 	switch (cmd) {
-	case PPPIOCGFLAGS:
-		val = ap->flags | ap->rbits;
-		if (put_user(val, (int *) arg))
-			break;
-		err = 0;
-		break;
-	case PPPIOCSFLAGS:
-		if (get_user(val, (int *) arg))
-			break;
-		ap->flags = val & ~SC_RCV_BITS;
-		ap->rbits = val & SC_RCV_BITS;
-		err = 0;
-		break;
-
-	case PPPIOCGASYNCMAP:
-		if (put_user(ap->xaccm[0], (u32 *) arg))
-			break;
-		err = 0;
-		break;
-	case PPPIOCSASYNCMAP:
-		if (get_user(ap->xaccm[0], (u32 *) arg))
-			break;
-		err = 0;
-		break;
-
-	case PPPIOCGRASYNCMAP:
-		if (put_user(ap->raccm, (u32 *) arg))
-			break;
-		err = 0;
-		break;
-	case PPPIOCSRASYNCMAP:
-		if (get_user(ap->raccm, (u32 *) arg))
-			break;
-		err = 0;
-		break;
-
-	case PPPIOCGXASYNCMAP:
-		if (copy_to_user((void *) arg, ap->xaccm, sizeof(ap->xaccm)))
-			break;
-		err = 0;
-		break;
-	case PPPIOCSXASYNCMAP:
-		if (copy_from_user(accm, (void *) arg, sizeof(accm)))
-			break;
-		accm[2] &= ~0x40000000U;	/* can't escape 0x5e */
-		accm[3] |= 0x60000000U;		/* must escape 0x7d, 0x7e */
-		memcpy(ap->xaccm, accm, sizeof(ap->xaccm));
-		err = 0;
-		break;
-
-	case PPPIOCGMRU:
-		if (put_user(ap->mru, (int *) arg))
-			break;
-		err = 0;
-		break;
-	case PPPIOCSMRU:
-		if (get_user(val, (int *) arg))
-			break;
-		if (val < PPP_MRU)
-			val = PPP_MRU;
-		ap->mru = val;
-		err = 0;
-		break;
-
-	case PPPIOCATTACH:
-		if (get_user(val, (int *) arg))
-			break;
-		err = -EALREADY;
-		if (ap->connected)
-			break;
-		ap->chan.private = ap;
-		ap->chan.ops = &sync_ops;
-		err = ppp_register_channel(&ap->chan);
-		if (err != 0)
-			break;
-		ap->connected = 1;
-		break;
-	case PPPIOCDETACH:
+	case PPPIOCGUNIT:
 		err = -ENXIO;
-		if (!ap->connected)
+		if (ap == 0)
+			break;
+		err = -EFAULT;
+		if (put_user(ppp_channel_index(&ap->chan), (int *) arg))
 			break;
-		ppp_unregister_channel(&ap->chan);
-		ap->connected = 0;
 		err = 0;
 		break;
 
@@ -460,8 +286,6 @@
 
 	case TCFLSH:
 		/* flush our buffers and the serial port's buffer */
-		if (arg == TCIFLUSH || arg == TCIOFLUSH)
-			flush_skb_queue(&ap->rq);
 		if (arg == TCIOFLUSH || arg == TCOFLUSH)
 			ppp_sync_flush_output(ap);
 		err = n_tty_ioctl(tty, file, cmd, arg);
@@ -469,17 +293,39 @@
 
 	case FIONREAD:
 		val = 0;
-		if ((skb = skb_peek(&ap->rq)) != 0)
-			val = skb->len;
 		if (put_user(val, (int *) arg))
 			break;
 		err = 0;
 		break;
 
+	/*
+	 * Compatibility calls until pppd is updated.
+	 */
+	case PPPIOCGFLAGS:
+	case PPPIOCSFLAGS:
+	case PPPIOCGASYNCMAP:
+	case PPPIOCSASYNCMAP:
+	case PPPIOCGRASYNCMAP:
+	case PPPIOCSRASYNCMAP:
+	case PPPIOCGXASYNCMAP:
+	case PPPIOCSXASYNCMAP:
+	case PPPIOCGMRU:
+	case PPPIOCSMRU:
+		err = -EPERM;
+		if (!capable(CAP_NET_ADMIN))
+			break;
+		err = ppp_sync_ioctl(&ap->chan, cmd, arg);
+		break;
+
+	case PPPIOCATTACH:
+	case PPPIOCDETACH:
+		err = ppp_channel_ioctl(&ap->chan, cmd, arg);
+		break;
+
 	default:
 		err = -ENOIOCTLCMD;
 	}
- out:
+
 	return err;
 }
 
@@ -489,12 +335,10 @@
 	struct syncppp *ap = tty->disc_data;
 	unsigned int mask;
 
-	if (ap == 0)
-		return 0;	/* should never happen */
-	poll_wait(file, &ap->rwait, wait);
 	mask = POLLOUT | POLLWRNORM;
-	if (skb_peek(&ap->rq))
-		mask |= POLLIN | POLLRDNORM;
+	/* compatibility for old pppd */
+	if (ap != 0)
+		mask |= ppp_channel_poll(&ap->chan, file, wait);
 	if (test_bit(TTY_OTHER_CLOSED, &tty->flags) || tty_hung_up_p(file))
 		mask |= POLLHUP;
 	return mask;
@@ -514,9 +358,9 @@
 
 	if (ap == 0)
 		return;
-	trylock_recv_path(ap);
+	spin_lock_bh(&ap->recv_lock);
 	ppp_sync_input(ap, buf, flags, count);
-	unlock_recv_path(ap);
+	spin_unlock_bh(&ap->recv_lock);
 	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
 	    && tty->driver.unthrottle)
 		tty->driver.unthrottle(tty);
@@ -530,7 +374,7 @@
 	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	if (ap == 0)
 		return;
-	if (ppp_sync_push(ap) && ap->connected)
+	if (ppp_sync_push(ap))
 		ppp_output_wakeup(&ap->chan);
 }
 
@@ -542,7 +386,7 @@
 	close:	ppp_sync_close,
 	read:	ppp_sync_read,
 	write:	ppp_sync_write,
-	ioctl:	ppp_sync_ioctl,
+	ioctl:	ppp_synctty_ioctl,
 	poll:	ppp_sync_poll,
 	receive_room: ppp_sync_room,
 	receive_buf: ppp_sync_receive,
@@ -562,54 +406,133 @@
 }
 
 /*
+ * The following routines provide the PPP channel interface.
+ */
+static int
+ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg)
+{
+	struct syncppp *ap = chan->private;
+	int err, val;
+	u32 accm[8];
+
+	err = -EFAULT;
+	switch (cmd) {
+	case PPPIOCGFLAGS:
+		val = ap->flags | ap->rbits;
+		if (put_user(val, (int *) arg))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSFLAGS:
+		if (get_user(val, (int *) arg))
+			break;
+		ap->flags = val & ~SC_RCV_BITS;
+		spin_lock_bh(&ap->recv_lock);
+		ap->rbits = val & SC_RCV_BITS;
+		spin_unlock_bh(&ap->recv_lock);
+		err = 0;
+		break;
+
+	case PPPIOCGASYNCMAP:
+		if (put_user(ap->xaccm[0], (u32 *) arg))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSASYNCMAP:
+		if (get_user(ap->xaccm[0], (u32 *) arg))
+			break;
+		err = 0;
+		break;
+
+	case PPPIOCGRASYNCMAP:
+		if (put_user(ap->raccm, (u32 *) arg))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSRASYNCMAP:
+		if (get_user(ap->raccm, (u32 *) arg))
+			break;
+		err = 0;
+		break;
+
+	case PPPIOCGXASYNCMAP:
+		if (copy_to_user((void *) arg, ap->xaccm, sizeof(ap->xaccm)))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSXASYNCMAP:
+		if (copy_from_user(accm, (void *) arg, sizeof(accm)))
+			break;
+		accm[2] &= ~0x40000000U;	/* can't escape 0x5e */
+		accm[3] |= 0x60000000U;		/* must escape 0x7d, 0x7e */
+		memcpy(ap->xaccm, accm, sizeof(ap->xaccm));
+		err = 0;
+		break;
+
+	case PPPIOCGMRU:
+		if (put_user(ap->mru, (int *) arg))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSMRU:
+		if (get_user(val, (int *) arg))
+			break;
+		if (val < PPP_MRU)
+			val = PPP_MRU;
+		ap->mru = val;
+		err = 0;
+		break;
+
+	default:
+		err = -ENOTTY;
+	}
+	return err;
+}
+
+/*
  * Procedures for encapsulation and framing.
  */
 
 struct sk_buff*
-ppp_sync_txdequeue(struct syncppp *ap)
+ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)
 {
 	int proto;
 	unsigned char *data;
 	int islcp;
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&ap->xq)) != NULL) {
 
-		data  = skb->data;
-		proto = (data[0] << 8) + data[1];
+	data  = skb->data;
+	proto = (data[0] << 8) + data[1];
 
-		/* LCP packets with codes between 1 (configure-request)
-		 * and 7 (code-reject) must be sent as though no options
-		 * have been negotiated.
-		 */
-		islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7;
-
-		/* compress protocol field if option enabled */
-                if (data[0] == 0 && (ap->flags & SC_COMP_PROT) && !islcp)
-			skb_pull(skb,1);
-
-		/* prepend address/control fields if necessary */
-		if ((ap->flags & SC_COMP_AC) == 0 || islcp) {
-			if (skb_headroom(skb) < 2) {
-				struct sk_buff *npkt = dev_alloc_skb(skb->len + 2);
-				if (npkt == NULL) {
-					kfree_skb(skb);
-					continue;
-				}
-				skb_reserve(npkt,2);
-				memcpy(skb_put(npkt,skb->len), skb->data, skb->len);
+	/* LCP packets with codes between 1 (configure-request)
+	 * and 7 (code-reject) must be sent as though no options
+	 * have been negotiated.
+	 */
+	islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7;
+
+	/* compress protocol field if option enabled */
+	if (data[0] == 0 && (ap->flags & SC_COMP_PROT) && !islcp)
+		skb_pull(skb,1);
+
+	/* prepend address/control fields if necessary */
+	if ((ap->flags & SC_COMP_AC) == 0 || islcp) {
+		if (skb_headroom(skb) < 2) {
+			struct sk_buff *npkt = dev_alloc_skb(skb->len + 2);
+			if (npkt == NULL) {
 				kfree_skb(skb);
-				skb = npkt;
+				return NULL;
 			}
-			skb_push(skb,2);
-			skb->data[0] = PPP_ALLSTATIONS;
-			skb->data[1] = PPP_UI;
+			skb_reserve(npkt,2);
+			memcpy(skb_put(npkt,skb->len), skb->data, skb->len);
+			kfree_skb(skb);
+			skb = npkt;
 		}
-
-		ap->last_xmit = jiffies;
-		break;
+		skb_push(skb,2);
+		skb->data[0] = PPP_ALLSTATIONS;
+		skb->data[1] = PPP_UI;
 	}
 
+	ap->last_xmit = jiffies;
+
 	if (skb && ap->flags & SC_LOG_OUTPKT)
 		ppp_print_buffer ("send buffer", skb->data, skb->len);
 
@@ -633,9 +556,13 @@
 
 	ppp_sync_push(ap);
 
-	if (test_and_set_bit(XMIT_FULL, &ap->busy))
+	if (test_and_set_bit(XMIT_FULL, &ap->xmit_flags))
 		return 0;	/* already full */
-	skb_queue_head(&ap->xq,skb);
+	skb = ppp_sync_txmunge(ap, skb);
+	if (skb != NULL)
+		ap->tpkt = skb;
+	else
+		clear_bit(XMIT_FULL, &ap->xmit_flags);
 
 	ppp_sync_push(ap);
 	return 1;
@@ -651,20 +578,13 @@
 	struct tty_struct *tty = ap->tty;
 	int tty_stuffed = 0;
 
-	if (!trylock_xmit_path(ap)) {
-		set_bit(XMIT_WAKEUP, &ap->busy);
+	set_bit(XMIT_WAKEUP, &ap->xmit_flags);
+	if (!spin_trylock_bh(&ap->xmit_lock))
 		return 0;
-	}
 	for (;;) {
-		if (test_and_clear_bit(XMIT_WAKEUP, &ap->busy))
+		if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags))
 			tty_stuffed = 0;
-		if (ap->tpkt == 0) {
-			if ((ap->tpkt = ppp_sync_txdequeue(ap)) == 0) {
-				clear_bit(XMIT_FULL, &ap->busy);
-			        done = 1;
-			}
-		}
-		if (!tty_stuffed && ap->tpkt != NULL) {
+		if (!tty_stuffed && ap->tpkt != 0) {
 			set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 			sent = tty->driver.write(tty, 0, ap->tpkt->data, ap->tpkt->len);
 			if (sent < 0)
@@ -674,15 +594,17 @@
 			} else {
 				kfree_skb(ap->tpkt);
 				ap->tpkt = 0;
+				clear_bit(XMIT_FULL, &ap->xmit_flags);
+				done = 1;
 			}
 			continue;
 		}
 		/* haven't made any progress */
-		unlock_xmit_path(ap);
-		if (!(test_bit(XMIT_WAKEUP, &ap->busy)
+		spin_unlock_bh(&ap->xmit_lock);
+		if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags)
 		      || (!tty_stuffed && ap->tpkt != 0)))
 			break;
-		if (!trylock_xmit_path(ap))
+		if (!spin_trylock_bh(&ap->xmit_lock))
 			break;
 	}
 	return done;
@@ -691,10 +613,10 @@
 	if (ap->tpkt != 0) {
 		kfree_skb(ap->tpkt);
 		ap->tpkt = 0;
-		clear_bit(XMIT_FULL, &ap->busy);
+		clear_bit(XMIT_FULL, &ap->xmit_flags);
 		done = 1;
 	}
-	unlock_xmit_path(ap);
+	spin_unlock_bh(&ap->xmit_lock);
 	return done;
 }
 
@@ -707,16 +629,15 @@
 {
 	int done = 0;
 
-	flush_skb_queue(&ap->xq);
-	lock_xmit_path(ap);
+	spin_lock_bh(&ap->xmit_lock);
 	if (ap->tpkt != NULL) {
 		kfree_skb(ap->tpkt);
 		ap->tpkt = 0;
-		clear_bit(XMIT_FULL, &ap->busy);
+		clear_bit(XMIT_FULL, &ap->xmit_flags);
 		done = 1;
 	}
-	unlock_xmit_path(ap);
-	if (done && ap->connected)
+	spin_unlock_bh(&ap->xmit_lock);
+	if (done)
 		ppp_output_wakeup(&ap->chan);
 }
 
@@ -750,30 +671,13 @@
 	} else if (skb->len < 2)
 		goto err;
 
-	/* pass to generic layer or queue it */
-	if (ap->connected) {
-		ppp_input(&ap->chan, skb);
-	} else {
-		skb_queue_tail(&ap->rq, skb);
-		/* drop old frames if queue too long */
-		while (ap->rq.qlen > PPPSYNC_MAX_RQLEN
-		       && (skb = skb_dequeue(&ap->rq)) != 0)
-			kfree(skb);
-		wake_up_interruptible(&ap->rwait);
-	}
+	/* pass to generic layer */
+	ppp_input(&ap->chan, skb);
 	return;
 
  err:
 	kfree_skb(skb);
-	if (ap->connected)
-		ppp_input_error(&ap->chan, code);
-}
-
-static inline void
-input_error(struct syncppp *ap, int code)
-{
-	if (ap->connected)
-		ppp_input_error(&ap->chan, code);
+	ppp_input_error(&ap->chan, code);
 }
 
 /* called when the tty driver has data for us. 
@@ -794,7 +698,7 @@
 
 	/* if flag set, then error, ignore frame */
 	if (flags != 0 && *flags) {
-		input_error(ap, *flags);
+		ppp_input_error(&ap->chan, *flags);
 		return;
 	}
 
@@ -805,7 +709,7 @@
 	if ((skb = ap->rpkt) == 0) {
 		if ((skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2)) == 0) {
 			printk(KERN_ERR "PPPsync: no memory (input pkt)\n");
-			input_error(ap, 0);
+			ppp_input_error(&ap->chan, 0);
 			return;
 		}
 		/* Try to get the payload 4-byte aligned */
@@ -815,7 +719,7 @@
 	}
 	if (count > skb_tailroom(skb)) {
 		/* packet overflowed MRU */
-		input_error(ap, 1);
+		ppp_input_error(&ap->chan, 1);
 	} else {
 		sp = skb_put(skb, count);
 		memcpy(sp, buf, count);
@@ -823,17 +727,12 @@
 	}
 }
 
-#ifdef MODULE
-int
-init_module(void)
-{
-	return ppp_sync_init();
-}
-
-void
-cleanup_module(void)
+void __exit
+ppp_sync_cleanup(void)
 {
 	if (tty_register_ldisc(N_SYNC_PPP, NULL) != 0)
 		printk(KERN_ERR "failed to unregister Sync PPP line discipline\n");
 }
-#endif /* MODULE */
+
+module_init(ppp_sync_init);
+module_exit(ppp_sync_cleanup);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c
--- v2.3.99-pre3/linux/drivers/net/sk98lin/skge.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/sk98lin/skge.c	Mon Mar 27 10:35:56 2000
@@ -412,21 +412,6 @@
 
 		pci_set_master(pdev);
 
-#ifdef __sparc__
-		/* Set the proper cache line size value, plus enable
-		 * write-invalidate and fast back-to-back on Sparc.
-		 */
-		{
-			SK_U16 pci_command;
-
-			SkPciWriteCfgByte(pAC, PCI_CACHE_LINE_SIZE, 0x10);
-
-			SkPciReadCfgWord(pAC, PCI_COMMAND, &pci_command);
-			pci_command |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK);
-			SkPciWriteCfgWord(pAC, PCI_COMMAND, pci_command);
-		}
-#endif
-
 		base_address = pdev->resource[0].start;
 
 #ifdef SK_BIG_ENDIAN
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.3.99-pre3/linux/drivers/net/sunhme.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/sunhme.c	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.94 2000/03/15 06:47:04 davem Exp $
+/* $Id: sunhme.c,v 1.95 2000/03/25 05:18:15 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.
@@ -2688,7 +2688,6 @@
 	struct pcidev_cookie *pcp;
 	struct happy_meal *hp;
 	unsigned long hpreg_base;
-	unsigned short pci_command;
 	int i, node, qfe_slot = -1;
 	char prom_name[64];
 
@@ -2844,20 +2843,6 @@
 	happy_meal_set_initial_advertisement(hp);
 
 	ether_setup(dev);
-
-	/* If we don't do this, nothing works. */
-	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-	pci_command |= PCI_COMMAND_MASTER;
-	pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-
-	/* Set the latency timer and cache line size as well,
-	 * PROM leaves it at zero.
-	 */
-	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
-	/* NOTE: Cache line size is in 32-bit word units. */
-	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
 
 #ifdef MODULE
 	/* We are home free at this point, link us in to the happy
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/tokenring/Config.in linux/drivers/net/tokenring/Config.in
--- v2.3.99-pre3/linux/drivers/net/tokenring/Config.in	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/tokenring/Config.in	Thu Mar 30 16:54:53 2000
@@ -14,7 +14,9 @@
    if [ "$CONFIG_TMS380TR" != "n" ]; then
       dep_tristate '    Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_TMS380TR
       dep_tristate '    Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_TMS380TR
-      dep_tristate '    Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_TMS380TR
+      if [ "$CONFIG_MCA" = "y" ]; then 
+         dep_tristate '    Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_TMS380TR
+      fi
    fi
    dep_tristate '  SMC ISA/MCA adapter support' CONFIG_SMCTR $CONFIG_TR
 fi
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c
--- v2.3.99-pre3/linux/drivers/net/tokenring/ibmtr.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/tokenring/ibmtr.c	Sun Apr  2 15:38:54 2000
@@ -88,6 +88,9 @@
  *      to support windowing into on adapter shared ram.
  *      i.e. Use LANAID to setup a PnP configuration with 16K RAM. Paging
  *      will shift this 16K window over the entire available shared RAM.
+ *
+ *      Changes by Peter De Schrijver (p2@mind.be) :
+ *      + fixed a problem with PCMCIA card removal
  */
 
 /* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value 
@@ -95,16 +98,8 @@
 
 #define IBMTR_DEBUG_MESSAGES 0
 
-#ifdef PCMCIA
-#define MODULE
-#endif
-
 #include <linux/module.h>
 
-#ifdef PCMCIA
-#undef MODULE
-#endif
-
 #define NO_AUTODETECT 1
 #undef NO_AUTODETECT
 /* #undef ENABLE_PAGING */
@@ -161,13 +156,13 @@
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/ibmtr.h>
 #include <net/checksum.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 
-#include "ibmtr.h"
 
 
 #define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args)
@@ -814,6 +809,9 @@
 
 	int i;
 
+	if(ti->open_status==CLOSED)
+		return;
+
 	address[0] = address[1] = address[2] = address[3] = 0;
 
 	mclist = dev->mc_list;
@@ -870,26 +868,28 @@
 
 	struct tok_info *ti=(struct tok_info *) dev->priv;
 
-	netif_stop_queue(dev);
-	SET_PAGE(ti->srb_page);	
-	isa_writeb(DIR_CLOSE_ADAPTER,
-	       ti->srb + offsetof(struct srb_close_adapter, command));
-	isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-	ti->open_status=CLOSED;
-
-	sleep_on(&ti->wait_for_tok_int);
-
-	SET_PAGE(ti->srb_page);
-	if (isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)))
-		DPRINTK("close adapter failed: %02X\n",
-			(int)isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
+	if(ti->open_status!=CLOSED) {
+		netif_stop_queue(dev);
+		SET_PAGE(ti->srb_page);	
+		isa_writeb(DIR_CLOSE_ADAPTER,
+	       	ti->srb + offsetof(struct srb_close_adapter, command));
+		isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+
+		ti->open_status=CLOSED;
+
+		sleep_on(&ti->wait_for_tok_int);
+
+		SET_PAGE(ti->srb_page);
+		if (isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)))
+			DPRINTK("close adapter failed: %02X\n",
+				(int)isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
 
 #ifdef PCMCIA
-	ti->sram = 0 ;
+		ti->sram = 0 ;
 #endif
-	DPRINTK("Adapter closed.\n");
-	MOD_DEC_USE_COUNT;
+		DPRINTK("Adapter closed.\n");
+		MOD_DEC_USE_COUNT;
+	}
 
 	return 0;
 }
@@ -937,6 +937,7 @@
     		if (status == 0xFF)
        		{
 		          DPRINTK("PCMCIA card removed.\n");
+                          ti->open_status=CLOSED;
 			  goto return_point ; 
        		}
 
@@ -944,6 +945,7 @@
       	        if ( isa_readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF)
     	        {
          		 DPRINTK("PCMCIA card removed.\n");
+                         ti->open_status=CLOSED;
 			 goto return_point ; 
       		}
 #endif
@@ -1851,6 +1853,7 @@
 	return 0;
 }
 
+#ifndef PCMCIA
 #ifdef MODULE
 
 /* 3COM 3C619C supports 8 interrupts, 32 I/O ports */
@@ -1908,3 +1911,4 @@
                 }
 }
 #endif /* MODULE */
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/wan/cycx_drv.c linux/drivers/net/wan/cycx_drv.c
--- v2.3.99-pre3/linux/drivers/net/wan/cycx_drv.c	Tue Jan 11 22:31:40 2000
+++ linux/drivers/net/wan/cycx_drv.c	Mon Apr  3 19:32:57 2000
@@ -48,14 +48,8 @@
 * Aug  8, 1998	acme		Initial version.
 */
 
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
+#include <linux/init.h>		/* __init */
 #include <linux/module.h>
-#else
-#define EXPORT_SYMBOL(function)
-#endif
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
@@ -66,12 +60,10 @@
 #include <asm/io.h>		/* read[wl], write[wl], ioremap, iounmap */
 
 #define	MOD_VERSION	0
-#define	MOD_RELEASE	5
+#define	MOD_RELEASE	6
 
-#ifdef MODULE
 MODULE_AUTHOR("Arnaldo Carvalho de Melo");
 MODULE_DESCRIPTION("Cyclom 2x Sync Card Driver");
-#endif
 
 /* Function Prototypes */
 /* Module entry points. These are called by the OS and must be public. */
@@ -129,20 +121,21 @@
  * Return:	0	Ok
  *		< 0	error.
  * Context:	process */
-#ifdef MODULE
-int init_module(void)
+
+int __init cycx_drv_init(void)
 {
 	printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE,
 			 copyright);
 
 	return 0;
 }
+
 /* Module 'remove' entry point.
  * o release all remaining system resources */
-void cleanup_module(void)
+void cycx_drv_cleanup(void)
 {
 }
-#endif
+
 /* Kernel APIs */
 /* Set up adapter.
  * o detect adapter type
@@ -599,4 +592,8 @@
 
 	return crc;
 }
+
+module_init(cycx_drv_init);
+module_exit(cycx_drv_cleanup);
+
 /* End */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/wan/cycx_main.c linux/drivers/net/wan/cycx_main.c
--- v2.3.99-pre3/linux/drivers/net/wan/cycx_main.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/wan/cycx_main.c	Mon Apr  3 19:32:57 2000
@@ -13,6 +13,8 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* 2000/04/02	acme		dprintk and cycx_debug
+* 				module_init/module_exit
 * 2000/01/21	acme		rename cyclomx_open to cyclomx_mod_inc_use_count
 *				and cyclomx_close to cyclomx_mod_dec_use_count
 * 2000/01/08	acme		cleanup
@@ -43,15 +45,21 @@
 #include <asm/uaccess.h>	/* kernel <-> user copy */
 #include <linux/init.h>         /* __init (when not using as a module) */
 
+/* Debug */
+
+unsigned int cycx_debug = 0;
+
 #ifdef MODULE
 MODULE_AUTHOR("Arnaldo Carvalho de Melo");
 MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver.");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "cyclomx debug level");
 #endif
 
 /* Defines & Macros */
 
 #define	DRV_VERSION	0		/* version number */
-#define	DRV_RELEASE	6		/* release (minor version) number */
+#define	DRV_RELEASE	7		/* release (minor version) number */
 #define	MAX_CARDS	1		/* max number of adapters */
 
 #ifndef	CONFIG_CYCLOMX_CARDS		/* configurable option */
@@ -60,10 +68,6 @@
 
 /* Function Prototypes */
 
-/* Module entry points */
-int init_module (void);
-void cleanup_module (void);
-
 /* WAN link driver entry points */
 static int setup (wan_device_t *wandev, wandev_conf_t *conf);
 static int shutdown (wan_device_t *wandev);
@@ -98,11 +102,7 @@
  *		< 0	error.
  * Context:	process
  */
-#ifdef MODULE
-int init_module (void)
-#else
 int __init cyclomx_init (void)
-#endif
 {
 	int cnt, err = 0;
 
@@ -156,8 +156,7 @@
  * o unregister all adapters from the WAN router
  * o release all remaining system resources
  */
-#ifdef MODULE
-void cleanup_module (void)
+void cyclomx_cleanup (void)
 {
 	int i = 0;
 
@@ -168,7 +167,7 @@
 
 	kfree(card_array);
 }
-#endif
+
 /* WAN Device Driver Entry Points */
 /*
  * Setup/configure WAN link driver.
@@ -384,5 +383,8 @@
 	card->state_tick = jiffies;
 	spin_unlock_irqrestore(&card->lock, host_cpu_flags);
 }
+
+module_init(cyclomx_init);
+module_exit(cyclomx_cleanup);
 
 /* End */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c
--- v2.3.99-pre3/linux/drivers/net/wan/cycx_x25.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/wan/cycx_x25.c	Mon Apr  3 19:32:57 2000
@@ -12,6 +12,10 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* 2000/04/02	acme		dprintk, cycx_debug
+* 				fixed the bug introduced in get_dev_by_lcn and
+* 				get_dev_by_dte_addr by the anonymous hacker
+* 				that converted this driver to softnet
 * 2000/01/08	acme		cleanup
 * 1999/10/27	acme		use ARPHRD_HWX25 so that the X.25 stack know
 *				that we have a X.25 stack implemented in
@@ -110,7 +114,7 @@
 	u32 idle_tmout;			/* sec, before disconnecting */
 	struct sk_buff *rx_skb;		/* receive socket buffer */
 	cycx_t *card;			/* -> owner */
-	struct enet_statistics ifstats;	/* interface statistics */
+	struct net_device_stats ifstats;/* interface statistics */
 } x25_channel_t;
 
 /* Function Prototypes */
@@ -178,13 +182,11 @@
 static void x25_dump_config(TX25Config *conf);
 static void x25_dump_stats(TX25Stats *stats);
 static void x25_dump_devs(wan_device_t *wandev);
-#define dprintk(format, a...) printk(format, ##a)
 #else
 #define hex_dump(msg, p, len)
 #define x25_dump_config(conf)
 #define x25_dump_stats(stats)
 #define x25_dump_devs(wandev)
-#define dprintk(format, a...)
 #endif
 /* Public Functions */
 
@@ -846,7 +848,7 @@
 	if (sizerem)
 		nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1);
 
-	dprintk(KERN_INFO "connect_intr:lcn=%d, local=%s, remote=%s\n",
+	dprintk(1, KERN_INFO "connect_intr:lcn=%d, local=%s, remote=%s\n",
 			  lcn, loc, rem);
 
 	if ((dev = get_dev_by_dte_addr(wandev, rem)) == NULL) {
@@ -872,7 +874,7 @@
 
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
 	cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key));
-	dprintk(KERN_INFO "%s: connect_confirm_intr:lcn=%d, key=%d\n",
+	dprintk(1, KERN_INFO "%s: connect_confirm_intr:lcn=%d, key=%d\n",
 			  card->devname, lcn, key);
 
 	if ((dev = get_dev_by_lcn(wandev, -key)) == NULL) {
@@ -897,7 +899,7 @@
 	u8 lcn;
 
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	dprintk(KERN_INFO "%s: disconnect_confirm_intr:lcn=%d\n",
+	dprintk(1, KERN_INFO "%s: disconnect_confirm_intr:lcn=%d\n",
 			  card->devname, lcn);
 	if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) {
 		/* Invalid channel, discard packet */
@@ -917,7 +919,7 @@
 	u8 lcn;
 
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	dprintk(KERN_INFO "disconnect_intr:lcn=%d\n", lcn);
+	dprintk(1, KERN_INFO "disconnect_intr:lcn=%d\n", lcn);
 
 	if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {
 		x25_channel_t *chan = dev->priv;
@@ -1172,7 +1174,7 @@
 	key = ffz(card->u.x.connection_keys);
 	set_bit(key, (void*)&card->u.x.connection_keys);
 	++key;
-	dprintk(KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key);
+	dprintk(1, KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key);
 	memset(d, 0, sizeof(d));
 	d[1] = key; /* user key */
 	d[2] = 0x10;
@@ -1259,6 +1261,8 @@
 	x25_channel_t *chan;
 
 	while (dev) {
+		chan = (x25_channel_t*)dev->priv;
+
 		if (chan->lcn == lcn)
 			break;
 		dev = chan->slave;
@@ -1273,6 +1277,8 @@
 	x25_channel_t *chan;
 
 	while (dev) {
+		chan = (x25_channel_t*)dev->priv;
+
 		if (!strcmp(chan->addr, dte))
 			break;
 		dev = chan->slave;
@@ -1296,7 +1302,7 @@
                 if (!chan->addr[0])
 			return -EINVAL; /* no destination address */
 
-                dprintk(KERN_INFO "%s: placing X.25 call to %s...\n",
+                dprintk(1, KERN_INFO "%s: placing X.25 call to %s...\n",
 				  card->devname, chan->addr);
 
                 if (x25_place_call(card, chan))
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c
--- v2.3.99-pre3/linux/drivers/net/wan/z85230.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/net/wan/z85230.c	Sun Apr  2 15:38:53 2000
@@ -1316,7 +1316,7 @@
  *	@rtable: Table of register, value pairs
  *	FIXME: ioctl to allow user uploaded tables
  *
- *	Load a Z8530 channel up from the system data> We use +16 to 
+ *	Load a Z8530 channel up from the system data. We use +16 to 
  *	indicate the 'prime' registers. The value 255 terminates the
  *	table
  */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- v2.3.99-pre3/linux/drivers/parport/ChangeLog	Mon Mar 27 08:08:27 2000
+++ linux/drivers/parport/ChangeLog	Mon Mar 27 11:27:07 2000
@@ -1,3 +1,8 @@
+2000-03-27  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (parport_pc_ecp_read_block_pio): Correct operation
+	when peripheral is trying to send data when we stop listening.
+
 2000-03-22  Tim Waugh  <twaugh@redhat.com>
 
 	* init.c (parport_setup): Fix return value.
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.3.99-pre3/linux/drivers/parport/parport_pc.c	Mon Mar 27 08:08:27 2000
+++ linux/drivers/parport/parport_pc.c	Mon Mar 27 11:27:07 2000
@@ -178,9 +178,6 @@
 	int cnfga;
 	const struct parport_pc_private *priv = p->physport->private_data;
 
-	/* Prevent further data transfer. */
-	frob_econtrol (p, 0xe0, ECR_TST << 5);
-
 	/* Adjust for the contents of the FIFO. */
 	for (residue = priv->fifo_depth; ; residue--) {
 		if (inb (ECONTROL (p)) & 0x2)
@@ -862,7 +859,8 @@
 						       length, flags);
 
 	/* Switch to reverse mode if necessary. */
-	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
+	if ((port->ieee1284.phase != IEEE1284_PH_REV_IDLE) &&
+	    (port->ieee1284.phase != IEEE1284_PH_REV_DATA)) {
 		/* Event 38: Set nAutoFd low */
 		parport_frob_control (port,
 				      PARPORT_CONTROL_AUTOFD,
@@ -879,7 +877,7 @@
 		parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
 	}
 
-	/* Set up ECP parallel port mode.*/
+	/* Set up ECP FIFO mode.*/
 	parport_pc_data_reverse (port); /* Must be in PS2 mode */
 	parport_pc_frob_control (port,
 				 PARPORT_CONTROL_STROBE |
@@ -951,14 +949,23 @@
 		left--;
 	}
 
+	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+
+	/* Go to forward idle mode to shut the peripheral up. */
+	parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+	parport_wait_peripheral (port,
+				 PARPORT_STATUS_PAPEROUT,
+				 PARPORT_STATUS_PAPEROUT);
+	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
 	/* Finish up. */
-	if (change_mode (port, ECR_PS2) == -EBUSY) {
+	{
 		int lost = get_fifo_residue (port);
-		printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name,
-			lost);
+		if (lost)
+			/* Shouldn't happen with compliant peripherals. */
+			printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n",
+				port->name, lost);
 	}
-
-	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
 
 	return length - left;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/parport/parport_sunbpp.c linux/drivers/parport/parport_sunbpp.c
--- v2.3.99-pre3/linux/drivers/parport/parport_sunbpp.c	Wed Dec 29 13:13:16 1999
+++ linux/drivers/parport/parport_sunbpp.c	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: parport_sunbpp.c,v 1.9 1999/10/14 05:59:43 ecd Exp $
+/* $Id: parport_sunbpp.c,v 1.10 2000/03/27 01:47:56 anton Exp $
  * Parallel-port routines for Sun architecture
  * 
  * Author: Derrick J. Brashear <shadow@dementia.org>
@@ -334,6 +334,8 @@
 		sbus_iounmap(base, size);
 		return 0;
 	}
+
+	p->size = size;
 
 	dprintk(("init_one_port: request_irq(%08x:%p:%x:%s:%p) ",
 		p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p));
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/parport/share.c linux/drivers/parport/share.c
--- v2.3.99-pre3/linux/drivers/parport/share.c	Sat Feb 26 22:31:47 2000
+++ linux/drivers/parport/share.c	Mon Apr  3 13:24:05 2000
@@ -103,6 +103,19 @@
 	request_module ("parport_lowlevel");
 }
 
+/**
+ * parport_register_driver - register a parallel port device driver
+ * @drv: structure describing the driver
+ *
+ * This can be called by a parallel port device driver in order to
+ * receive notifications about ports being found in the system, as
+ * well as ports no longer available.
+ *
+ * The @drv structure is allocated by the caller and must not be
+ * deallocated until after calling parport_unregister_driver().
+ *
+ * Returns 0 on success.  Currently it always succeeds.
+ **/
 int parport_register_driver (struct parport_driver *drv)
 {
 	struct parport *port;
@@ -121,6 +134,23 @@
 	return 0;
 }
 
+/**
+ * parport_unregister_driver - deregister a parallel port device driver
+ * @arg: structure describing the driver that was given to
+ *       parport_register_driver()
+ *
+ * This should be called by a parallel port device driver that has
+ * registered itself using parport_register_driver() when it is about
+ * to be unloaded.
+ *
+ * When it returns, the driver's attach() routine will no longer be
+ * called, and for each port that attach() was called for, the
+ * detach() routine will hae been called.
+ *
+ * If the caller's attach() function can block, it is their
+ * responsibility to make sure to wait for it to exit before
+ * unloading.
+ **/
 void parport_unregister_driver (struct parport_driver *arg)
 {
 	struct parport_driver *drv = driver_chain, *olddrv = NULL;
@@ -149,8 +179,17 @@
 	}
 }
 
-/* Return a list of all the ports we know about.  This function shouldn't
- * really be used -- use parport_register_driver instead. */
+/**
+ * parport_enumerate - return a list of the system's parallel ports
+ *
+ * This returns the head of the list of parallel ports in the system.
+ * The structure that is returned describes the first port in the
+ * list, and its 'next' member points to the next port, or %NULL if
+ * it's the last port.
+ *
+ * If there are no parallel ports in the system, parport_enumerate()
+ * will return %NULL.
+ **/
 struct parport *parport_enumerate(void)
 {
 	if (!portlist)
@@ -159,6 +198,33 @@
 	return portlist;
 }
 
+/**
+ * parport_register_port - register a parallel port
+ * @base: base I/O address
+ * @irq: IRQ line
+ * @dma: DMA channel
+ * @ops: pointer to the port driver's port operations structure
+ *
+ * When a parallel port (lowlevel) driver finds a port that should be
+ * made available to parallel port device drivers, it should call
+ * parport_register_port().  The @base, @irq, and @dma parameters are
+ * for the convenience of port drivers, and for ports where they
+ * aren't meaningful needn't be set to anything special.  They can be
+ * altered afterwards by adjusting the relevant members of the parport
+ * structure that is returned and represents the port.  They should
+ * not be tampered with after calling parport_announce_port, however.
+ *
+ * If there are parallel port device drivers in the system that have
+ * registered themselves using parport_register_driver(), they are not
+ * told about the port at this time; that is done by
+ * parport_announce_port().
+ *
+ * The @ops structure is allocated by the caller, and must not be
+ * deallocated before calling parport_unregister_port().
+ *
+ * If there is no memory to allocate a new parport structure, this
+ * function will return %NULL.
+ **/
 struct parport *parport_register_port(unsigned long base, int irq, int dma,
 				      struct parport_operations *ops)
 {
@@ -243,6 +309,17 @@
 	return tmp;
 }
 
+/**
+ * parport_announce_port - tell device drivers about a parallel port
+ * @port: parallel port to announce
+ *
+ * After a port driver has registered a parallel port with
+ * parport_register_port, and performed any necessary initialisation
+ * or adjustments, it should call parport_announce_port() in order to
+ * notify all device drivers that have called
+ * parport_register_driver().  Their attach() functions will be
+ * called, with @port as the parameter.
+ **/
 void parport_announce_port (struct parport *port)
 {
 #ifdef CONFIG_PARPORT_1284
@@ -286,6 +363,23 @@
 	kfree(port);
 }
 
+/**
+ * parport_unregister_port - deregister a parallel port
+ * @port: parallel port to deregister
+ *
+ * When a parallel port driver is forcibly unloaded, or a parallel
+ * port becomes inaccessible, the port driver must call this function
+ * in order to deal with device drivers that still want to use it.
+ *
+ * The parport structure associated with the port has its operations
+ * structure replaced with one containing 'null' operations that
+ * return errors or just don't do anything.
+ *
+ * Any drivers that have registered themselves using
+ * parport_register_driver() are notified that the port is no longer
+ * accessible by having their detach() routines called with @port as
+ * the parameter.
+ **/
 void parport_unregister_port(struct parport *port)
 {
 	struct parport *p;
@@ -320,10 +414,76 @@
 		free_port (port);
 }
 
-struct pardevice *parport_register_device(struct parport *port, const char *name,
-			  int (*pf)(void *), void (*kf)(void *),
-			  void (*irq_func)(int, void *, struct pt_regs *), 
-			  int flags, void *handle)
+/**
+ * parport_register_device - register a device on a parallel port
+ * @port: port to which the device is attached
+ * @name: a name to refer to the device
+ * @pf: preemption callback
+ * @kf: kick callback (wake-up)
+ * @irq_func: interrupt handler
+ * @flags: registration flags
+ * @handle: data for callback functions
+ *
+ * This function, called by parallel port device drivers, declares
+ * that a device is connected to a port, and tells the system all it
+ * needs to know.
+ *
+ * The @name is allocated by the caller and must not be deallocated
+ * until the caller calls @parport_unregister_device for that device.
+ *
+ * The preemption callback function, @pf, is called when this device
+ * driver has claimed access to the port but another device driver
+ * wants to use it.  It is given @handle as its parameter, and should
+ * return zero if it is willing for the system to release the port to
+ * another driver on its behalf.  If it wants to keep control of the
+ * port it should return non-zero, and no action will be taken.  It is
+ * good manners for the driver to try to release the port at the
+ * earliest opportunity after its preemption callback rejects a
+ * preemption attempt.  Note that if a preemption callback is happy
+ * for preemption to go ahead, there is no need to release the port;
+ * it is done automatically.  This function may not block, as it may
+ * be called from interrupt context.  If the device driver does not
+ * support preemption, @pf can be %NULL.
+ *
+ * The wake-up ("kick") callback function, @kf, is called when the
+ * port is available to be claimed for exclusive access; that is,
+ * parport_claim() is guaranteed to succeed when called from inside
+ * the wake-up callback function.  If the driver wants to claim the
+ * port it should do so; otherwise, it need not take any action.  This
+ * function may not block, as it may be called from interrupt context.
+ * If the device driver does not want to be explicitly invited to
+ * claim the port in this way, @kf can be %NULL.
+ *
+ * The interrupt handler, @irq_func, is called when an interrupt
+ * arrives from the parallel port.  Note that if a device driver wants
+ * to use interrupts it should use parport_enable_irq(), and can also
+ * check the irq member of the parport structure representing the
+ * port.
+ *
+ * The parallel port (lowlevel) driver is the one that has called
+ * request_irq() and whose interrupt handler is called first.  This
+ * handler does whatever needs to be done to the hardware to
+ * acknowledge the interrupt (for PC-style ports there is nothing
+ * special to be done).  It then tells the IEEE 1284 code about the
+ * interrupt, which may involve reacting to an IEEE 1284 event
+ * depending on the current IEEE 1284 phase.  After this, it calls
+ * @irq_func.  Needless to say, @irq_func will be called from
+ * interrupt context, and may not block.
+ *
+ * The %PARPORT_DEV_EXCL flag is for preventing port sharing, and so
+ * should only be used when sharing the port with other device drivers
+ * is impossible and would lead to incorrect behaviour.  Use it
+ * sparingly!  Normally, @flags will be zero.
+ *
+ * This function returns a pointer to a structure that represents the
+ * device on the port, or %NULL if there is not enough memory to
+ * allocate space for that structure.
+ **/
+struct pardevice *
+parport_register_device(struct parport *port, const char *name,
+			int (*pf)(void *), void (*kf)(void *),
+			void (*irq_func)(int, void *, struct pt_regs *), 
+			int flags, void *handle)
 {
 	struct pardevice *tmp;
 
@@ -341,17 +501,25 @@
 		}
 	}
 
+	/* We up our own module reference count, and that of the port
+           on which a device is to be registered, to ensure that
+           neither of us gets unloaded while we sleep in (e.g.)
+           kmalloc.  To be absolutely safe, we have to require that
+           our caller doesn't sleep in between parport_enumerate and
+           parport_register_device.. */
+	inc_parport_count();
+	port->ops->inc_use_count();
+
 	tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL);
 	if (tmp == NULL) {
 		printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
-		return NULL;
+		goto out;
 	}
 
 	tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL);
 	if (tmp->state == NULL) {
 		printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
-		kfree(tmp);
-		return NULL;
+		goto out_free_pardevice;
 	}
 
 	tmp->name = name;
@@ -376,12 +544,10 @@
 	if (flags & PARPORT_DEV_EXCL) {
 		if (port->physport->devices) {
 			spin_unlock (&port->physport->pardevice_lock);
-			kfree (tmp->state);
-			kfree (tmp);
 			printk (KERN_DEBUG
 				"%s: cannot grant exclusive access for "
 				"device %s\n", port->name, name);
-			return NULL;
+			goto out_free_all;
 		}
 		port->flags |= PARPORT_FLAG_EXCL;
 	}
@@ -392,9 +558,6 @@
 	port->physport->devices = tmp;
 	spin_unlock(&port->physport->pardevice_lock);
 
-	inc_parport_count();
-	port->ops->inc_use_count();
-
 	init_waitqueue_head(&tmp->wait_q);
 	tmp->timeslice = parport_default_timeslice;
 	tmp->waitnext = tmp->waitprev = NULL;
@@ -406,8 +569,23 @@
 	port->ops->init_state(tmp, tmp->state);
 	parport_device_proc_register(tmp);
 	return tmp;
+
+ out_free_all:
+	kfree (tmp->state);
+ out_free_pardevice:
+	kfree (tmp);
+ out:
+	dec_parport_count();
+	port->ops->dec_use_count();
+	return NULL;
 }
 
+/**
+ * parport_unregister_device - deregister a device on a parallel port
+ * @dev: pointer to structure representing device
+ *
+ * This undoes the effect of parport_register_device().
+ **/
 void parport_unregister_device(struct pardevice *dev)
 {
 	struct parport *port;
@@ -454,6 +632,16 @@
 		free_port (port);
 }
 
+/**
+ * parport_claim - claim access to a parallel port device
+ * @dev: pointer to structure representing a device on the port
+ *
+ * This function will not block and so can be used from interrupt
+ * context.  If parport_claim() succeeds in claiming access to the
+ * port it returns zero and the port is available to use.  It may fail
+ * (returning non-zero) if the port is in use by another driver and
+ * that driver is not willing to relinquish control of the port.
+ **/
 int parport_claim(struct pardevice *dev)
 {
 	struct pardevice *oldcad;
@@ -555,6 +743,15 @@
 	return -EAGAIN;
 }
 
+/**
+ * parport_claim_or_block - claim access to a parallel port device
+ * @dev: pointer to structure representing a device on the port
+ *
+ * This behaves like parport_claim(), but will block if necessary to
+ * wait for the port to be free.  A return value of 1 indicates that
+ * it slept; 0 means that it succeeded without needing to sleep.  A
+ * negative error code indicates failure.
+ **/
 int parport_claim_or_block(struct pardevice *dev)
 {
 	int r;
@@ -597,6 +794,14 @@
 	return r;
 }
 
+/**
+ * parport_release - give up access to a parallel port device
+ * @dev: pointer to structure representing parallel port device
+ *
+ * This function cannot fail, but it should not be called without the
+ * port claimed.  Similarly, if the port is already claimed you should
+ * not try claiming it again.
+ **/
 void parport_release(struct pardevice *dev)
 {
 	struct parport *port = dev->port->physport;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/pci/gen-devlist.c linux/drivers/pci/gen-devlist.c
--- v2.3.99-pre3/linux/drivers/pci/gen-devlist.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/pci/gen-devlist.c	Mon Mar 27 14:29:13 2000
@@ -1,12 +1,14 @@
 /*
  *	Generate devlist.h and classlist.h from the PCI ID file.
  *
- *	(c) 1999 Martin Mares <mj@suse.cz>
+ *	(c) 1999--2000 Martin Mares <mj@suse.cz>
  */
 
 #include <stdio.h>
 #include <string.h>
 
+#define MAX_NAME_SIZE 79
+
 static void
 pq(FILE *f, const char *c)
 {
@@ -22,9 +24,11 @@
 int
 main(void)
 {
-	char line[1024], *c, vend[8];
+	char line[1024], *c, *bra, vend[8];
 	int vendors = 0;
 	int mode = 0;
+	int lino = 0;
+	int vendor_len = 0;
 	FILE *devf, *clsf;
 
 	devf = fopen("devlist.h", "w");
@@ -35,6 +39,7 @@
 	}
 
 	while (fgets(line, sizeof(line)-1, stdin)) {
+		lino++;
 		if ((c = strchr(line, '\n')))
 			*c = 0;
 		if (!line[0] || line[0] == '#')
@@ -56,6 +61,16 @@
 					c = line + 5;
 					while (*c == ' ')
 						*c++ = 0;
+					if (vendor_len + strlen(c) + 1 > MAX_NAME_SIZE) {
+						/* Too long, try cutting off long description */
+						bra = strchr(c, '[');
+						if (bra && bra > c && bra[-1] == ' ')
+							bra[-1] = 0;
+						if (vendor_len + strlen(c) + 1 > MAX_NAME_SIZE) {
+							fprintf(stderr, "Line %d: Device name too long\n", lino);
+							return 1;
+						}
+					}
 					fprintf(devf, "\tDEVICE(%s,%s,\"", vend, line+1);
 					pq(devf, c);
 					fputs("\")\n", devf);
@@ -80,13 +95,18 @@
 				fputs("ENDVENDOR()\n\n", devf);
 			vendors++;
 			strcpy(vend, line);
+			vendor_len = strlen(c);
+			if (vendor_len + 24 > MAX_NAME_SIZE) {
+				fprintf(stderr, "Line %d: Vendor name too long\n", lino);
+				return 1;
+			}
 			fprintf(devf, "VENDOR(%s,\"", vend);
 			pq(devf, c);
 			fputs("\")\n", devf);
 			mode = 1;
 		} else {
 		err:
-			fprintf(stderr, "Syntax error in mode %d: %s\n", mode, line);
+			fprintf(stderr, "Line %d: Syntax error in mode %d: %s\n", lino, mode, line);
 			return 1;
 		}
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- v2.3.99-pre3/linux/drivers/pci/pci.ids	Sun Mar 19 18:35:30 2000
+++ linux/drivers/pci/pci.ids	Mon Mar 27 14:29:13 2000
@@ -1245,7 +1245,7 @@
 10db  Rohm LSI Systems, Inc.
 10dc  CERN/ECP/EDU
 	0001  STAR/RD24 SCI-PCI (PMC)
-	0002  TAR/RD24 SCI-PCI (PMC) [ATT 2C15-3 (FPGA)  SCI bridge on PCI 5 Volt card]
+	0002  TAR/RD24 SCI-PCI (PMC)
 	0021  HIPPI destination
 	0022  HIPPI source
 	10dc  ATT2C15-3 FPGA
@@ -1328,7 +1328,7 @@
 	8089  Kingsberg Spacetec Serial Output Board
 	809c  S5933_HEPC3
 	811a  PCI-IEEE1355-DS-DE Interface
-	8170  S5933 "Matchmaker" PCI Chipset Development Tool
+	8170  S5933 "Matchmaker" [PCI Chipset Development Tool]
 10e9  Alps Electric Co., Ltd.
 10ea  Intergraphics Systems
 	1680  IGA-1680
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/pci/setup-res.c linux/drivers/pci/setup-res.c
--- v2.3.99-pre3/linux/drivers/pci/setup-res.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/pci/setup-res.c	Mon Mar 27 14:29:13 2000
@@ -89,7 +89,7 @@
 	return 0;
 }
 
-static void
+void
 pdev_assign_unassigned_resources(struct pci_dev *dev)
 {
 	u32 reg;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.3.99-pre3/linux/drivers/scsi/ChangeLog.ncr53c8xx	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Sat Apr  1 07:45:31 2000
@@ -1,3 +1,13 @@
+Sat Apr 1  12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2h
+	- Fix a compilation problem on Alpha introduced in version 3.2g.
+          (`port' changed to `base_io').
+	- Move from `sym' to this driver a tiny change for __sparc__ that 
+	  applies to cache line size (? Probably from David S Miller).
+	- Make sure no data transfer will happen for Scsi_Cmnd requests 
+	  that supply SCSI_DATA_NONE direction (this avoids some BUG() 
+	  statement in the PCI code when a data buffer is also supplied).
+
 Mon March 6  23:15 2000 Gerard Roudier (groudier@club-internet.fr)
 	* revision 3.2g
 	- Add the file sym53c8xx_comm.h that collects code that should 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx
--- v2.3.99-pre3/linux/drivers/scsi/ChangeLog.sym53c8xx	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/ChangeLog.sym53c8xx	Sat Apr  1 07:45:31 2000
@@ -1,3 +1,11 @@
+Sat Apr 1  12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* revision 1.5l
+	- Tiny change for __sparc__ appeared in 2.3.99-pre4.1 that 
+	  applies to cache line size (? Probably from David S Miller).
+	- Make sure no data transfer will happen for Scsi_Cmnd requests 
+	  that supply SCSI_DATA_NONE direction (this avoids some BUG() 
+	  statement in the PCI code when a data buffer is also supplied).
+
 Mon Mar  6 23:30 2000 Gerard Roudier (groudier@club-internet.fr)
 	* version sym53c8xx-1.5k
 	- Test against expected data transfer direction from SCRIPTS.
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.3.99-pre3/linux/drivers/scsi/Config.in	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/Config.in	Mon Mar 27 09:45:33 2000
@@ -55,7 +55,9 @@
    bool '  Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS
    int  '  Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
 fi
-dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI
+if [ "$CONFIG_X86" = "y" ]; then
+   dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI
+fi
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
 dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI
@@ -65,6 +67,7 @@
 if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then
    bool '  Omit FlashPoint support' CONFIG_SCSI_OMIT_FLASHPOINT
 fi
+dep_tristate 'DMX3191D SCSI support' CONFIG_SCSI_DMX3191D $CONFIG_SCSI $CONFIG_PCI
 dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
 dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support' CONFIG_SCSI_EATA $CONFIG_SCSI
 if [ "$CONFIG_SCSI_EATA" != "n" ]; then
@@ -86,10 +89,8 @@
 		"Port CONFIG_SCSI_G_NCR5380_PORT \
 		 Memory CONFIG_SCSI_G_NCR5380_MEM" Port
 fi
-if [ "$CONFIG_PCI" = "y" ]; then
-   dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI
-   dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI
-fi
+dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI $CONFIG_PCI
+dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI $CONFIG_PCI
 if [ "$CONFIG_PARPORT" != "n" ]; then
    dep_tristate 'IOMEGA parallel port (ppa - older drives)' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
    dep_tristate 'IOMEGA parallel port (imm - newer drives)' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT
@@ -101,13 +102,11 @@
 dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI
 dep_tristate 'symbios 53c416 SCSI support' CONFIG_SCSI_SYM53C416 $CONFIG_SCSI
 dep_tristate 'Simple 53c710 SCSI support (Compaq, NCR machines)' CONFIG_SCSI_SIM710 $CONFIG_SCSI
-if [ "$CONFIG_PCI" = "y" ]; then
-   dep_tristate 'NCR53c7,8xx SCSI support'  CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI
-   if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then
-      bool '  always negotiate synchronous transfers' CONFIG_SCSI_NCR53C7xx_sync
-      bool '  allow FAST-SCSI [10MHz]' CONFIG_SCSI_NCR53C7xx_FAST
-      bool '  allow DISCONNECT' CONFIG_SCSI_NCR53C7xx_DISCONNECT
-   fi
+dep_tristate 'NCR53c7,8xx SCSI support'  CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI $CONFIG_PCI
+if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then
+   bool '  always negotiate synchronous transfers' CONFIG_SCSI_NCR53C7xx_sync
+   bool '  allow FAST-SCSI [10MHz]' CONFIG_SCSI_NCR53C7xx_FAST
+   bool '  allow DISCONNECT' CONFIG_SCSI_NCR53C7xx_DISCONNECT
 fi
 if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then
    dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
@@ -149,7 +148,9 @@
    dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
    dep_tristate 'Qlogic QLA 1280 SCSI support' CONFIG_SCSI_QLOGIC_1280 $CONFIG_SCSI
 fi
-dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
+if [ "$CONFIG_X86" = "y" ]; then
+   dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
+fi
 if [ "$CONFIG_PCI" = "y" ]; then
    dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
    if [ "$CONFIG_SCSI_DC390T" != "n" ]; then
@@ -162,7 +163,9 @@
       bool '  enable elevator sorting' CONFIG_SCSI_U14_34F_LINKED_COMMANDS
       int  '  maximum number of queued commands' CONFIG_SCSI_U14_34F_MAX_TAGS 8
    fi
-dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
+if [ "$CONFIG_X86" = "y" ]; then
+   dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
+fi
 #
 # Note - this is a very special 'host' adapter that simulates the presence of some disks.
 # It can come in very handy for troubleshooting.  Anyone else is welcome to use it - all
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.3.99-pre3/linux/drivers/scsi/Makefile	Mon Mar 27 08:08:27 2000
+++ linux/drivers/scsi/Makefile	Mon Mar 27 09:44:58 2000
@@ -613,6 +613,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_DMX3191D),y)
+L_OBJS += dmx3191d.o
+else
+  ifeq ($(CONFIG_SCSI_DMX3191D),m)
+  M_OBJS += dmx3191d.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_DTC3280),y)
 L_OBJS += dtc.o
 else
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/dmx3191d.c linux/drivers/scsi/dmx3191d.c
--- v2.3.99-pre3/linux/drivers/scsi/dmx3191d.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/dmx3191d.c	Mon Mar 27 09:48:11 2000
@@ -0,0 +1,125 @@
+
+/*
+    dmx3191d.c - midlevel driver for the Domex DMX3191D SCSI card.
+    Copyright (C) 2000 by Massimo Piccioni <dafastidio@libero.it>
+
+    Based on the generic NCR5380 driver by Drew Eckhardt et al.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/stat.h>
+#include <linux/version.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+#include "sd.h"
+
+#include "dmx3191d.h"
+
+/* play with these values to tune up your system performances */
+/* default setting from g_NCR5380.c */
+/*
+#define USLEEP
+#define USLEEP_POLL		1
+#define USLEEP_SLEEP		20
+#define USLEEP_WAITLONG		500
+*/
+
+#define AUTOSENSE
+#include "NCR5380.h"
+#include "NCR5380.c"
+
+
+int __init dmx3191d_detect(Scsi_Host_Template *tmpl) {
+	int boards = 0;
+	struct Scsi_Host *instance = NULL;
+	struct pci_dev *pdev = NULL;
+
+	if (!pci_present()) {
+		dmx3191d_printk("PCI support not enabled\n");
+		return 0;
+	}
+
+	tmpl->proc_name = DMX3191D_DRIVER_NAME;
+
+	while ((pdev = pci_find_device(PCI_VENDOR_ID_DOMEX,
+			PCI_DEVICE_ID_DOMEX_DMX3191D, pdev))) {
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
+		unsigned long port = pdev->base_address[0] & PCI_IOADDRESS_MASK;
+#else
+		unsigned long port = pdev->resource[0].start;
+#endif	/* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) */
+
+		if (check_region(port, DMX3191D_REGION)) {
+			dmx3191d_printk("region 0x%lx-0x%lx already reserved\n",
+				port, port + DMX3191D_REGION);
+			continue;
+		}
+
+		request_region(port, DMX3191D_REGION, DMX3191D_DRIVER_NAME);
+
+		instance = scsi_register(tmpl, sizeof(struct NCR5380_hostdata));
+		instance->io_port = port;
+		instance->irq = pdev->irq;
+		NCR5380_init(instance, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
+
+		if (request_irq(pdev->irq, dmx3191d_do_intr, SA_SHIRQ,
+				DMX3191D_DRIVER_NAME, instance)) {
+			dmx3191d_printk("irq %d not available\n", pdev->irq);
+			/* Steam powered scsi controllers run without an IRQ
+			   anyway */
+			instance->irq = IRQ_NONE;
+		}
+
+		boards++;
+	}
+	return boards;
+}
+
+const char * dmx3191d_info(struct Scsi_Host *host) {
+	static const char *info ="Domex DMX3191D";
+
+	return info;
+}
+
+int dmx3191d_release_resources(struct Scsi_Host *instance)
+{
+	release_region(instance->io_port, DMX3191D_REGION);
+	if(instance->irq!=IRQ_NONE)
+		free_irq(instance->irq, instance);
+
+	return 0;
+}
+
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = DMX3191D;
+
+#include "scsi_module.c"
+
+#endif	/* MODULE */
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/dmx3191d.h linux/drivers/scsi/dmx3191d.h
--- v2.3.99-pre3/linux/drivers/scsi/dmx3191d.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/dmx3191d.h	Mon Mar 27 09:48:11 2000
@@ -0,0 +1,74 @@
+
+/*
+    dmx3191d.h - defines for the Domex DMX3191D SCSI card.
+    Copyright (C) 2000 by Massimo Piccioni <dafastidio@libero.it>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+*/
+
+#ifndef __DMX3191D_H
+#define __DMX3191D_H
+
+#define DMX3191D_DRIVER_NAME	"dmx3191d"
+#define DMX3191D_REGION		8
+
+#ifndef PCI_VENDOR_ID_DOMEX
+#define PCI_VENDOR_ID_DOMEX		0x134a
+#define PCI_DEVICE_ID_DOMEX_DMX3191D	0x0001
+#endif
+
+#define dmx3191d_printk( args... )	printk(__FILE__": " ##args)
+
+#ifndef ASM
+int dmx3191d_abort(Scsi_Cmnd *);
+int dmx3191d_detect(Scsi_Host_Template *);
+const char* dmx3191d_info(struct Scsi_Host *);
+int dmx3191d_proc_info(char *, char **, off_t, int, int, int);
+int dmx3191d_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int dmx3191d_release_resources(struct Scsi_Host *);
+int dmx3191d_reset(Scsi_Cmnd *, unsigned int);
+
+
+#if defined(HOSTS_C) || defined(MODULE)
+#define DMX3191D {				\
+	proc_info:	dmx3191d_proc_info,		\
+	name:		"Domex DMX3191D",		\
+	detect:		dmx3191d_detect,		\
+	release:	dmx3191d_release_resources,	\
+	info:		dmx3191d_info,			\
+	queuecommand:	dmx3191d_queue_command,		\
+	abort:		dmx3191d_abort,			\
+	reset:		dmx3191d_reset, 		\
+	bios_param:	NULL,				\
+	can_queue:	32,				\
+        this_id:	7,				\
+        sg_tablesize:	SG_ALL,				\
+	cmd_per_lun:	2,				\
+        use_clustering:	DISABLE_CLUSTERING		\
+}
+#endif	/* HOSTS_C || MODULE */
+
+
+#ifndef HOSTS_C
+#define NCR5380_read(reg)			inb(port + reg)
+#define NCR5380_write(reg, value)		outb(value, port + reg)
+
+#define NCR5380_implementation_fields		unsigned int port
+#define NCR5380_local_declare()			NCR5380_implementation_fields
+#define NCR5380_setup(instance)			port = instance->io_port
+
+#define NCR5380_abort				dmx3191d_abort
+#define do_NCR5380_intr				dmx3191d_do_intr
+#define NCR5380_intr				dmx3191d_intr
+#define NCR5380_proc_info			dmx3191d_proc_info
+#define NCR5380_queue_command			dmx3191d_queue_command
+#define NCR5380_reset				dmx3191d_reset
+
+#endif	/* HOSTS_C */
+#endif	/* ASM */
+
+#endif	/* __DMX3191D_H */
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.3.99-pre3/linux/drivers/scsi/esp.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/scsi/esp.c	Thu Mar 30 16:54:54 2000
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.92 2000/02/18 13:49:58 davem Exp $
+/* $Id: esp.c,v 1.94 2000/03/30 02:09:10 davem Exp $
  * esp.c:  EnhancedScsiProcessor Sun SCSI driver code.
  *
  * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
@@ -4346,6 +4346,13 @@
 		ESP_INTSON(esp->dregs);
 	}
 	spin_unlock_irqrestore(&esp->lock, flags);
+}
+
+int esp_revoke(Scsi_Device* SDptr)
+{
+	struct esp *esp = (struct esp *) SDptr->host->hostdata;
+	esp->targets_present &= ~(1 << SDptr->id);
+	return 0;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/esp.h linux/drivers/scsi/esp.h
--- v2.3.99-pre3/linux/drivers/scsi/esp.h	Wed Dec 29 13:13:18 1999
+++ linux/drivers/scsi/esp.h	Mon Apr 10 23:25:00 2000
@@ -1,4 +1,4 @@
-/* $Id: esp.h,v 1.27 1999/12/15 14:12:52 davem Exp $
+/* $Id: esp.h,v 1.28 2000/03/30 01:33:17 davem Exp $
  * esp.h:  Defines and structures for the Sparc ESP (Enhanced SCSI
  *         Processor) driver under Linux.
  *
@@ -398,12 +398,14 @@
 extern int esp_reset(Scsi_Cmnd *, unsigned int);
 extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
 			 int hostno, int inout);
+extern int esp_revoke(Scsi_Device* SDptr);
 
 #define SCSI_SPARC_ESP {                                        \
 		proc_name:      "esp",				\
 		proc_info:      &esp_proc_info,			\
 		name:           "Sun ESP 100/100a/200",		\
 		detect:         esp_detect,			\
+		revoke:		esp_revoke,			\
 		info:           esp_info,			\
 		command:        esp_command,			\
 		queuecommand:   esp_queue,			\
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.3.99-pre3/linux/drivers/scsi/hosts.c	Sat Feb 26 22:31:48 2000
+++ linux/drivers/scsi/hosts.c	Mon Mar 27 09:48:11 2000
@@ -205,6 +205,10 @@
 #include "t128.h"
 #endif
 
+#ifdef CONFIG_SCSI_DMX3191D
+#include "dmx3191d.h"
+#endif
+
 #ifdef CONFIG_SCSI_DTC3280
 #include "dtc.h"
 #endif
@@ -549,6 +553,9 @@
 #endif
 #ifdef CONFIG_SCSI_T128
     TRANTOR_T128,
+#endif
+#ifdef CONFIG_SCSI_DMX3191D
+        DMX3191D,
 #endif
 #ifdef CONFIG_SCSI_DTC3280
         DTC3x80,
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v2.3.99-pre3/linux/drivers/scsi/hosts.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/hosts.h	Mon Apr 10 23:24:58 2000
@@ -96,6 +96,8 @@
      */
     int (* detect)(struct SHT *);
 
+    int (*revoke)(Scsi_Device *);
+
     /* Used with loadable modules to unload the host structures.  Note:
      * there is a default action built into the modules code which may
      * be sufficient for most host adapters.  Thus you may not have to supply
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.3.99-pre3/linux/drivers/scsi/ncr53c8xx.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/ncr53c8xx.c	Sat Apr  1 07:45:31 2000
@@ -104,7 +104,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - version 3.2g"
+#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - version 3.2h"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
@@ -1120,7 +1120,7 @@
 	u_char		revision_id;	/* PCI device revision id	*/
 	u_char		bus;		/* PCI BUS number		*/
 	u_char		device_fn;	/* PCI BUS device and function	*/
-	u_long		port;		/* IO space base address	*/
+	u_long		base_io;	/* IO space base address	*/
 	u_int		irq;		/* IRQ level			*/
 	u_int		features;	/* Chip features map		*/
 	u_char		myaddr;		/* SCSI id of the adapter	*/
@@ -3734,7 +3734,7 @@
 	*/
 
 	request_region(device->slot.io_port, 128, "ncr53c8xx");
-	np->port = device->slot.io_port;
+	np->base_io = device->slot.io_port;
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 	if (nvram) {
@@ -3951,11 +3951,11 @@
 		unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
 	}
 #endif /* !NCR_IOMAPPED */
-	if (np->port) {
+	if (np->base_io) {
 #ifdef DEBUG_NCR53C8XX
-		printk(KERN_DEBUG "%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+		printk(KERN_DEBUG "%s: releasing IO region %x[%d]\n", ncr_name(np), np->base_io, 128);
 #endif
-		release_region(np->port, 128);
+		release_region(np->base_io, 128);
 	}
 	if (np->irq) {
 #ifdef DEBUG_NCR53C8XX
@@ -4260,11 +4260,17 @@
 	**----------------------------------------------------
 	*/
 
-	segments = ncr_scatter (np, cp, cp->cmd);
-
-	if (segments < 0) {
-		ncr_free_ccb(np, cp);
-		return(DID_ERROR);
+	direction = scsi_data_direction(cmd);
+	if (direction != SCSI_DATA_NONE) {
+		segments = ncr_scatter (np, cp, cp->cmd);
+		if (segments < 0) {
+			ncr_free_ccb(np, cp);
+			return(DID_ERROR);
+		}
+	}
+	else {
+		cp->data_len = 0;
+		segments = 0;
 	}
 
 	/*----------------------------------------------------
@@ -4275,8 +4281,6 @@
 	*/
 	if (!cp->data_len)
 		direction = SCSI_DATA_NONE;
-	else
-		direction = scsi_data_direction(cmd);
 
 	/*
 	**	If data direction is UNKNOWN, speculate DATA_READ 
@@ -4796,9 +4800,9 @@
 #endif /* !NCR_IOMAPPED */
 
 #ifdef DEBUG_NCR53C8XX
-	printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+	printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->base_io, 128);
 #endif
-	release_region(np->port, 128);
+	release_region(np->base_io, 128);
 
 	/*
 	**	Free allocated ccb(s)
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.3.99-pre3/linux/drivers/scsi/qlogicisp.c	Mon Mar 27 08:08:27 2000
+++ linux/drivers/scsi/qlogicisp.c	Mon Mar 27 10:35:56 2000
@@ -1389,14 +1389,6 @@
 		return 1;
 	}
 
-#ifdef __sparc__
-	command |= (PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY|
-		    PCI_COMMAND_INVALIDATE|PCI_COMMAND_SERR);
-	pci_write_config_word(pdev, PCI_COMMAND, command);
-	pci_read_config_word(pdev, PCI_COMMAND, &command);
-	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 16);
-	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
-#endif
 #ifdef __alpha__
 	/* Force ALPHA to use bus I/O and not bus MEM.
 	   This is to avoid having to use HAE_MEM registers,
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.3.99-pre3/linux/drivers/scsi/scsi.c	Mon Mar 27 08:08:27 2000
+++ linux/drivers/scsi/scsi.c	Thu Mar 30 16:54:54 2000
@@ -1866,6 +1866,8 @@
 			 * Nobody is using this device any more.
 			 * Free all of the command structures.
 			 */
+                        if (HBA_ptr->hostt->revoke)
+                                HBA_ptr->hostt->revoke(scd);
 			devfs_unregister (scd->de);
 			scsi_release_commandblocks(scd);
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.3.99-pre3/linux/drivers/scsi/sd.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/sd.c	Mon Mar 27 11:01:58 2000
@@ -120,7 +120,6 @@
 	struct Scsi_Host * host;
 	Scsi_Device * SDev;
 	int diskinfo[4];
-	struct hd_geometry *loc = (struct hd_geometry *) arg;
     
 	SDev = rscsi_disks[DEVICE_NR(dev)].device;
 	/*
@@ -138,6 +137,8 @@
 	switch (cmd) 
 	{
 		case HDIO_GETGEO:   /* Return BIOS disk parameters */
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
 			if(!loc)
 				return -EINVAL;
 
@@ -164,6 +165,7 @@
 				put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start))
 				return -EFAULT;
 			return 0;
+		}
 		case BLKGETSIZE:   /* Return device size */
 			if (!arg)
 				return -EINVAL;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.3.99-pre3/linux/drivers/scsi/sg.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/scsi/sg.c	Mon Mar 27 10:48:23 2000
@@ -17,8 +17,8 @@
  * any later version.
  *
  */
- static char * sg_version_str = "Version: 3.1.12 (20000222)";
- static int sg_version_num = 30112; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 3.1.13 (20000323)";
+ static int sg_version_num = 30113; /* 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
@@ -66,8 +66,10 @@
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 static int sg_proc_init(void);
+#ifdef MODULE
 static void sg_proc_cleanup(void);
 #endif
+#endif
 
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
@@ -548,12 +550,16 @@
     hp->cmd_len = (unsigned char)cmd_size;
     hp->iovec_count = 0;
     hp->mx_sb_len = 0;
+#if 1
+    hp->dxfer_direction = SG_DXFER_UNKNOWN;
+#else
     if (input_size > 0)
 	hp->dxfer_direction = ((old_hdr.reply_len - size_sg_header) > 0) ?
 			      SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
     else
 	hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV :
 					     SG_DXFER_NONE;
+#endif
     hp->dxfer_len = mxsize;
     hp->dxferp = (unsigned char *)buf + cmd_size;
     hp->sbp = NULL;
@@ -671,6 +677,8 @@
 	SCpnt->sc_data_direction = SCSI_DATA_READ; break;
     case SG_DXFER_TO_DEV:
 	SCpnt->sc_data_direction = SCSI_DATA_WRITE; break;
+    case SG_DXFER_UNKNOWN:
+	SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN; break;
     default:
 	SCpnt->sc_data_direction = SCSI_DATA_NONE; break;
     }
@@ -1166,9 +1174,10 @@
 
     for(k = 0; k < sg_template.dev_max; k++)
         if(! sg_dev_arr[k]) break;
-    if(k >= sg_template.dev_max) panic ("sg_dev_arr corrupt");
-
-    sdp = (Sg_device *)kmalloc(sizeof(Sg_device), GFP_ATOMIC);
+    if(k < sg_template.dev_max)
+    	sdp = (Sg_device *)kmalloc(sizeof(Sg_device), GFP_ATOMIC);
+    else
+    	sdp = NULL;
     if (NULL == sdp) {
 	scsidp->attached--;
 	write_unlock_irqrestore(&sg_dev_arr_lock, flags);
@@ -1318,12 +1327,16 @@
     Sg_fd * sfp = srp->parentfp;
     sg_io_hdr_t * hp = &srp->header;
     int dxfer_len = (int)hp->dxfer_len;
+    int dxfer_dir = hp->dxfer_direction;
     Sg_scatter_hold * req_schp = &srp->data;
     Sg_scatter_hold * rsv_schp = &sfp->reserve;
 
     SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len));
-    if ((hp->flags & SG_FLAG_DIRECT_IO) && (dxfer_len > 0) &&
-	(hp->dxfer_direction != SG_DXFER_NONE) && (0 == hp->iovec_count) &&
+    if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
+    	return 0;
+    if ((hp->flags & SG_FLAG_DIRECT_IO) && 
+	(dxfer_dir != SG_DXFER_UNKNOWN) &&
+	(0 == hp->iovec_count) &&
 	(! sfp->parentdp->device->host->unchecked_isa_dma)) {
 	res = sg_build_dir(srp, sfp, dxfer_len);
 	if (res <= 0)   /* -ve -> error, 0 -> done, 1 -> try indirect */
@@ -1563,12 +1576,13 @@
     int num_xfer = 0;
     int j, k, onum, usglen, ksglen, res, ok;
     int iovec_count = (int)hp->iovec_count;
+    int dxfer_dir = hp->dxfer_direction;
     unsigned char * p;
     unsigned char * up;
     int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
 
-    if ((SG_DXFER_TO_DEV == hp->dxfer_direction) ||
-	(SG_DXFER_TO_FROM_DEV == hp->dxfer_direction)) {
+    if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_TO_DEV == dxfer_dir) ||
+	(SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
 	num_xfer = (int)(new_interface ?  hp->dxfer_len : hp->flags);
 	if (schp->bufflen < num_xfer)
 	    num_xfer = schp->bufflen;
@@ -1711,12 +1725,13 @@
     int num_xfer = 0;
     int j, k, onum, usglen, ksglen, res, ok;
     int iovec_count = (int)hp->iovec_count;
+    int dxfer_dir = hp->dxfer_direction;
     unsigned char * p;
     unsigned char * up;
     int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
 
-    if ((SG_DXFER_FROM_DEV == hp->dxfer_direction) ||
-	(SG_DXFER_TO_FROM_DEV == hp->dxfer_direction)) {
+    if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_FROM_DEV == dxfer_dir) ||
+	(SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
 	num_xfer =  hp->dxfer_len;
 	if (schp->bufflen < num_xfer)
 	    num_xfer = schp->bufflen;
@@ -2445,6 +2460,7 @@
     return 0;
 }
 
+#ifdef MODULE
 static void sg_proc_cleanup()
 {
     int k;
@@ -2456,6 +2472,7 @@
 	remove_proc_entry(sg_proc_leaf_names[k], sg_proc_sgp);
     remove_proc_entry(sg_proc_sg_dirname, proc_scsi);
 }
+#endif
 
 static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset,
 			       int size, int * eof, void * data)
@@ -2505,7 +2522,7 @@
     }
     read_lock(&sg_dev_arr_lock);
     max_dev = sg_last_dev();
-    PRINT_PROC("dev_max=%d max_active_device=%d (origin 1)\n",
+    PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
 	       sg_template.dev_max, max_dev);
     PRINT_PROC(" scsi_dma_free_sectors=%u sg_pool_secs_aval=%d "
 	       "def_reserved_size=%d\n",
@@ -2523,12 +2540,13 @@
 	    }
 	    dev = MINOR(sdp->i_rdev);
 
-	    PRINT_PROC(" >>> device=%d(sg%d) ", dev, dev);
-	    PRINT_PROC("scsi%d chan=%d id=%d lun=%d   em=%d sg_tablesize=%d"
+	    if ((fp = sdp->headfp)) {
+		PRINT_PROC(" >>> device=%d(sg%d) ", dev, dev);
+		PRINT_PROC("scsi%d chan=%d id=%d lun=%d   em=%d sg_tablesize=%d"
 		       " excl=%d\n", scsidp->host->host_no, scsidp->channel,
 		       scsidp->id, scsidp->lun, scsidp->host->hostt->emulated,
 		       sdp->sg_tablesize, sdp->exclude);
-	    fp = sdp->headfp;
+	    }
 	    for (k = 1; fp; fp = fp->nextfp, ++k) {
 		PRINT_PROC("   FD(%d): timeout=%d bufflen=%d "
 			   "(res)sgat=%d low_dma=%d\n",
@@ -2543,13 +2561,13 @@
 		while (srp) {
 		    hp = &srp->header;
 /* stop indenting so far ... */
-	PRINT_PROC(srp->res_used ? "     reserved_buff>> " :
+	PRINT_PROC(srp->res_used ? "     rb>> " :
 	    ((SG_INFO_DIRECT_IO_MASK & hp->info) ? "     dio>> " : "     "));
 	blen = srp->my_cmdp ? srp->my_cmdp->bufflen : srp->data.bufflen;
 	usg = srp->my_cmdp ? srp->my_cmdp->use_sg : srp->data.k_use_sg;
 	PRINT_PROC(srp->done ? "rcv: id=%d" : (srp->my_cmdp ? "act: id=%d" :
 		    "prior: id=%d"), srp->header.pack_id);
-	if (! srp->res_used) PRINT_PROC(" blen=%d", blen);
+	PRINT_PROC(" blen=%d", blen);
 	if (srp->done)
 	    PRINT_PROC(" dur=%d", sg_jif_to_ms(hp->duration));
 	else
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.3.99-pre3/linux/drivers/scsi/sym53c8xx.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/sym53c8xx.c	Sat Apr  1 07:45:31 2000
@@ -84,7 +84,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.5k"
+#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.5l"
 
 /* #define DEBUG_896R1 */
 #define SCSI_NCR_OPTIMIZE_896
@@ -6303,7 +6303,6 @@
 	lcb_p lp		      = ncr_lp(np, tp, cmd->lun);
 	ccb_p cp;
 
-	int	segments;
 	u_char	idmsg, *msgptr;
 	u_int   msglen;
 	int	direction;
@@ -6452,11 +6451,17 @@
 	**----------------------------------------------------
 	*/
 
-	cp->segments = segments = np->scatter (np, cp, cp->cmd);
-
-	if (segments < 0) {
-		ncr_free_ccb(np, cp);
-		return(DID_ERROR);
+	direction = scsi_data_direction(cmd);
+	if (direction != SCSI_DATA_NONE) {
+		cp->segments = np->scatter (np, cp, cp->cmd);
+		if (cp->segments < 0) {
+			ncr_free_ccb(np, cp);
+			return(DID_ERROR);
+		}
+	}
+	else {
+		cp->data_len = 0;
+		cp->segments = 0;
 	}
 
 	/*----------------------------------------------------
@@ -6467,8 +6472,6 @@
 	*/
 	if (!cp->data_len)
 		direction = SCSI_DATA_NONE;
-	else
-		direction = scsi_data_direction(cmd);
 
 	/*
 	**	If data direction is UNKNOWN, speculate DATA_READ 
@@ -6480,7 +6483,7 @@
 	case SCSI_DATA_UNKNOWN:
 	case SCSI_DATA_WRITE:
 		goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
-		lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
+		lastp = goalp - 8 - (cp->segments * (SCR_SG_SIZE*4));
 		if (direction != SCSI_DATA_UNKNOWN)
 			break;
 		cp->phys.header.wgoalp	= cpu_to_scr(goalp);
@@ -6489,7 +6492,7 @@
 	case SCSI_DATA_READ:
 		cp->host_flags |= HF_DATA_IN;
 		goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
-		lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
+		lastp = goalp - 8 - (cp->segments * (SCR_SG_SIZE*4));
 		break;
 	default:
 	case SCSI_DATA_NONE:
@@ -12316,16 +12319,6 @@
 	}
 #endif
 #endif	/* __powerpc__ */
-
-#ifdef __sparc__
-	/*
-	**    Fix-ups for sparc.
-	*/
-	if (!cache_line_size)
-		suggested_cache_line_size = 16;
-
-	driver_setup.pci_fix_up |= 0x7;
-#endif	/* __sparc__ */
 
 #if defined(__i386__) && !defined(MODULE)
 	if (!cache_line_size) {
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h
--- v2.3.99-pre3/linux/drivers/scsi/sym53c8xx_comm.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/sym53c8xx_comm.h	Sat Apr  1 07:45:31 2000
@@ -2497,16 +2497,6 @@
 #endif
 #endif	/* __powerpc__ */
 
-#ifdef __sparc__
-	/*
-	**    Fix-ups for sparc.
-	*/
-	if (!cache_line_size)
-		suggested_cache_line_size = 16;
-
-	driver_setup.pci_fix_up |= 0x7;
-#endif	/* __sparc__ */
-
 #if defined(__i386__) && !defined(MODULE)
 	if (!cache_line_size) {
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/scsi/wd33c93.c linux/drivers/scsi/wd33c93.c
--- v2.3.99-pre3/linux/drivers/scsi/wd33c93.c	Tue Nov 23 22:42:21 1999
+++ linux/drivers/scsi/wd33c93.c	Mon Mar 27 09:48:11 2000
@@ -1638,7 +1638,7 @@
       setup_used[i] = 0;
    done_setup = 1;
 
-   return 0;
+   return 1;
 }
 
 __setup("wd33c93", wd33c93_setup);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.3.99-pre3/linux/drivers/sound/Makefile	Sun Mar 19 18:35:30 2000
+++ linux/drivers/sound/Makefile	Mon Apr 10 22:58:59 2000
@@ -35,7 +35,6 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_SOUND)		+= soundcore.o
-obj-$(CONFIG_DMASOUND)		+= dmasound.o
 obj-$(CONFIG_SOUND_OSS)		+= sound.o
 obj-$(CONFIG_SOUND_CS4232)	+= cs4232.o ad1848.o 
 
@@ -81,6 +80,17 @@
 obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
 obj-$(CONFIG_SOUND_TRIDENT)	+= trident.o ac97_codec.o
 
+ifeq ($(CONFIG_DMASOUND),y)
+  SUB_DIRS += dmasound
+  MOD_SUB_DIRS += dmasound
+  obj-y += dmasound/dmasound.o
+else
+  ifeq ($(CONFIG_DMASOUND),m)
+    MOD_SUB_DIRS += dmasound
+  endif
+endif
+
+
 # Declare multi-part drivers.
 
 list-multi	:= sound.o gus.o pas2.o sb.o sb_lib.o softoss2.o vidc_mod.o \
@@ -137,10 +147,6 @@
 MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
 MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
 MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
-
-ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
-    O_OBJS	+= lowlevel/lowlevel.o
-endif
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/ad1816.c linux/drivers/sound/ad1816.c
--- v2.3.99-pre3/linux/drivers/sound/ad1816.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/sound/ad1816.c	Mon Mar 27 10:41:51 2000
@@ -1266,8 +1266,7 @@
 static int __initdata dma2 = -1;
 
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
-struct pci_dev	*ad1816_dev  = NULL,
-		*mpu_dev = NULL;
+struct pci_dev	*ad1816_dev  = NULL;
 
 static int activated	= 1;
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c
--- v2.3.99-pre3/linux/drivers/sound/aedsp16.c	Fri Mar 10 16:40:44 2000
+++ linux/drivers/sound/aedsp16.c	Mon Mar 27 09:48:11 2000
@@ -1383,6 +1383,7 @@
 	mss_base = ints[4];
 	mpu_base = ints[5];
 	mpu_irq	 = ints[6];
+	return 1;
 }
 
 __setup("aedsp16=", setup_aedsp16);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c
--- v2.3.99-pre3/linux/drivers/sound/dev_table.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/sound/dev_table.c	Sun Apr  2 15:45:06 2000
@@ -26,15 +26,13 @@
 	struct audio_operations *op;
 	int l, num;
 
-	if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver))
-	{
+	if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver)) {
 		printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name);
 		return -(EINVAL);
 	}
 	num = sound_alloc_audiodev();
 
-	if (num == -1)
-	{
+	if (num == -1) {
 		printk(KERN_ERR "sound: Too many audio drivers\n");
 		return -(EBUSY);
 	}
@@ -47,8 +45,7 @@
 
 	if (sound_nblocks < 1024)
 		sound_nblocks++;
-	if (d == NULL || op == NULL)
-	{
+	if (d == NULL || op == NULL) {
 		printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name);
 		sound_unload_audiodev(num);
 		return -(ENOMEM);
@@ -91,14 +88,12 @@
 
 	int n = sound_alloc_mixerdev();
 
-	if (n == -1)
-	{
+	if (n == -1) {
 		printk(KERN_ERR "Sound: Too many mixer drivers\n");
 		return -EBUSY;
 	}
 	if (vers != MIXER_DRIVER_VERSION ||
-		driver_size > sizeof(struct mixer_operations))
-	{
+		driver_size > sizeof(struct mixer_operations)) {
 		printk(KERN_ERR "Sound: Incompatible mixer driver for %s\n", name);
 		return -EINVAL;
 	}
@@ -110,8 +105,7 @@
 
 	if (sound_nblocks < 1024)
 		sound_nblocks++;
-	if (op == NULL)
-	{
+	if (op == NULL) {
 		printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name);
 		return -ENOMEM;
 	}
@@ -131,8 +125,7 @@
 
 void sound_unload_audiodev(int dev)
 {
-	if (dev != -1)
-	{
+	if (dev != -1) {
 		DMAbuf_deinit(dev);
 		audio_devs[dev] = NULL;
 		unregister_sound_dsp((dev<<4)+3);
@@ -165,10 +158,8 @@
 {
 	int i;
 
-	for (i = 0; i < MAX_SYNTH_DEV; i++)
-	{
-		if (synth_devs[i] == NULL)
-		{
+	for (i = 0; i < MAX_SYNTH_DEV; i++) {
+		if (synth_devs[i] == NULL) {
 			if (i >= num_synths)
 				num_synths++;
 			return i;
@@ -192,10 +183,8 @@
 {
 	int i;
 
-	for (i = 0; i < MAX_TIMER_DEV; i++)
-	{
-		if (sound_timer_devs[i] == NULL)
-		{
+	for (i = 0; i < MAX_TIMER_DEV; i++) {
+		if (sound_timer_devs[i] == NULL) {
 			if (i >= num_sound_timers)
 				num_sound_timers++;
 			return i;
@@ -206,8 +195,7 @@
 
 void sound_unload_mixerdev(int dev)
 {
-	if (dev != -1)
-	{
+	if (dev != -1) {
 		mixer_devs[dev] = NULL;
 		unregister_sound_mixer(dev<<4);
 		num_mixers--;
@@ -216,8 +204,7 @@
 
 void sound_unload_mididev(int dev)
 {
-	if (dev != -1)
-	{
+	if (dev != -1) {
 		midi_devs[dev] = NULL;
 		unregister_sound_midi((dev<<4)+2);
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.3.99-pre3/linux/drivers/sound/dev_table.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/sound/dev_table.h	Sun Apr  2 15:45:06 2000
@@ -133,9 +133,6 @@
 	char	neutral_byte;
 	int	dma;		/* DMA channel */
 
-#ifdef OS_DMA_PARMS
-	OS_DMA_PARMS
-#endif
 	int     applic_profile;	/* Application profile (APF_*) */
 	/* Interrupt callback stuff */
 	void (*audio_callback) (int dev, int parm);
@@ -347,7 +344,6 @@
 };
 
 #ifdef _DEV_TABLE_C_   
-
 struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL};
 int num_audiodevs = 0;
 struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL};
@@ -356,21 +352,13 @@
 int num_synths = 0;
 struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL};
 int num_midis = 0;
-#ifndef EXCLUDE_TIMERS
+
 extern struct sound_timer_operations default_sound_timer;
 struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
 	&default_sound_timer, NULL
 }; 
 int num_sound_timers = 1;
 #else
-struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
-	NULL
-};
-int num_sound_timers = 0;
-#endif
-
-
-#else
 extern struct audio_operations *audio_devs[MAX_AUDIO_DEV];
 extern int num_audiodevs;
 extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
@@ -384,8 +372,6 @@
 #endif	/* _DEV_TABLE_C_ */
 
 extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
-int sndtable_probe (int unit, struct address_info *hw_config);
-int sndtable_start_card (int unit, struct address_info *hw_config);
 void sound_timer_init (struct sound_lowlev_timer *t, char *name);
 void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan);
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dmasound/Config.in linux/drivers/sound/dmasound/Config.in
--- v2.3.99-pre3/linux/drivers/sound/dmasound/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/dmasound/Config.in	Mon Apr 10 22:58:59 2000
@@ -0,0 +1,27 @@
+# drivers/sound/dmasound/Config.in
+
+if [ "$CONFIG_ATARI" = "y" ]; then
+   dep_tristate '  Atari DMA sound support' CONFIG_DMASOUND_ATARI $CONFIG_SOUND
+fi
+if [ "$CONFIG_ALL_PPC" = "y" ]; then
+   dep_tristate '  PowerMac DMA sound support' CONFIG_DMASOUND_AWACS $CONFIG_SOUND
+fi
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_APUS" = "y" ]; then
+   dep_tristate '  Amiga DMA sound support' CONFIG_DMASOUND_PAULA $CONFIG_SOUND
+fi
+if [ "$CONFIG_Q40" = "y" ]; then
+   dep_tristate '  Q40 sound support' CONFIG_DMASOUND_Q40 $CONFIG_SOUND
+fi
+if [ "$CONFIG_DMASOUND_ATARI" = "y" -o \
+     "$CONFIG_DMASOUND_AWACS" = "y" -o \
+     "$CONFIG_DMASOUND_PAULA" = "y" -o \
+     "$CONFIG_DMASOUND_Q40" = "y" ]; then
+   define_tristate CONFIG_DMASOUND y
+else
+   if [ "$CONFIG_DMASOUND_ATARI" = "m" -o \
+	"$CONFIG_DMASOUND_AWACS" = "m" -o \
+	"$CONFIG_DMASOUND_PAULA" = "m" -o \
+	"$CONFIG_DMASOUND_Q40" = "m" ]; then
+      define_tristate CONFIG_DMASOUND m
+   fi
+fi
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dmasound/Makefile linux/drivers/sound/dmasound/Makefile
--- v2.3.99-pre3/linux/drivers/sound/dmasound/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/dmasound/Makefile	Mon Apr 10 22:58:59 2000
@@ -0,0 +1,38 @@
+#
+# Makefile for the DMA sound driver
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET    :=
+O_OBJS      :=
+OX_OBJS     :=
+M_OBJS      :=
+MX_OBJS     :=
+
+export-objs := dmasound_core.o
+
+obj-$(CONFIG_DMASOUND_ATARI)  += dmasound_core.o dmasound_atari.o
+obj-$(CONFIG_DMASOUND_AWACS)  += dmasound_core.o dmasound_awacs.o
+obj-$(CONFIG_DMASOUND_PAULA)  += dmasound_core.o dmasound_paula.o
+obj-$(CONFIG_DMASOUND_Q40)    += dmasound_core.o dmasound_q40.o
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m       := $(filter-out $(obj-y), $(obj-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS      := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS     := $(filter     $(export-objs), $(obj-y))
+M_OBJS      := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS     := $(sort $(filter     $(export-objs), $(obj-m)))
+
+ifeq ($(CONFIG_DMASOUND),y)
+  O_TARGET = dmasound.o
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound.h linux/drivers/sound/dmasound/dmasound.h
--- v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/dmasound/dmasound.h	Mon Apr 10 22:58:59 2000
@@ -0,0 +1,246 @@
+
+/*
+ *  linux/drivers/sound/dmasound.h
+ *
+ *
+ *  Minor numbers for the sound driver.
+ *
+ *  Unfortunately Creative called the codec chip of SB as a DSP. For this
+ *  reason the /dev/dsp is reserved for digitized audio use. There is a
+ *  device for true DSP processors but it will be called something else.
+ *  In v3.0 it's /dev/sndproc but this could be a temporary solution.
+ */
+
+
+#include <linux/config.h>
+
+
+#define SND_NDEVS	256	/* Number of supported devices */
+#define SND_DEV_CTL	0	/* Control port /dev/mixer */
+#define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM
+				   synthesizer and MIDI output) */
+#define SND_DEV_MIDIN	2	/* Raw midi access */
+#define SND_DEV_DSP	3	/* Digitized voice /dev/dsp */
+#define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
+#define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
+#define SND_DEV_STATUS	6	/* /dev/sndstat */
+/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
+#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
+#define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
+#define SND_DEV_PSS	SND_DEV_SNDPROC
+
+#define DSP_DEFAULT_SPEED	8000
+
+#define ON		1
+#define OFF		0
+
+#define MAX_AUDIO_DEV	5
+#define MAX_MIXER_DEV	2
+#define MAX_SYNTH_DEV	3
+#define MAX_MIDI_DEV	6
+#define MAX_TIMER_DEV	3
+
+
+#define MAX_CATCH_RADIUS	10
+#define MIN_BUFFERS		4
+#define MIN_BUFSIZE		4	/* in KB */
+#define MAX_BUFSIZE		128	/* Limit for Amiga in KB */
+
+
+#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
+#define min(x, y)	((x) < (y) ? (x) : (y))
+#define le2be16(x)	(((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
+#define le2be16dbl(x)	(((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
+
+#define IOCTL_IN(arg, ret) \
+	do { int error = get_user(ret, (int *)(arg)); \
+		if (error) return error; \
+	} while (0)
+#define IOCTL_OUT(arg, ret)	ioctl_return((int *)(arg), ret)
+
+static inline int ioctl_return(int *addr, int value)
+{
+	return value < 0 ? value : put_user(value, addr);
+}
+
+
+    /*
+     *  Configuration
+     */
+
+#undef HAS_8BIT_TABLES
+#undef HAS_14BIT_TABLES
+#undef HAS_16BIT_TABLES
+#undef HAS_RECORD
+
+#if defined(CONFIG_DMASOUND_ATARI) || defined(CONFIG_DMASOUND_ATARI_MODULE) ||\
+    defined(CONFIG_DMASOUND_PAULA) || defined(CONFIG_DMASOUND_PAULA_MODULE) ||\
+    defined(CONFIG_DMASOUND_Q40) || defined(CONFIG_DMASOUND_Q40_MODULE)
+#define HAS_8BIT_TABLES
+#endif
+#if defined(CONFIG_DMASOUND_AWACS) || defined(CONFIG_DMASOUND_AWACS_MODULE)
+#define HAS_16BIT_TABLES
+#define HAS_RECORD
+#endif
+
+
+    /*
+     *  Initialization
+     */
+
+extern int dmasound_init(void);
+extern void dmasound_deinit(void);
+
+
+    /*
+     *  Machine definitions
+     */
+
+typedef struct {
+    const char *name;
+    const char *name2;
+    void (*open)(void);
+    void (*release)(void);
+    void *(*dma_alloc)(unsigned int, int);
+    void (*dma_free)(void *, unsigned int);
+    int (*irqinit)(void);
+#ifdef MODULE
+    void (*irqcleanup)(void);
+#endif /* MODULE */
+    void (*init)(void);
+    void (*silence)(void);
+    int (*setFormat)(int);
+    int (*setVolume)(int);
+    int (*setBass)(int);
+    int (*setTreble)(int);
+    int (*setGain)(int);
+    void (*play)(void);
+    void (*record)(void);			/* optional */
+    void (*mixer_init)(void);			/* optional */
+    int (*mixer_ioctl)(u_int, u_long);		/* optional */
+    void (*write_sq_setup)(void);		/* optional */
+    void (*read_sq_setup)(void);		/* optional */
+    void (*sq_open)(void);			/* optional */
+    int (*state_info)(char *);			/* optional */
+    void (*abort_read)(void);			/* optional */
+    int min_dsp_speed;
+} MACHINE;
+
+
+    /*
+     *  Low level stuff
+     */
+
+typedef struct {
+    int format;		/* AFMT_* */
+    int stereo;		/* 0 = mono, 1 = stereo */
+    int size;		/* 8/16 bit*/
+    int speed;		/* speed */
+} SETTINGS;
+
+typedef struct {
+    ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+    ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+    ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+    ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+    ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+    ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+    ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+    ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+} TRANS;
+
+struct sound_settings {
+    MACHINE mach;	/* machine dependent things */
+    SETTINGS hard;	/* hardware settings */
+    SETTINGS soft;	/* software settings */
+    SETTINGS dsp;	/* /dev/dsp default settings */
+    TRANS *trans_write;	/* supported translations */
+#ifdef HAS_RECORD
+    TRANS *trans_read;	/* supported translations */
+#endif
+    int volume_left;	/* volume (range is machine dependent) */
+    int volume_right;
+    int bass;		/* tone (range is machine dependent) */
+    int treble;
+    int gain;
+    int minDev;		/* minor device number currently open */
+};
+
+extern struct sound_settings dmasound;
+
+extern char dmasound_ulaw2dma8[];
+extern char dmasound_alaw2dma8[];
+extern short dmasound_ulaw2dma16[];
+extern short dmasound_alaw2dma16[];
+
+
+    /*
+     *  Mid level stuff
+     */
+
+static inline int dmasound_set_volume(int volume)
+{
+	return dmasound.mach.setVolume(volume);
+}
+
+static inline int dmasound_set_bass(int bass)
+{
+	return dmasound.mach.setBass ? dmasound.mach.setBass(bass) : 50;
+}
+
+static inline int dmasound_set_treble(int treble)
+{
+	return dmasound.mach.setTreble ? dmasound.mach.setTreble(treble) : 50;
+}
+
+static inline int dmasound_set_gain(int gain)
+{
+	return dmasound.mach.setGain ? dmasound.mach.setGain(gain) : 100;
+}
+
+
+    /*
+     * Sound queue stuff, the heart of the driver
+     */
+
+struct sound_queue {
+    /* buffers allocated for this queue */
+    int numBufs;
+    int bufSize;			/* in bytes */
+    char **buffers;
+
+    /* current parameters */
+    int max_count;
+    int block_size;			/* in bytes */
+    int max_active;
+
+    /* it shouldn't be necessary to declare any of these volatile */
+    int front, rear, count;
+    int rear_size;
+    /*
+     *	The use of the playing field depends on the hardware
+     *
+     *	Atari, PMac: The number of frames that are loaded/playing
+     *
+     *	Amiga: Bit 0 is set: a frame is loaded
+     *	       Bit 1 is set: a frame is playing
+     */
+    int active;
+    wait_queue_head_t action_queue, open_queue, sync_queue;
+    int open_mode;
+    int busy, syncing;
+};
+
+#define SLEEP(queue)		interruptible_sleep_on_timeout(&queue, HZ)
+#define WAKE_UP(queue)		(wake_up_interruptible(&queue))
+
+extern struct sound_queue dmasound_write_sq;
+extern struct sound_queue dmasound_read_sq;
+
+#define write_sq	dmasound_write_sq
+#define read_sq		dmasound_read_sq
+
+extern int dmasound_catchRadius;
+
+#define catchRadius	dmasound_catchRadius
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound_atari.c linux/drivers/sound/dmasound/dmasound_atari.c
--- v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound_atari.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/dmasound/dmasound_atari.c	Mon Apr 10 22:58:59 2000
@@ -0,0 +1,1560 @@
+
+/*
+ *  linux/drivers/sound/dmasound_atari.c
+ *
+ *  Atari DMA Sound Driver
+ *
+ *  See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/soundcard.h>
+#include <linux/mm.h>
+
+#include <asm/pgalloc.h>
+#include <asm/uaccess.h>
+#include <asm/atariints.h>
+#include <asm/atari_stram.h>
+
+#include "dmasound.h"
+
+
+extern void atari_microwire_cmd(int cmd);
+
+
+static int is_falcon;
+static int write_sq_ignore_int = 0;	/* ++TeSche: used for Falcon */
+
+static int expand_bal;	/* Balance factor for expanding (not volume!) */
+static int expand_data;	/* Data for expanding */
+
+
+/*** Translations ************************************************************/
+
+
+/* ++TeSche: radically changed for new expanding purposes...
+ *
+ * These two routines now deal with copying/expanding/translating the samples
+ * from user space into our buffer at the right frequency. They take care about
+ * how much data there's actually to read, how much buffer space there is and
+ * to convert samples into the right frequency/encoding. They will only work on
+ * complete samples so it may happen they leave some bytes in the input stream
+ * if the user didn't write a multiple of the current sample size. They both
+ * return the number of bytes they've used from both streams so you may detect
+ * such a situation. Luckily all programs should be able to cope with that.
+ *
+ * I think I've optimized anything as far as one can do in plain C, all
+ * variables should fit in registers and the loops are really short. There's
+ * one loop for every possible situation. Writing a more generalized and thus
+ * parameterized loop would only produce slower code. Feel free to optimize
+ * this in assembler if you like. :)
+ *
+ * I think these routines belong here because they're not yet really hardware
+ * independent, especially the fact that the Falcon can play 16bit samples
+ * only in stereo is hardcoded in both of them!
+ *
+ * ++geert: split in even more functions (one per format)
+ */
+
+static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed,
+			 ssize_t frameLeft);
+static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed,
+			 ssize_t frameLeft);
+static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft);
+static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft);
+static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft);
+static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft);
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void AtaOpen(void);
+static void AtaRelease(void);
+static void *AtaAlloc(unsigned int size, int flags);
+static void AtaFree(void *, unsigned int size);
+static int AtaIrqInit(void);
+#ifdef MODULE
+static void AtaIrqCleanUp(void);
+#endif /* MODULE */
+static int AtaSetBass(int bass);
+static int AtaSetTreble(int treble);
+static void TTSilence(void);
+static void TTInit(void);
+static int TTSetFormat(int format);
+static int TTSetVolume(int volume);
+static int TTSetGain(int gain);
+static void FalconSilence(void);
+static void FalconInit(void);
+static int FalconSetFormat(int format);
+static int FalconSetVolume(int volume);
+static void AtaPlayNextFrame(int index);
+static void AtaPlay(void);
+static void AtaInterrupt(int irq, void *dummy, struct pt_regs *fp);
+
+/*** Mid level stuff *********************************************************/
+
+static void TTMixerInit(void);
+static void FalconMixerInit(void);
+static int AtaMixerIoctl(u_int cmd, u_long arg);
+static int TTMixerIoctl(u_int cmd, u_long arg);
+static int FalconMixerIoctl(u_int cmd, u_long arg);
+static void AtaWriteSqSetup(void);
+static void AtaSqOpen(void);
+static int TTStateInfo(char *buffer);
+static int FalconStateInfo(char *buffer);
+
+
+/*** Translations ************************************************************/
+
+
+static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8
+							  : dmasound_alaw2dma8;
+	ssize_t count, used;
+	u_char *p = &frame[*frameUsed];
+
+	count = min(userCount, frameLeft);
+	if (dmasound.soft.stereo)
+		count &= ~1;
+	used = count;
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		*p++ = table[data];
+		count--;
+	}
+	*frameUsed += used;
+	return used;
+}
+
+
+static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed,
+			 ssize_t frameLeft)
+{
+	ssize_t count, used;
+	void *p = &frame[*frameUsed];
+
+	count = min(userCount, frameLeft);
+	if (dmasound.soft.stereo)
+		count &= ~1;
+	used = count;
+	if (copy_from_user(p, userPtr, count))
+		return -EFAULT;
+	*frameUsed += used;
+	return used;
+}
+
+
+static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed,
+			 ssize_t frameLeft)
+{
+	ssize_t count, used;
+
+	if (!dmasound.soft.stereo) {
+		u_char *p = &frame[*frameUsed];
+		count = min(userCount, frameLeft);
+		used = count;
+		while (count > 0) {
+			u_char data;
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			*p++ = data ^ 0x80;
+			count--;
+		}
+	} else {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>1;
+		used = count*2;
+		while (count > 0) {
+			u_short data;
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			*p++ = data ^ 0x8080;
+			count--;
+		}
+	}
+	*frameUsed += used;
+	return used;
+}
+
+
+static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
+{
+	ssize_t count, used;
+
+	if (!dmasound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>1;
+		used = count*2;
+		while (count > 0) {
+			u_short data;
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			*p++ = data;
+			*p++ = data;
+			count--;
+		}
+		*frameUsed += used*2;
+	} else {
+		void *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft) & ~3;
+		used = count;
+		if (copy_from_user(p, userPtr, count))
+			return -EFAULT;
+		*frameUsed += used;
+	}
+	return used;
+}
+
+
+static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
+{
+	ssize_t count, used;
+
+	if (!dmasound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>1;
+		used = count*2;
+		while (count > 0) {
+			u_short data;
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data ^= 0x8000;
+			*p++ = data;
+			*p++ = data;
+			count--;
+		}
+		*frameUsed += used*2;
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>2;
+		used = count*4;
+		while (count > 0) {
+			u_long data;
+			if (get_user(data, ((u_int *)userPtr)++))
+				return -EFAULT;
+			*p++ = data ^ 0x80008000;
+			count--;
+		}
+		*frameUsed += used;
+	}
+	return used;
+}
+
+
+static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
+{
+	ssize_t count, used;
+
+	count = frameLeft;
+	if (!dmasound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>1;
+		used = count*2;
+		while (count > 0) {
+			u_short data;
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data = le2be16(data);
+			*p++ = data;
+			*p++ = data;
+			count--;
+		}
+		*frameUsed += used*2;
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>2;
+		used = count*4;
+		while (count > 0) {
+			u_long data;
+			if (get_user(data, ((u_int *)userPtr)++))
+				return -EFAULT;
+			data = le2be16dbl(data);
+			*p++ = data;
+			count--;
+		}
+		*frameUsed += used;
+	}
+	return used;
+}
+
+
+static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
+{
+	ssize_t count, used;
+
+	count = frameLeft;
+	if (!dmasound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>1;
+		used = count*2;
+		while (count > 0) {
+			u_short data;
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data = le2be16(data) ^ 0x8000;
+			*p++ = data;
+			*p++ = data;
+		}
+		*frameUsed += used*2;
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>2;
+		used = count;
+		while (count > 0) {
+			u_long data;
+			if (get_user(data, ((u_int *)userPtr)++))
+				return -EFAULT;
+			data = le2be16dbl(data) ^ 0x80008000;
+			*p++ = data;
+			count--;
+		}
+		*frameUsed += used;
+	}
+	return used;
+}
+
+
+static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8
+							  : dmasound_alaw2dma8;
+	/* this should help gcc to stuff everything into registers */
+	long bal = expand_bal;
+	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	ssize_t used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!dmasound.soft.stereo) {
+		u_char *p = &frame[*frameUsed];
+		u_char data = expand_data;
+		while (frameLeft) {
+			u_char c;
+			if (bal < 0) {
+				if (!userCount)
+					break;
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data = table[c];
+				userCount--;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft--;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	} else {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = expand_data;
+		while (frameLeft >= 2) {
+			u_char c;
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data = table[c] << 8;
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data |= table[c];
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 2;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	}
+	expand_bal = bal;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return used;
+}
+
+
+static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	/* this should help gcc to stuff everything into registers */
+	long bal = expand_bal;
+	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	ssize_t used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!dmasound.soft.stereo) {
+		u_char *p = &frame[*frameUsed];
+		u_char data = expand_data;
+		while (frameLeft) {
+			if (bal < 0) {
+				if (!userCount)
+					break;
+				if (get_user(data, userPtr++))
+					return -EFAULT;
+				userCount--;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft--;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	} else {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = expand_data;
+		while (frameLeft >= 2) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 2;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	}
+	expand_bal = bal;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return used;
+}
+
+
+static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	/* this should help gcc to stuff everything into registers */
+	long bal = expand_bal;
+	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	ssize_t used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!dmasound.soft.stereo) {
+		u_char *p = &frame[*frameUsed];
+		u_char data = expand_data;
+		while (frameLeft) {
+			if (bal < 0) {
+				if (!userCount)
+					break;
+				if (get_user(data, userPtr++))
+					return -EFAULT;
+				data ^= 0x80;
+				userCount--;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft--;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	} else {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = expand_data;
+		while (frameLeft >= 2) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				data ^= 0x8080;
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 2;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	}
+	expand_bal = bal;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return used;
+}
+
+
+static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft)
+{
+	/* this should help gcc to stuff everything into registers */
+	long bal = expand_bal;
+	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	ssize_t used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!dmasound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = expand_data;
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		u_long data = expand_data;
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 4)
+					break;
+				if (get_user(data, ((u_int *)userPtr)++))
+					return -EFAULT;
+				userCount -= 4;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	}
+	expand_bal = bal;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return used;
+}
+
+
+static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft)
+{
+	/* this should help gcc to stuff everything into registers */
+	long bal = expand_bal;
+	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	ssize_t used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!dmasound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = expand_data;
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				data ^= 0x8000;
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		u_long data = expand_data;
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 4)
+					break;
+				if (get_user(data, ((u_int *)userPtr)++))
+					return -EFAULT;
+				data ^= 0x80008000;
+				userCount -= 4;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	}
+	expand_bal = bal;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return used;
+}
+
+
+static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft)
+{
+	/* this should help gcc to stuff everything into registers */
+	long bal = expand_bal;
+	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	ssize_t used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!dmasound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = expand_data;
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				data = le2be16(data);
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		u_long data = expand_data;
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 4)
+					break;
+				if (get_user(data, ((u_int *)userPtr)++))
+					return -EFAULT;
+				data = le2be16dbl(data);
+				userCount -= 4;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	}
+	expand_bal = bal;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return used;
+}
+
+
+static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft)
+{
+	/* this should help gcc to stuff everything into registers */
+	long bal = expand_bal;
+	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	ssize_t used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!dmasound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = expand_data;
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				data = le2be16(data) ^ 0x8000;
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		u_long data = expand_data;
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 4)
+					break;
+				if (get_user(data, ((u_int *)userPtr)++))
+					return -EFAULT;
+				data = le2be16dbl(data) ^ 0x80008000;
+				userCount -= 4;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+		expand_data = data;
+	}
+	expand_bal = bal;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return used;
+}
+
+
+static TRANS transTTNormal = {
+	ct_ulaw:	ata_ct_law,
+	ct_alaw:	ata_ct_law,
+	ct_s8:		ata_ct_s8,
+	ct_u8:		ata_ct_u8,
+};
+
+static TRANS transTTExpanding = {
+	ct_ulaw:	ata_ctx_law,
+	ct_alaw:	ata_ctx_law,
+	ct_s8:		ata_ctx_s8,
+	ct_u8:		ata_ctx_u8,
+};
+
+static TRANS transFalconNormal = {
+	ct_ulaw:	ata_ct_law,
+	ct_alaw:	ata_ct_law,
+	ct_s8:		ata_ct_s8,
+	ct_u8:		ata_ct_u8,
+	ct_s16be:	ata_ct_s16be,
+	ct_u16be:	ata_ct_u16be,
+	ct_s16le:	ata_ct_s16le,
+	ct_u16le:	ata_ct_u16le
+};
+
+static TRANS transFalconExpanding = {
+	ct_ulaw:	ata_ctx_law,
+	ct_alaw:	ata_ctx_law,
+	ct_s8:		ata_ctx_s8,
+	ct_u8:		ata_ctx_u8,
+	ct_s16be:	ata_ctx_s16be,
+	ct_u16be:	ata_ctx_u16be,
+	ct_s16le:	ata_ctx_s16le,
+	ct_u16le:	ata_ctx_u16le,
+};
+
+
+/*** Low level stuff *********************************************************/
+
+
+
+/*
+ * Atari (TT/Falcon)
+ */
+
+static void AtaOpen(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void AtaRelease(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static void *AtaAlloc(unsigned int size, int flags)
+{
+	return atari_stram_alloc( size, NULL, "dmasound" );
+}
+
+static void AtaFree(void *obj, unsigned int size)
+{
+	atari_stram_free( obj );
+}
+
+static int __init AtaIrqInit(void)
+{
+	/* Set up timer A. Timer A
+	   will receive a signal upon end of playing from the sound
+	   hardware. Furthermore Timer A is able to count events
+	   and will cause an interrupt after a programmed number
+	   of events. So all we need to keep the music playing is
+	   to provide the sound hardware with new data upon
+	   an interrupt from timer A. */
+	mfp.tim_ct_a = 0;	/* ++roman: Stop timer before programming! */
+	mfp.tim_dt_a = 1;	/* Cause interrupt after first event. */
+	mfp.tim_ct_a = 8;	/* Turn on event counting. */
+	/* Register interrupt handler. */
+	request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound",
+		    AtaInterrupt);
+	mfp.int_en_a |= 0x20;	/* Turn interrupt on. */
+	mfp.int_mk_a |= 0x20;
+	return 1;
+}
+
+#ifdef MODULE
+static void AtaIrqCleanUp(void)
+{
+	mfp.tim_ct_a = 0;	/* stop timer */
+	mfp.int_en_a &= ~0x20;	/* turn interrupt off */
+	free_irq(IRQ_MFP_TIMA, AtaInterrupt);
+}
+#endif /* MODULE */
+
+
+#define TONE_VOXWARE_TO_DB(v) \
+	(((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25)
+#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)
+
+
+static int AtaSetBass(int bass)
+{
+	dmasound.bass = TONE_VOXWARE_TO_DB(bass);
+	atari_microwire_cmd(MW_LM1992_BASS(dmasound.bass));
+	return TONE_DB_TO_VOXWARE(dmasound.bass);
+}
+
+
+static int AtaSetTreble(int treble)
+{
+	dmasound.treble = TONE_VOXWARE_TO_DB(treble);
+	atari_microwire_cmd(MW_LM1992_TREBLE(dmasound.treble));
+	return TONE_DB_TO_VOXWARE(dmasound.treble);
+}
+
+
+
+/*
+ * TT
+ */
+
+
+static void TTSilence(void)
+{
+	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+	atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
+}
+
+
+static void TTInit(void)
+{
+	int mode, i, idx;
+	const int freq[4] = {50066, 25033, 12517, 6258};
+
+	/* search a frequency that fits into the allowed error range */
+
+	idx = -1;
+	for (i = 0; i < arraysize(freq); i++)
+		/* this isn't as much useful for a TT than for a Falcon, but
+		 * then it doesn't hurt very much to implement it for a TT too.
+		 */
+		if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+			idx = i;
+	if (idx > -1) {
+		dmasound.soft.speed = freq[idx];
+		dmasound.trans_write = &transTTNormal;
+	} else
+		dmasound.trans_write = &transTTExpanding;
+
+	TTSilence();
+	dmasound.hard = dmasound.soft;
+
+	if (dmasound.hard.speed > 50066) {
+		/* we would need to squeeze the sound, but we won't do that */
+		dmasound.hard.speed = 50066;
+		mode = DMASND_MODE_50KHZ;
+		dmasound.trans_write = &transTTNormal;
+	} else if (dmasound.hard.speed > 25033) {
+		dmasound.hard.speed = 50066;
+		mode = DMASND_MODE_50KHZ;
+	} else if (dmasound.hard.speed > 12517) {
+		dmasound.hard.speed = 25033;
+		mode = DMASND_MODE_25KHZ;
+	} else if (dmasound.hard.speed > 6258) {
+		dmasound.hard.speed = 12517;
+		mode = DMASND_MODE_12KHZ;
+	} else {
+		dmasound.hard.speed = 6258;
+		mode = DMASND_MODE_6KHZ;
+	}
+
+	tt_dmasnd.mode = (dmasound.hard.stereo ?
+			  DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+		DMASND_MODE_8BIT | mode;
+
+	expand_bal = -dmasound.soft.speed;
+}
+
+
+static int TTSetFormat(int format)
+{
+	/* TT sound DMA supports only 8bit modes */
+
+	switch (format) {
+	case AFMT_QUERY:
+		return dmasound.soft.format;
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_S8:
+	case AFMT_U8:
+		break;
+	default:
+		format = AFMT_S8;
+	}
+
+	dmasound.soft.format = format;
+	dmasound.soft.size = 8;
+	if (dmasound.minDev == SND_DEV_DSP) {
+		dmasound.dsp.format = format;
+		dmasound.dsp.size = 8;
+	}
+	TTInit();
+
+	return format;
+}
+
+
+#define VOLUME_VOXWARE_TO_DB(v) \
+	(((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
+#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
+
+
+static int TTSetVolume(int volume)
+{
+	dmasound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
+	atari_microwire_cmd(MW_LM1992_BALLEFT(dmasound.volume_left));
+	dmasound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
+	atari_microwire_cmd(MW_LM1992_BALRIGHT(dmasound.volume_right));
+	return VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |
+	       (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8);
+}
+
+
+#define GAIN_VOXWARE_TO_DB(v) \
+	(((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80)
+#define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4)
+
+static int TTSetGain(int gain)
+{
+	dmasound.gain = GAIN_VOXWARE_TO_DB(gain);
+	atari_microwire_cmd(MW_LM1992_VOLUME(dmasound.gain));
+	return GAIN_DB_TO_VOXWARE(dmasound.gain);
+}
+
+
+
+/*
+ * Falcon
+ */
+
+
+static void FalconSilence(void)
+{
+	/* stop playback, set sample rate 50kHz for PSG sound */
+	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+	tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
+	tt_dmasnd.int_div = 0; /* STE compatible divider */
+	tt_dmasnd.int_ctrl = 0x0;
+	tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
+	tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
+	tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
+	tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
+}
+
+
+static void FalconInit(void)
+{
+	int divider, i, idx;
+	const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
+
+	/* search a frequency that fits into the allowed error range */
+
+	idx = -1;
+	for (i = 0; i < arraysize(freq); i++)
+		/* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
+		 * be playable without expanding, but that now a kernel runtime
+		 * option
+		 */
+		if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+			idx = i;
+	if (idx > -1) {
+		dmasound.soft.speed = freq[idx];
+		dmasound.trans_write = &transFalconNormal;
+	} else
+		dmasound.trans_write = &transFalconExpanding;
+
+	FalconSilence();
+	dmasound.hard = dmasound.soft;
+
+	if (dmasound.hard.size == 16) {
+		/* the Falcon can play 16bit samples only in stereo */
+		dmasound.hard.stereo = 1;
+	}
+
+	if (dmasound.hard.speed > 49170) {
+		/* we would need to squeeze the sound, but we won't do that */
+		dmasound.hard.speed = 49170;
+		divider = 1;
+		dmasound.trans_write = &transFalconNormal;
+	} else if (dmasound.hard.speed > 32780) {
+		dmasound.hard.speed = 49170;
+		divider = 1;
+	} else if (dmasound.hard.speed > 24585) {
+		dmasound.hard.speed = 32780;
+		divider = 2;
+	} else if (dmasound.hard.speed > 19668) {
+		dmasound.hard.speed = 24585;
+		divider = 3;
+	} else if (dmasound.hard.speed > 16390) {
+		dmasound.hard.speed = 19668;
+		divider = 4;
+	} else if (dmasound.hard.speed > 12292) {
+		dmasound.hard.speed = 16390;
+		divider = 5;
+	} else if (dmasound.hard.speed > 9834) {
+		dmasound.hard.speed = 12292;
+		divider = 7;
+	} else if (dmasound.hard.speed > 8195) {
+		dmasound.hard.speed = 9834;
+		divider = 9;
+	} else {
+		dmasound.hard.speed = 8195;
+		divider = 11;
+	}
+	tt_dmasnd.int_div = divider;
+
+	/* Setup Falcon sound DMA for playback */
+	tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
+	tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
+	tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
+	tt_dmasnd.cbar_dst = 0x0000;
+	tt_dmasnd.rec_track_select = 0;
+	tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
+	tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
+
+	tt_dmasnd.mode = (dmasound.hard.stereo ?
+			  DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+		((dmasound.hard.size == 8) ?
+		 DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
+		DMASND_MODE_6KHZ;
+
+	expand_bal = -dmasound.soft.speed;
+}
+
+
+static int FalconSetFormat(int format)
+{
+	int size;
+	/* Falcon sound DMA supports 8bit and 16bit modes */
+
+	switch (format) {
+	case AFMT_QUERY:
+		return dmasound.soft.format;
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_U8:
+	case AFMT_S8:
+		size = 8;
+		break;
+	case AFMT_S16_BE:
+	case AFMT_U16_BE:
+	case AFMT_S16_LE:
+	case AFMT_U16_LE:
+		size = 16;
+		break;
+	default: /* :-) */
+		size = 8;
+		format = AFMT_S8;
+	}
+
+	dmasound.soft.format = format;
+	dmasound.soft.size = size;
+	if (dmasound.minDev == SND_DEV_DSP) {
+		dmasound.dsp.format = format;
+		dmasound.dsp.size = dmasound.soft.size;
+	}
+
+	FalconInit();
+
+	return format;
+}
+
+
+/* This is for the Falcon output *attenuation* in 1.5dB steps,
+ * i.e. output level from 0 to -22.5dB in -1.5dB steps.
+ */
+#define VOLUME_VOXWARE_TO_ATT(v) \
+	((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)
+#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)
+
+
+static int FalconSetVolume(int volume)
+{
+	dmasound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
+	dmasound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
+	tt_dmasnd.output_atten = dmasound.volume_left << 8 | dmasound.volume_right << 4;
+	return VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |
+	       VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8;
+}
+
+
+static void AtaPlayNextFrame(int index)
+{
+	char *start, *end;
+
+	/* used by AtaPlay() if all doubts whether there really is something
+	 * to be played are already wiped out.
+	 */
+	start = write_sq.buffers[write_sq.front];
+	end = start+((write_sq.count == index) ? write_sq.rear_size
+					       : write_sq.block_size);
+	/* end might not be a legal virtual address. */
+	DMASNDSetEnd(virt_to_phys(end - 1) + 1);
+	DMASNDSetBase(virt_to_phys(start));
+	/* Since only an even number of samples per frame can
+	   be played, we might lose one byte here. (TO DO) */
+	write_sq.front = (write_sq.front+1) % write_sq.max_count;
+	write_sq.active++;
+	tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
+}
+
+
+static void AtaPlay(void)
+{
+	/* ++TeSche: Note that write_sq.active is no longer just a flag but
+	 * holds the number of frames the DMA is currently programmed for
+	 * instead, may be 0, 1 (currently being played) or 2 (pre-programmed).
+	 *
+	 * Changes done to write_sq.count and write_sq.active are a bit more
+	 * subtle again so now I must admit I also prefer disabling the irq
+	 * here rather than considering all possible situations. But the point
+	 * is that disabling the irq doesn't have any bad influence on this
+	 * version of the driver as we benefit from having pre-programmed the
+	 * DMA wherever possible: There's no need to reload the DMA at the
+	 * exact time of an interrupt but only at some time while the
+	 * pre-programmed frame is playing!
+	 */
+	atari_disable_irq(IRQ_MFP_TIMA);
+
+	if (write_sq.active == 2 ||	/* DMA is 'full' */
+	    write_sq.count <= 0) {	/* nothing to do */
+		atari_enable_irq(IRQ_MFP_TIMA);
+		return;
+	}
+
+	if (write_sq.active == 0) {
+		/* looks like there's nothing 'in' the DMA yet, so try
+		 * to put two frames into it (at least one is available).
+		 */
+		if (write_sq.count == 1 &&
+		    write_sq.rear_size < write_sq.block_size &&
+		    !write_sq.syncing) {
+			/* hmmm, the only existing frame is not
+			 * yet filled and we're not syncing?
+			 */
+			atari_enable_irq(IRQ_MFP_TIMA);
+			return;
+		}
+		AtaPlayNextFrame(1);
+		if (write_sq.count == 1) {
+			/* no more frames */
+			atari_enable_irq(IRQ_MFP_TIMA);
+			return;
+		}
+		if (write_sq.count == 2 &&
+		    write_sq.rear_size < write_sq.block_size &&
+		    !write_sq.syncing) {
+			/* hmmm, there were two frames, but the second
+			 * one is not yet filled and we're not syncing?
+			 */
+			atari_enable_irq(IRQ_MFP_TIMA);
+			return;
+		}
+		AtaPlayNextFrame(2);
+	} else {
+		/* there's already a frame being played so we may only stuff
+		 * one new into the DMA, but even if this may be the last
+		 * frame existing the previous one is still on write_sq.count.
+		 */
+		if (write_sq.count == 2 &&
+		    write_sq.rear_size < write_sq.block_size &&
+		    !write_sq.syncing) {
+			/* hmmm, the only existing frame is not
+			 * yet filled and we're not syncing?
+			 */
+			atari_enable_irq(IRQ_MFP_TIMA);
+			return;
+		}
+		AtaPlayNextFrame(2);
+	}
+	atari_enable_irq(IRQ_MFP_TIMA);
+}
+
+
+static void AtaInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+#if 0
+	/* ++TeSche: if you should want to test this... */
+	static int cnt = 0;
+	if (write_sq.active == 2)
+		if (++cnt == 10) {
+			/* simulate losing an interrupt */
+			cnt = 0;
+			return;
+		}
+#endif
+
+	if (write_sq_ignore_int && is_falcon) {
+		/* ++TeSche: Falcon only: ignore first irq because it comes
+		 * immediately after starting a frame. after that, irqs come
+		 * (almost) like on the TT.
+		 */
+		write_sq_ignore_int = 0;
+		return;
+	}
+
+	if (!write_sq.active) {
+		/* playing was interrupted and sq_reset() has already cleared
+		 * the sq variables, so better don't do anything here.
+		 */
+		WAKE_UP(write_sq.sync_queue);
+		return;
+	}
+
+	/* Probably ;) one frame is finished. Well, in fact it may be that a
+	 * pre-programmed one is also finished because there has been a long
+	 * delay in interrupt delivery and we've completely lost one, but
+	 * there's no way to detect such a situation. In such a case the last
+	 * frame will be played more than once and the situation will recover
+	 * as soon as the irq gets through.
+	 */
+	write_sq.count--;
+	write_sq.active--;
+
+	if (!write_sq.active) {
+		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+		write_sq_ignore_int = 1;
+	}
+
+	WAKE_UP(write_sq.action_queue);
+	/* At least one block of the queue is free now
+	   so wake up a writing process blocked because
+	   of a full queue. */
+
+	if ((write_sq.active != 1) || (write_sq.count != 1))
+		/* We must be a bit carefully here: write_sq.count indicates the
+		 * number of buffers used and not the number of frames to be
+		 * played. If write_sq.count==1 and write_sq.active==1 that
+		 * means the only remaining frame was already programmed
+		 * earlier (and is currently running) so we mustn't call
+		 * AtaPlay() here, otherwise we'll play one frame too much.
+		 */
+		AtaPlay();
+
+	if (!write_sq.active) WAKE_UP(write_sq.sync_queue);
+	/* We are not playing after AtaPlay(), so there
+	   is nothing to play any more. Wake up a process
+	   waiting for audio output to drain. */
+}
+
+
+/*** Mid level stuff *********************************************************/
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+#define RECLEVEL_VOXWARE_TO_GAIN(v)	\
+	((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
+#define RECLEVEL_GAIN_TO_VOXWARE(v)	(((v) * 20 + 2) / 3)
+
+
+static void __init TTMixerInit(void)
+{
+	atari_microwire_cmd(MW_LM1992_VOLUME(0));
+	dmasound.volume_left = 0;
+	atari_microwire_cmd(MW_LM1992_BALLEFT(0));
+	dmasound.volume_right = 0;
+	atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
+	atari_microwire_cmd(MW_LM1992_TREBLE(0));
+	atari_microwire_cmd(MW_LM1992_BASS(0));
+}
+
+static void __init FalconMixerInit(void)
+{
+	dmasound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
+	dmasound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
+}
+
+static int AtaMixerIoctl(u_int cmd, u_long arg)
+{
+	int data;
+	switch (cmd) {
+	    case SOUND_MIXER_READ_SPEAKER:
+		    if (is_falcon || MACH_IS_TT) {
+			    int porta;
+			    cli();
+			    sound_ym.rd_data_reg_sel = 14;
+			    porta = sound_ym.rd_data_reg_sel;
+			    sti();
+			    return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
+		    }
+		    break;
+	    case SOUND_MIXER_WRITE_VOLUME:
+		    IOCTL_IN(arg, data);
+		    return IOCTL_OUT(arg, dmasound_set_volume(data));
+	    case SOUND_MIXER_WRITE_SPEAKER:
+		    if (is_falcon || MACH_IS_TT) {
+			    int porta;
+			    IOCTL_IN(arg, data);
+			    cli();
+			    sound_ym.rd_data_reg_sel = 14;
+			    porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+				    (data < 50 ? 0x40 : 0);
+			    sound_ym.wd_data = porta;
+			    sti();
+			    return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
+		    }
+	}
+	return -EINVAL;
+}
+
+
+static int TTMixerIoctl(u_int cmd, u_long arg)
+{
+	int data;
+	switch (cmd) {
+	    case SOUND_MIXER_READ_RECMASK:
+		return IOCTL_OUT(arg, 0);
+	    case SOUND_MIXER_READ_DEVMASK:
+		return IOCTL_OUT(arg,
+				 SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
+				 (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0));
+	    case SOUND_MIXER_READ_STEREODEVS:
+		return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
+	    case SOUND_MIXER_READ_VOLUME:
+		return IOCTL_OUT(arg,
+				 VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |
+				 (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8));
+	    case SOUND_MIXER_READ_BASS:
+		return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.bass));
+	    case SOUND_MIXER_READ_TREBLE:
+		return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.treble));
+	    case SOUND_MIXER_READ_OGAIN:
+		return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(dmasound.gain));
+	    case SOUND_MIXER_WRITE_BASS:
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, dmasound_set_bass(data));
+	    case SOUND_MIXER_WRITE_TREBLE:
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, dmasound_set_treble(data));
+	    case SOUND_MIXER_WRITE_OGAIN:
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, dmasound_set_gain(data));
+	}
+	return AtaMixerIoctl(cmd, arg);
+}
+
+static int FalconMixerIoctl(u_int cmd, u_long arg)
+{
+	int data;
+	switch (cmd) {
+	    case SOUND_MIXER_READ_RECMASK:
+		return IOCTL_OUT(arg, SOUND_MASK_MIC);
+	    case SOUND_MIXER_READ_DEVMASK:
+		return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);
+	    case SOUND_MIXER_READ_STEREODEVS:
+		return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);
+	    case SOUND_MIXER_READ_VOLUME:
+		return IOCTL_OUT(arg,
+			VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |
+			VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8);
+	    case SOUND_MIXER_READ_CAPS:
+		return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);
+	    case SOUND_MIXER_WRITE_MIC:
+		IOCTL_IN(arg, data);
+		tt_dmasnd.input_gain =
+			RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
+			RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
+		/* fall thru, return set value */
+	    case SOUND_MIXER_READ_MIC:
+		return IOCTL_OUT(arg,
+			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
+			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8);
+	}
+	return AtaMixerIoctl(cmd, arg);
+}
+
+static void AtaWriteSqSetup(void)
+{
+	write_sq_ignore_int = 0;
+}
+
+static void AtaSqOpen(void)
+{
+	write_sq_ignore_int = 1;
+}
+
+static int TTStateInfo(char *buffer)
+{
+	int len = 0;
+	len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
+		       dmasound.volume_left);
+	len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
+		       dmasound.volume_right);
+	len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
+		       dmasound.bass);
+	len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
+		       dmasound.treble);
+	return len;
+}
+
+static int FalconStateInfo(char *buffer)
+{
+	int len = 0;
+	len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
+		       dmasound.volume_left);
+	len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
+		       dmasound.volume_right);
+	return len;
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machTT = {
+	name:		"Atari",
+	name2:		"TT",
+	open:		AtaOpen,
+	release:	AtaRelease,
+	dma_alloc:	AtaAlloc,
+	dma_free:	AtaFree,
+	irqinit:	AtaIrqInit,
+#ifdef MODULE
+	irqcleanup:	AtaIrqCleanUp,
+#endif /* MODULE */
+	init:		TTInit,
+	silence:	TTSilence,
+	setFormat:	TTSetFormat,
+	setVolume:	TTSetVolume,
+	setBass:	AtaSetBass,
+	setTreble:	AtaSetTreble,
+	setGain:	TTSetGain,
+	play:		AtaPlay,
+	mixer_init:	TTMixerInit,
+	mixer_ioctl:	TTMixerIoctl,
+	write_sq_setup:	AtaWriteSqSetup,
+	sq_open:	AtaSqOpen,
+	state_info:	TTStateInfo,
+	min_dsp_speed:	6258,
+};
+
+static MACHINE machFalcon = {
+	name:		"Atari",
+	name2:		"FALCON",
+	dma_alloc:	AtaAlloc,
+	dma_free:	AtaFree,
+	irqinit:	AtaIrqInit,
+#ifdef MODULE
+	irqcleanup:	AtaIrqCleanUp,
+#endif /* MODULE */
+	init:		FalconInit,
+	silence:	FalconSilence,
+	setFormat:	FalconSetFormat,
+	setVolume:	FalconSetVolume,
+	setBass:	AtaSetBass,
+	setTreble:	AtaSetTreble,
+	play:		AtaPlay,
+	mixer_init:	FalconMixerInit,
+	mixer_ioctl:	FalconMixerIoctl,
+	write_sq_setup:	AtaWriteSqSetup,
+	sq_open:	AtaSqOpen,
+	state_info:	FalconStateInfo,
+	min_dsp_speed:	8195,
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+static int __init dmasound_atari_init(void)
+{
+	if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) {
+	    if (ATARIHW_PRESENT(CODEC)) {
+		dmasound.mach = machFalcon;
+		is_falcon = 1;
+	    } else if (ATARIHW_PRESENT(MICROWIRE)) {
+		dmasound.mach = machTT;
+		is_falcon = 0;
+	    } else
+		return -ENODEV;
+	    if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+		return dmasound_init();
+	    else {
+		printk("DMA sound driver: Timer A interrupt already in use\n");
+		return -EBUSY;
+	    }
+	}
+	return -ENODEV;
+}
+
+static void __exit dmasound_atari_cleanup(void)
+{
+	dmasound_deinit();
+}
+
+module_init(dmasound_atari_init);
+module_exit(dmasound_atari_cleanup);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound_awacs.c linux/drivers/sound/dmasound/dmasound_awacs.c
--- v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound_awacs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/dmasound/dmasound_awacs.c	Mon Apr 10 22:58:59 2000
@@ -0,0 +1,2113 @@
+
+/*
+ *  linux/drivers/sound/dmasound_awacs.c
+ *
+ *  PowerMac DMA Sound Driver
+ *
+ *  See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/adb.h>
+#include <linux/nvram.h>
+#include <linux/vt_kern.h>
+#include <linux/cuda.h>
+
+#include <asm/uaccess.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+
+#include "awacs_defs.h"
+#include "dmasound.h"
+
+
+/*
+ * Interrupt numbers and addresses, obtained from the device tree.
+ */
+static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
+static volatile struct awacs_regs *awacs;
+static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
+static int awacs_rate_index;
+static int awacs_subframe;
+static int awacs_spkr_vol;
+static struct device_node* awacs_node;
+
+static char awacs_name[64];
+static int awacs_revision;
+#define AWACS_BURGUNDY	100		/* fake revision # for burgundy */
+
+/*
+ * Space for the DBDMA command blocks.
+ */
+static void *awacs_tx_cmd_space;
+static volatile struct dbdma_cmd *awacs_tx_cmds;
+
+static void *awacs_rx_cmd_space;
+static volatile struct dbdma_cmd *awacs_rx_cmds;
+
+/*
+ * Cached values of AWACS registers (we can't read them).
+ * Except on the burgundy. XXX
+ */
+int awacs_reg[5];
+
+#define HAS_16BIT_TABLES
+#undef HAS_8BIT_TABLES
+
+/*
+ * Stuff for outputting a beep.  The values range from -327 to +327
+ * so we can multiply by an amplitude in the range 0..100 to get a
+ * signed short value to put in the output buffer.
+ */
+static short beep_wform[256] = {
+	0,	40,	79,	117,	153,	187,	218,	245,
+	269,	288,	304,	316,	323,	327,	327,	324,
+	318,	310,	299,	288,	275,	262,	249,	236,
+	224,	213,	204,	196,	190,	186,	183,	182,
+	182,	183,	186,	189,	192,	196,	200,	203,
+	206,	208,	209,	209,	209,	207,	204,	201,
+	197,	193,	188,	183,	179,	174,	170,	166,
+	163,	161,	160,	159,	159,	160,	161,	162,
+	164,	166,	168,	169,	171,	171,	171,	170,
+	169,	167,	163,	159,	155,	150,	144,	139,
+	133,	128,	122,	117,	113,	110,	107,	105,
+	103,	103,	103,	103,	104,	104,	105,	105,
+	105,	103,	101,	97,	92,	86,	78,	68,
+	58,	45,	32,	18,	3,	-11,	-26,	-41,
+	-55,	-68,	-79,	-88,	-95,	-100,	-102,	-102,
+	-99,	-93,	-85,	-75,	-62,	-48,	-33,	-16,
+	0,	16,	33,	48,	62,	75,	85,	93,
+	99,	102,	102,	100,	95,	88,	79,	68,
+	55,	41,	26,	11,	-3,	-18,	-32,	-45,
+	-58,	-68,	-78,	-86,	-92,	-97,	-101,	-103,
+	-105,	-105,	-105,	-104,	-104,	-103,	-103,	-103,
+	-103,	-105,	-107,	-110,	-113,	-117,	-122,	-128,
+	-133,	-139,	-144,	-150,	-155,	-159,	-163,	-167,
+	-169,	-170,	-171,	-171,	-171,	-169,	-168,	-166,
+	-164,	-162,	-161,	-160,	-159,	-159,	-160,	-161,
+	-163,	-166,	-170,	-174,	-179,	-183,	-188,	-193,
+	-197,	-201,	-204,	-207,	-209,	-209,	-209,	-208,
+	-206,	-203,	-200,	-196,	-192,	-189,	-186,	-183,
+	-182,	-182,	-183,	-186,	-190,	-196,	-204,	-213,
+	-224,	-236,	-249,	-262,	-275,	-288,	-299,	-310,
+	-318,	-324,	-327,	-327,	-323,	-316,	-304,	-288,
+	-269,	-245,	-218,	-187,	-153,	-117,	-79,	-40,
+};
+
+#define BEEP_SRATE	22050	/* 22050 Hz sample rate */
+#define BEEP_BUFLEN	512
+#define BEEP_VOLUME	15	/* 0 - 100 */
+
+static int beep_volume = BEEP_VOLUME;
+static int beep_playing = 0;
+static int awacs_beep_state = 0;
+static short *beep_buf;
+static volatile struct dbdma_cmd *beep_dbdma_cmd;
+static void (*orig_mksound)(unsigned int, unsigned int);
+static int is_pbook_3400;
+static unsigned char *latch_base;
+static int is_pbook_G3;
+static unsigned char *macio_base;
+
+/* Burgundy functions */
+static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
+static unsigned awacs_burgundy_rcw(unsigned addr);
+static void awacs_burgundy_write_volume(unsigned address, int volume);
+static int awacs_burgundy_read_volume(unsigned address);
+static void awacs_burgundy_write_mvolume(unsigned address, int volume);
+static int awacs_burgundy_read_mvolume(unsigned address);
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Stuff for restoring after a sleep.
+ */
+static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
+struct pmu_sleep_notifier awacs_sleep_notifier = {
+	awacs_sleep_notify, SLEEP_LEVEL_SOUND,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+static int expand_bal;	/* Balance factor for expanding (not volume!) */
+static int expand_data;	/* Data for expanding */
+
+
+/*** Translations ************************************************************/
+
+
+/* ++TeSche: radically changed for new expanding purposes...
+ *
+ * These two routines now deal with copying/expanding/translating the samples
+ * from user space into our buffer at the right frequency. They take care about
+ * how much data there's actually to read, how much buffer space there is and
+ * to convert samples into the right frequency/encoding. They will only work on
+ * complete samples so it may happen they leave some bytes in the input stream
+ * if the user didn't write a multiple of the current sample size. They both
+ * return the number of bytes they've used from both streams so you may detect
+ * such a situation. Luckily all programs should be able to cope with that.
+ *
+ * I think I've optimized anything as far as one can do in plain C, all
+ * variables should fit in registers and the loops are really short. There's
+ * one loop for every possible situation. Writing a more generalized and thus
+ * parameterized loop would only produce slower code. Feel free to optimize
+ * this in assembler if you like. :)
+ *
+ * I think these routines belong here because they're not yet really hardware
+ * independent, especially the fact that the Falcon can play 16bit samples
+ * only in stereo is hardcoded in both of them!
+ *
+ * ++geert: split in even more functions (one per format)
+ */
+
+static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void PMacOpen(void);
+static void PMacRelease(void);
+static void *PMacAlloc(unsigned int size, int flags);
+static void PMacFree(void *ptr, unsigned int size);
+static int PMacIrqInit(void);
+#ifdef MODULE
+static void PMacIrqCleanup(void);
+#endif
+static void PMacSilence(void);
+static void PMacInit(void);
+static int PMacSetFormat(int format);
+static int PMacSetVolume(int volume);
+static void PMacPlay(void);
+static void PMacRecord(void);
+static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
+static void awacs_write(int val);
+static int awacs_get_volume(int reg, int lshift);
+static int awacs_volume_setter(int volume, int n, int mute, int lshift);
+static void awacs_mksound(unsigned int hz, unsigned int ticks);
+static void awacs_nosound(unsigned long xx);
+
+
+/*** Mid level stuff **********************************************************/
+
+
+static int PMacMixerIoctl(u_int cmd, u_long arg);
+static void PMacWriteSqSetup(void);
+static void PMacReadSqSetup(void);
+static void PMacAbortRead(void);
+
+
+/*** Translations ************************************************************/
+
+
+static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	short *table = dmasound.soft.format == AFMT_MU_LAW
+		? dmasound_ulaw2dma16 : dmasound_alaw2dma16;
+	ssize_t count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = dmasound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		val = table[data];
+		*p++ = val;
+		if (stereo) {
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			val = table[data];
+		}
+		*p++ = val;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	ssize_t count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = dmasound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		val = data << 8;
+		*p++ = val;
+		if (stereo) {
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			val = data << 8;
+		}
+		*p++ = val;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	ssize_t count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = dmasound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		val = (data ^ 0x80) << 8;
+		*p++ = val;
+		if (stereo) {
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			val = (data ^ 0x80) << 8;
+		}
+		*p++ = val;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	ssize_t count, used;
+	int stereo = dmasound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	used = count = min(userCount, frameLeft);
+	if (!stereo) {
+		short *up = (short *) userPtr;
+		while (count > 0) {
+			short data;
+			if (get_user(data, up++))
+				return -EFAULT;
+			*fp++ = data;
+			*fp++ = data;
+			count--;
+		}
+	} else {
+		if (copy_from_user(fp, userPtr, count * 4))
+			return -EFAULT;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 4: used * 2;
+}
+
+static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	ssize_t count, used;
+	int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+	int stereo = dmasound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+	short *up = (short *) userPtr;
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		int data;
+		if (get_user(data, up++))
+			return -EFAULT;
+		data ^= mask;
+		*fp++ = data;
+		if (stereo) {
+			if (get_user(data, up++))
+				return -EFAULT;
+			data ^= mask;
+		}
+		*fp++ = data;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 4: used * 2;
+}
+
+
+static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
+{
+	unsigned short *table = (unsigned short *)
+		(dmasound.soft.format == AFMT_MU_LAW
+		 ? dmasound_ulaw2dma16 : dmasound_alaw2dma16);
+	unsigned int data = expand_data;
+	unsigned int *p = (unsigned int *) &frame[*frameUsed];
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int utotal, ftotal;
+	int stereo = dmasound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(c, userPtr++))
+				return -EFAULT;
+			data = table[c];
+			if (stereo) {
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data = (data << 16) + table[c];
+			} else
+				data = (data << 16) + data;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	unsigned int *p = (unsigned int *) &frame[*frameUsed];
+	unsigned int data = expand_data;
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int stereo = dmasound.soft.stereo;
+	int utotal, ftotal;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(c, userPtr++))
+				return -EFAULT;
+			data = c << 8;
+			if (stereo) {
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data = (data << 16) + (c << 8);
+			} else
+				data = (data << 16) + data;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	unsigned int *p = (unsigned int *) &frame[*frameUsed];
+	unsigned int data = expand_data;
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int stereo = dmasound.soft.stereo;
+	int utotal, ftotal;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(c, userPtr++))
+				return -EFAULT;
+			data = (c ^ 0x80) << 8;
+			if (stereo) {
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data = (data << 16) + ((c ^ 0x80) << 8);
+			} else
+				data = (data << 16) + data;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
+{
+	unsigned int *p = (unsigned int *) &frame[*frameUsed];
+	unsigned int data = expand_data;
+	unsigned short *up = (unsigned short *) userPtr;
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int stereo = dmasound.soft.stereo;
+	int utotal, ftotal;
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		unsigned short c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(data, up++))
+				return -EFAULT;
+			if (stereo) {
+				if (get_user(c, up++))
+					return -EFAULT;
+				data = (data << 16) + c;
+			} else
+				data = (data << 16) + data;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 4: utotal * 2;
+}
+
+
+static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
+{
+	int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+	unsigned int *p = (unsigned int *) &frame[*frameUsed];
+	unsigned int data = expand_data;
+	unsigned short *up = (unsigned short *) userPtr;
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int stereo = dmasound.soft.stereo;
+	int utotal, ftotal;
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		unsigned short c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(data, up++))
+				return -EFAULT;
+			data ^= mask;
+			if (stereo) {
+				if (get_user(c, up++))
+					return -EFAULT;
+				data = (data << 16) + (c ^ mask);
+			} else
+				data = (data << 16) + data;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 4: utotal * 2;
+}
+
+static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	ssize_t count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = dmasound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+
+		val = *p++;
+		data = val >> 8;
+		if (put_user(data, (u_char *)userPtr++))
+			return -EFAULT;
+		if (stereo) {
+			val = *p;
+			data = val >> 8;
+			if (put_user(data, (u_char *)userPtr++))
+				return -EFAULT;
+		}
+		p++;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	ssize_t count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = dmasound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+
+		val = *p++;
+		data = (val >> 8) ^ 0x80;
+		if (put_user(data, (u_char *)userPtr++))
+			return -EFAULT;
+		if (stereo) {
+			val = *p;
+			data = (val >> 8) ^ 0x80;
+			if (put_user(data, (u_char *)userPtr++))
+				return -EFAULT;
+		}
+		p++;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	ssize_t count, used;
+	int stereo = dmasound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	used = count = min(userCount, frameLeft);
+	if (!stereo) {
+		short *up = (short *) userPtr;
+		while (count > 0) {
+			short data;
+			data = *fp;
+			if (put_user(data, up++))
+				return -EFAULT;
+			fp+=2;
+			count--;
+		}
+	} else {
+		if (copy_to_user((u_char *)userPtr, fp, count * 4))
+			return -EFAULT;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 4: used * 2;
+}
+
+static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	ssize_t count, used;
+	int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+	int stereo = dmasound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+	short *up = (short *) userPtr;
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		int data;
+
+		data = *fp++;
+		data ^= mask;
+		if (put_user(data, up++))
+			return -EFAULT;
+		if (stereo) {
+			data = *fp;
+			data ^= mask;
+			if (put_user(data, up++))
+				return -EFAULT;
+		}
+		fp++;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 4: used * 2;
+}
+
+
+static TRANS transAwacsNormal = {
+	ct_ulaw:	pmac_ct_law,
+	ct_alaw:	pmac_ct_law,
+	ct_s8:		pmac_ct_s8,
+	ct_u8:		pmac_ct_u8,
+	ct_s16be:	pmac_ct_s16,
+	ct_u16be:	pmac_ct_u16,
+	ct_s16le:	pmac_ct_s16,
+	ct_u16le:	pmac_ct_u16,
+};
+
+static TRANS transAwacsExpand = {
+	ct_ulaw:	pmac_ctx_law,
+	ct_alaw:	pmac_ctx_law,
+	ct_s8:		pmac_ctx_s8,
+	ct_u8:		pmac_ctx_u8,
+	ct_s16be:	pmac_ctx_s16,
+	ct_u16be:	pmac_ctx_u16,
+	ct_s16le:	pmac_ctx_s16,
+	ct_u16le:	pmac_ctx_u16,
+};
+
+static TRANS transAwacsNormalRead = {
+	ct_s8:		pmac_ct_s8_read,
+	ct_u8:		pmac_ct_u8_read,
+	ct_s16be:	pmac_ct_s16_read,
+	ct_u16be:	pmac_ct_u16_read,
+	ct_s16le:	pmac_ct_s16_read,
+	ct_u16le:	pmac_ct_u16_read,
+};
+
+/*** Low level stuff *********************************************************/
+
+
+
+/*
+ * PCI PowerMac, with AWACS and DBDMA.
+ */
+
+static void PMacOpen(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void PMacRelease(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static void *PMacAlloc(unsigned int size, int flags)
+{
+	return kmalloc(size, flags);
+}
+
+static void PMacFree(void *ptr, unsigned int size)
+{
+	kfree(ptr);
+}
+
+static int __init PMacIrqInit(void)
+{
+	if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
+	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0)
+	    || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0))
+		return 0;
+	return 1;
+}
+
+#ifdef MODULE
+static void PMacIrqCleanup(void)
+{
+	/* turn off output dma */
+	out_le32(&awacs_txdma->control, RUN<<16);
+	/* disable interrupts from awacs interface */
+	out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
+#ifdef CONFIG_PMAC_PBOOK
+	if (is_pbook_G3) {
+		feature_clear(awacs_node, FEATURE_Sound_power);
+		feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+	}
+#endif
+	free_irq(awacs_irq, 0);
+	free_irq(awacs_tx_irq, 0);
+	free_irq(awacs_rx_irq, 0);
+	kfree(awacs_tx_cmd_space);
+	if (awacs_rx_cmd_space)
+		kfree(awacs_rx_cmd_space);
+	if (beep_buf)
+		kfree(beep_buf);
+	kd_mksound = orig_mksound;
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
+#endif
+}
+#endif /* MODULE */
+
+static void PMacSilence(void)
+{
+	/* turn off output dma */
+	out_le32(&awacs_txdma->control, RUN<<16);
+}
+
+static int awacs_freqs[8] = {
+	44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
+};
+static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+static void PMacInit(void)
+{
+	int i, tolerance;
+
+	switch (dmasound.soft.format) {
+	case AFMT_S16_LE:
+	case AFMT_U16_LE:
+		dmasound.hard.format = AFMT_S16_LE;
+		break;
+	default:
+		dmasound.hard.format = AFMT_S16_BE;
+		break;
+	}
+	dmasound.hard.stereo = 1;
+	dmasound.hard.size = 16;
+
+	/*
+	 * If we have a sample rate which is within catchRadius percent
+	 * of the requested value, we don't have to expand the samples.
+	 * Otherwise choose the next higher rate.
+	 * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz.
+	 */
+	i = 8;
+	do {
+		tolerance = catchRadius * awacs_freqs[--i] / 100;
+		if (awacs_freqs_ok[i]
+		    && dmasound.soft.speed <= awacs_freqs[i] + tolerance)
+			break;
+	} while (i > 0);
+	if (dmasound.soft.speed >= awacs_freqs[i] - tolerance)
+		dmasound.trans_write = &transAwacsNormal;
+	else
+		dmasound.trans_write = &transAwacsExpand;
+	dmasound.trans_read = &transAwacsNormalRead;
+	dmasound.hard.speed = awacs_freqs[i];
+	awacs_rate_index = i;
+
+	/* XXX disable error interrupt on burgundy for now */
+	out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11
+		 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
+	awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
+	awacs_write(awacs_reg[1] | MASK_ADDR1);
+	out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+
+	/* We really want to execute a DMA stop command, after the AWACS
+	 * is initialized.
+	 * For reasons I don't understand, it stops the hissing noise
+	 * common to many PowerBook G3 systems (like mine :-).
+	 */
+	out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+	st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+	out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+	out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+
+	expand_bal = -dmasound.soft.speed;
+}
+
+static int PMacSetFormat(int format)
+{
+	int size;
+
+	switch (format) {
+	case AFMT_QUERY:
+		return dmasound.soft.format;
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_U8:
+	case AFMT_S8:
+		size = 8;
+		break;
+	case AFMT_S16_BE:
+	case AFMT_U16_BE:
+	case AFMT_S16_LE:
+	case AFMT_U16_LE:
+		size = 16;
+		break;
+	default: /* :-) */
+		printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
+		       format);
+		size = 8;
+		format = AFMT_U8;
+	}
+
+	dmasound.soft.format = format;
+	dmasound.soft.size = size;
+	if (dmasound.minDev == SND_DEV_DSP) {
+		dmasound.dsp.format = format;
+		dmasound.dsp.size = size;
+	}
+
+	PMacInit();
+
+	return format;
+}
+
+#define AWACS_VOLUME_TO_MASK(x)	(15 - ((((x) - 1) * 15) / 99))
+#define AWACS_MASK_TO_VOLUME(y)	(100 - ((y) * 99 / 15))
+
+static int awacs_get_volume(int reg, int lshift)
+{
+	int volume;
+
+	volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
+	volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
+	return volume;
+}
+
+static int awacs_volume_setter(int volume, int n, int mute, int lshift)
+{
+	int r1, rn;
+
+	if (mute && volume == 0) {
+		r1 = awacs_reg[1] | mute;
+	} else {
+		r1 = awacs_reg[1] & ~mute;
+		rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
+		rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
+		rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
+		awacs_reg[n] = rn;
+		awacs_write((n << 12) | rn);
+		volume = awacs_get_volume(rn, lshift);
+	}
+	if (r1 != awacs_reg[1]) {
+		awacs_reg[1] = r1;
+		awacs_write(r1 | MASK_ADDR1);
+	}
+	return volume;
+}
+
+static int PMacSetVolume(int volume)
+{
+	return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);
+}
+
+static void PMacPlay(void)
+{
+	volatile struct dbdma_cmd *cp;
+	int i, count;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	if (awacs_beep_state) {
+		/* sound takes precedence over beeps */
+		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+		out_le32(&awacs->control,
+			 (in_le32(&awacs->control) & ~0x1f00)
+			 | (awacs_rate_index << 8));
+		out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+		out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(write_sq.front+write_sq.active) % write_sq.max_count])));
+
+		beep_playing = 0;
+		awacs_beep_state = 0;
+	}
+	i = write_sq.front + write_sq.active;
+	if (i >= write_sq.max_count)
+		i -= write_sq.max_count;
+	while (write_sq.active < 2 && write_sq.active < write_sq.count) {
+		count = (write_sq.count == write_sq.active + 1)?write_sq.rear_size:write_sq.block_size;
+		if (count < write_sq.block_size && !write_sq.syncing)
+			/* last block not yet filled, and we're not syncing. */
+			break;
+		cp = &awacs_tx_cmds[i];
+		st_le16(&cp->req_count, count);
+		st_le16(&cp->xfer_status, 0);
+		if (++i >= write_sq.max_count)
+			i = 0;
+		out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
+		out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
+		if (write_sq.active == 0)
+			out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
+		out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+		++write_sq.active;
+	}
+	restore_flags(flags);
+}
+
+
+static void PMacRecord(void)
+{
+	unsigned long flags;
+
+	if (read_sq.active)
+		return;
+
+	save_flags(flags); cli();
+
+	/* This is all we have to do......Just start it up.
+	*/
+	out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+	read_sq.active = 1;
+
+	restore_flags(flags);
+}
+
+
+static void
+pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+	int i = write_sq.front;
+	int stat;
+	volatile struct dbdma_cmd *cp;
+
+	while (write_sq.active > 0) {
+		cp = &awacs_tx_cmds[i];
+		stat = ld_le16(&cp->xfer_status);
+		if ((stat & ACTIVE) == 0)
+			break;	/* this frame is still going */
+		--write_sq.count;
+		--write_sq.active;
+		if (++i >= write_sq.max_count)
+			i = 0;
+	}
+	if (i != write_sq.front)
+		WAKE_UP(write_sq.action_queue);
+	write_sq.front = i;
+
+	PMacPlay();
+
+	if (!write_sq.active)
+		WAKE_UP(write_sq.sync_queue);
+}
+
+
+static void
+pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+
+	/* For some reason on my PowerBook G3, I get one interrupt
+	 * when the interrupt vector is installed (like something is
+	 * pending).  This happens before the dbdma is initialize by
+	 * us, so I just check the command pointer and if it is zero,
+	 * just blow it off.
+	 */
+	if (in_le32(&awacs_rxdma->cmdptr) == 0)
+		return;
+
+	/* We also want to blow 'em off when shutting down.
+	*/
+	if (read_sq.active == 0)
+		return;
+
+	/* Check multiple buffers in case we were held off from
+	 * interrupt processing for a long time.  Geeze, I really hope
+	 * this doesn't happen.
+	 */
+	while (awacs_rx_cmds[read_sq.rear].xfer_status) {
+
+		/* Clear status and move on to next buffer.
+		*/
+		awacs_rx_cmds[read_sq.rear].xfer_status = 0;
+		read_sq.rear++;
+
+		/* Wrap the buffer ring.
+		*/
+		if (read_sq.rear >= read_sq.max_active)
+			read_sq.rear = 0;
+
+		/* If we have caught up to the front buffer, bump it.
+		 * This will cause weird (but not fatal) results if the
+		 * read loop is currently using this buffer.  The user is
+		 * behind in this case anyway, so weird things are going
+		 * to happen.
+		 */
+		if (read_sq.rear == read_sq.front) {
+			read_sq.front++;
+			if (read_sq.front >= read_sq.max_active)
+				read_sq.front = 0;
+		}
+	}
+
+	WAKE_UP(read_sq.action_queue);
+}
+
+
+static void
+pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
+{
+	int ctrl = in_le32(&awacs->control);
+
+	if (ctrl & MASK_PORTCHG) {
+		/* do something when headphone is plugged/unplugged? */
+	}
+	if (ctrl & MASK_CNTLERR) {
+		int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16;
+		if (err != 0 && awacs_revision < AWACS_BURGUNDY)
+			printk(KERN_ERR "AWACS: error %x\n", err);
+	}
+	/* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
+	out_le32(&awacs->control, ctrl);
+}
+
+static void
+awacs_write(int val)
+{
+	if (awacs_revision >= AWACS_BURGUNDY)
+		return;
+	while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
+		;	/* XXX should have timeout */
+	out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));
+}
+
+static void awacs_nosound(unsigned long xx)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	if (beep_playing) {
+		st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+		out_le32(&awacs->control,
+			 (in_le32(&awacs->control) & ~0x1f00)
+			 | (awacs_rate_index << 8));
+		out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+		beep_playing = 0;
+	}
+	restore_flags(flags);
+}
+
+static struct timer_list beep_timer = {
+	NULL, NULL, 0, 0, awacs_nosound
+};
+
+static void awacs_mksound(unsigned int hz, unsigned int ticks)
+{
+	unsigned long flags;
+	int beep_speed = 0;
+	int srate;
+	int period, ncycles, nsamples;
+	int i, j, f;
+	short *p;
+	static int beep_hz_cache;
+	static int beep_nsamples_cache;
+	static int beep_volume_cache;
+
+	for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)
+		if (awacs_freqs_ok[i])
+			beep_speed = i;
+	srate = awacs_freqs[beep_speed];
+
+	if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
+#if 1
+		/* this is a hack for broken X server code */
+		hz = 750;
+		ticks = 12;
+#else
+		/* cancel beep currently playing */
+		awacs_nosound(0);
+		return;
+#endif
+	}
+	save_flags(flags); cli();
+	del_timer(&beep_timer);
+	if (ticks) {
+		beep_timer.expires = jiffies + ticks;
+		add_timer(&beep_timer);
+	}
+	if (beep_playing || write_sq.active || beep_buf == NULL) {
+		restore_flags(flags);
+		return;		/* too hard, sorry :-( */
+	}
+	beep_playing = 1;
+	st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
+	restore_flags(flags);
+
+	if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
+		nsamples = beep_nsamples_cache;
+	} else {
+		period = srate * 256 / hz;	/* fixed point */
+		ncycles = BEEP_BUFLEN * 256 / period;
+		nsamples = (period * ncycles) >> 8;
+		f = ncycles * 65536 / nsamples;
+		j = 0;
+		p = beep_buf;
+		for (i = 0; i < nsamples; ++i, p += 2) {
+			p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
+			j = (j + f) & 0xffff;
+		}
+		beep_hz_cache = hz;
+		beep_volume_cache = beep_volume;
+		beep_nsamples_cache = nsamples;
+	}
+
+	st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
+	st_le16(&beep_dbdma_cmd->xfer_status, 0);
+	st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
+	st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
+	awacs_beep_state = 1;
+
+	save_flags(flags); cli();
+	if (beep_playing) {	/* i.e. haven't been terminated already */
+		out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+		out_le32(&awacs->control,
+			 (in_le32(&awacs->control) & ~0x1f00)
+			 | (beep_speed << 8));
+		out_le32(&awacs->byteswap, 0);
+		out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+		out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+	}
+	restore_flags(flags);
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Save state when going to sleep, restore it afterwards.
+ */
+static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+	switch (when) {
+	case PBOOK_SLEEP_NOW:
+		/* XXX we should stop any dma in progress when going to sleep
+		   and restart it when we wake. */
+		PMacSilence();
+		disable_irq(awacs_irq);
+		disable_irq(awacs_tx_irq);
+		if (is_pbook_G3) {
+			feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+			feature_clear(awacs_node, FEATURE_Sound_power);
+		}
+		break;
+	case PBOOK_WAKE:
+		/* There is still a problem on wake. Sound seems to work fine
+		   if I launch mpg123 and resumes fine if mpg123 was playing,
+		   but the console beep is dead until I do something with the
+		   mixer. Probably yet another timing issue */
+		if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
+		    || !feature_test(awacs_node, FEATURE_Sound_power)) {
+			/* these aren't present on the 3400 AFAIK -- paulus */
+			feature_set(awacs_node, FEATURE_Sound_CLK_enable);
+			feature_set(awacs_node, FEATURE_Sound_power);
+			mdelay(1000);
+		}
+		out_le32(&awacs->control, MASK_IEPC
+			 | (awacs_rate_index << 8) | 0x11
+			 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
+		awacs_write(awacs_reg[0] | MASK_ADDR0);
+		awacs_write(awacs_reg[1] | MASK_ADDR1);
+		awacs_write(awacs_reg[2] | MASK_ADDR2);
+		awacs_write(awacs_reg[4] | MASK_ADDR4);
+		out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+		enable_irq(awacs_irq);
+		enable_irq(awacs_tx_irq);
+		if (awacs_revision == 3) {
+			mdelay(100);
+			awacs_write(0x6000);
+			mdelay(2);
+			awacs_write(awacs_reg[1] | MASK_ADDR1);
+		}
+		/* enable CD sound input */
+		if (macio_base && is_pbook_G3) {
+			out_8(macio_base + 0x37, 3);
+		} else if (is_pbook_3400) {
+			feature_set(awacs_node, FEATURE_IOBUS_enable);
+			udelay(10);
+			in_8(latch_base + 0x190);
+		}
+		/* Resume pending sounds. */
+		PMacPlay();
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+
+/* All the burgundy functions: */
+
+/* Waits for busy flag to clear */
+inline static void
+awacs_burgundy_busy_wait(void)
+{
+	while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
+		;
+}
+
+inline static void
+awacs_burgundy_extend_wait(void)
+{
+	while (!(in_le32(&awacs->codec_stat) & MASK_EXTEND))
+		;
+	while (in_le32(&awacs->codec_stat) & MASK_EXTEND)
+		;
+}
+
+static void
+awacs_burgundy_wcw(unsigned addr, unsigned val)
+{
+	out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
+	awacs_burgundy_busy_wait();
+	out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
+	awacs_burgundy_busy_wait();
+	out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
+	awacs_burgundy_busy_wait();
+	out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
+	awacs_burgundy_busy_wait();
+}
+
+static unsigned
+awacs_burgundy_rcw(unsigned addr)
+{
+	unsigned val = 0;
+	unsigned long flags;
+
+	/* should have timeouts here */
+	save_flags(flags); cli();
+
+	out_le32(&awacs->codec_ctrl, addr + 0x100000);
+	awacs_burgundy_busy_wait();
+	awacs_burgundy_extend_wait();
+	val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
+
+	out_le32(&awacs->codec_ctrl, addr + 0x100100);
+	awacs_burgundy_busy_wait();
+	awacs_burgundy_extend_wait();
+	val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8;
+
+	out_le32(&awacs->codec_ctrl, addr + 0x100200);
+	awacs_burgundy_busy_wait();
+	awacs_burgundy_extend_wait();
+	val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16;
+
+	out_le32(&awacs->codec_ctrl, addr + 0x100300);
+	awacs_burgundy_busy_wait();
+	awacs_burgundy_extend_wait();
+	val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24;
+
+	restore_flags(flags);
+
+	return val;
+}
+
+
+static void
+awacs_burgundy_wcb(unsigned addr, unsigned val)
+{
+	out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
+	awacs_burgundy_busy_wait();
+}
+
+static unsigned
+awacs_burgundy_rcb(unsigned addr)
+{
+	unsigned val = 0;
+	unsigned long flags;
+
+	/* should have timeouts here */
+	save_flags(flags); cli();
+
+	out_le32(&awacs->codec_ctrl, addr + 0x100000);
+	awacs_burgundy_busy_wait();
+	awacs_burgundy_extend_wait();
+	val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
+
+	restore_flags(flags);
+
+	return val;
+}
+
+static int
+awacs_burgundy_check(void)
+{
+	/* Checks to see the chip is alive and kicking */
+	int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE;
+
+	return error == 0xf0000;
+}
+
+static int
+awacs_burgundy_init(void)
+{
+	if (awacs_burgundy_check()) {
+		printk(KERN_WARNING "AWACS: disabled by MacOS :-(\n");
+		return 1;
+	}
+
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES,
+			   DEF_BURGUNDY_OUTPUTENABLES);
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+			   DEF_BURGUNDY_MORE_OUTPUTENABLES);
+	awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
+			   DEF_BURGUNDY_OUTPUTSELECTS);
+
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21,
+			   DEF_BURGUNDY_INPSEL21);
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3,
+			   DEF_BURGUNDY_INPSEL3);
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD,
+			   DEF_BURGUNDY_GAINCD);
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE,
+			   DEF_BURGUNDY_GAINLINE);
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC,
+			   DEF_BURGUNDY_GAINMIC);
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM,
+			   DEF_BURGUNDY_GAINMODEM);
+
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER,
+			   DEF_BURGUNDY_ATTENSPEAKER);
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT,
+			   DEF_BURGUNDY_ATTENLINEOUT);
+	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP,
+			   DEF_BURGUNDY_ATTENHP);
+
+	awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME,
+			   DEF_BURGUNDY_MASTER_VOLUME);
+	awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD,
+			   DEF_BURGUNDY_VOLCD);
+	awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE,
+			   DEF_BURGUNDY_VOLLINE);
+	awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC,
+			   DEF_BURGUNDY_VOLMIC);
+	return 0;
+}
+
+static void
+awacs_burgundy_write_volume(unsigned address, int volume)
+{
+	int hardvolume,lvolume,rvolume;
+
+	lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0;
+	rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0;
+
+	hardvolume = lvolume + (rvolume << 16);
+
+	awacs_burgundy_wcw(address, hardvolume);
+}
+
+static int
+awacs_burgundy_read_volume(unsigned address)
+{
+	int softvolume,wvolume;
+
+	wvolume = awacs_burgundy_rcw(address);
+
+	softvolume = (wvolume & 0xff) - 155;
+	softvolume += (((wvolume >> 16) & 0xff) - 155)<<8;
+
+	return softvolume > 0 ? softvolume : 0;
+}
+
+
+
+
+static int
+awacs_burgundy_read_mvolume(unsigned address)
+{
+	int lvolume,rvolume,wvolume;
+
+	wvolume = awacs_burgundy_rcw(address);
+
+	wvolume &= 0xffff;
+
+	rvolume = (wvolume & 0xff) - 155;
+	lvolume = ((wvolume & 0xff00)>>8) - 155;
+
+	return lvolume + (rvolume << 8);
+}
+
+
+static void
+awacs_burgundy_write_mvolume(unsigned address, int volume)
+{
+	int lvolume,rvolume,hardvolume;
+
+	lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0;
+	rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0;
+
+	hardvolume = lvolume + (rvolume << 8);
+	hardvolume += (hardvolume << 16);
+
+	awacs_burgundy_wcw(address, hardvolume);
+}
+
+/* End burgundy functions */
+
+
+
+
+
+/* Turn on sound output, needed on G3 desktop powermacs */
+static void
+awacs_enable_amp(int spkr_vol)
+{
+	struct adb_request req;
+
+	awacs_spkr_vol = spkr_vol;
+	if (sys_ctrler != SYS_CTRLER_CUDA)
+		return;
+
+	/* turn on headphones */
+	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+		     0x8a, 4, 0);
+	while (!req.complete) cuda_poll();
+	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+		     0x8a, 6, 0);
+	while (!req.complete) cuda_poll();
+
+	/* turn on speaker */
+	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+		     0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100);
+	while (!req.complete) cuda_poll();
+	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+		     0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100);
+	while (!req.complete) cuda_poll();
+
+	cuda_request(&req, NULL, 5, CUDA_PACKET,
+		     CUDA_GET_SET_IIC, 0x8a, 1, 0x29);
+	while (!req.complete) cuda_poll();
+}
+
+
+/*** Mid level stuff *********************************************************/
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+static int PMacMixerIoctl(u_int cmd, u_long arg)
+{
+	int data;
+	/* Different IOCTLS for burgundy*/
+	if (awacs_revision < AWACS_BURGUNDY) {
+		switch (cmd) {
+		case SOUND_MIXER_READ_DEVMASK:
+			data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+				| SOUND_MASK_LINE | SOUND_MASK_MIC
+				| SOUND_MASK_CD | SOUND_MASK_RECLEV
+				| SOUND_MASK_ALTPCM
+				| SOUND_MASK_MONITOR;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_RECMASK:
+			data = SOUND_MASK_LINE | SOUND_MASK_MIC
+				| SOUND_MASK_CD;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_RECSRC:
+			data = 0;
+			if (awacs_reg[0] & MASK_MUX_AUDIN)
+				data |= SOUND_MASK_LINE;
+			if (awacs_reg[0] & MASK_MUX_MIC)
+				data |= SOUND_MASK_MIC;
+			if (awacs_reg[0] & MASK_MUX_CD)
+				data |= SOUND_MASK_CD;
+			if (awacs_reg[1] & MASK_LOOPTHRU)
+				data |= SOUND_MASK_MONITOR;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_RECSRC:
+			IOCTL_IN(arg, data);
+			data &= (SOUND_MASK_LINE
+				 | SOUND_MASK_MIC | SOUND_MASK_CD
+				 | SOUND_MASK_MONITOR);
+			awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
+					  | MASK_MUX_AUDIN);
+			awacs_reg[1] &= ~MASK_LOOPTHRU;
+			if (data & SOUND_MASK_LINE)
+				awacs_reg[0] |= MASK_MUX_AUDIN;
+			if (data & SOUND_MASK_MIC)
+				awacs_reg[0] |= MASK_MUX_MIC;
+			if (data & SOUND_MASK_CD)
+				awacs_reg[0] |= MASK_MUX_CD;
+			if (data & SOUND_MASK_MONITOR)
+				awacs_reg[1] |= MASK_LOOPTHRU;
+			awacs_write(awacs_reg[0] | MASK_ADDR0);
+			awacs_write(awacs_reg[1] | MASK_ADDR1);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_STEREODEVS:
+			data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+				| SOUND_MASK_RECLEV;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_CAPS:
+			return IOCTL_OUT(arg, 0);
+		case SOUND_MIXER_READ_VOLUME:
+			data = (awacs_reg[1] & MASK_AMUTE)? 0:
+				awacs_get_volume(awacs_reg[2], 6);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_VOLUME:
+			IOCTL_IN(arg, data);
+			return IOCTL_OUT(arg, dmasound_set_volume(data));
+		case SOUND_MIXER_READ_SPEAKER:
+			if (awacs_revision == 3
+			    && sys_ctrler == SYS_CTRLER_CUDA)
+				data = awacs_spkr_vol;
+			else
+				data = (awacs_reg[1] & MASK_CMUTE)? 0:
+					awacs_get_volume(awacs_reg[4], 6);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_SPEAKER:
+			IOCTL_IN(arg, data);
+			if (awacs_revision == 3
+			    && sys_ctrler == SYS_CTRLER_CUDA)
+				awacs_enable_amp(data);
+			else
+				data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */
+			IOCTL_IN(arg, data);
+			beep_volume = data & 0xff;
+			/* fall through */
+		case SOUND_MIXER_READ_ALTPCM:
+			return IOCTL_OUT(arg, beep_volume);
+		case SOUND_MIXER_WRITE_LINE:
+			IOCTL_IN(arg, data);
+			awacs_reg[0] &= ~MASK_MUX_AUDIN;
+			if ((data & 0xff) >= 50)
+				awacs_reg[0] |= MASK_MUX_AUDIN;
+			awacs_write(MASK_ADDR0 | awacs_reg[0]);
+			/* fall through */
+		case SOUND_MIXER_READ_LINE:
+			data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_MIC:
+			IOCTL_IN(arg, data);
+			data &= 0xff;
+			awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);
+			if (data >= 25) {
+				awacs_reg[0] |= MASK_MUX_MIC;
+				if (data >= 75)
+					awacs_reg[0] |= MASK_GAINLINE;
+			}
+			awacs_write(MASK_ADDR0 | awacs_reg[0]);
+			/* fall through */
+		case SOUND_MIXER_READ_MIC:
+			data = (awacs_reg[0] & MASK_MUX_MIC)?
+				(awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_CD:
+			IOCTL_IN(arg, data);
+			awacs_reg[0] &= ~MASK_MUX_CD;
+			if ((data & 0xff) >= 50)
+				awacs_reg[0] |= MASK_MUX_CD;
+			awacs_write(MASK_ADDR0 | awacs_reg[0]);
+			/* fall through */
+		case SOUND_MIXER_READ_CD:
+			data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_RECLEV:
+			IOCTL_IN(arg, data);
+			data = awacs_volume_setter(data, 0, 0, 4);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_RECLEV:
+			data = awacs_get_volume(awacs_reg[0], 4);
+			return IOCTL_OUT(arg, data);
+		}
+	} else {
+		/* We are, we are, we are... Burgundy or better */
+		switch(cmd) {
+		case SOUND_MIXER_READ_DEVMASK:
+			data = SOUND_MASK_VOLUME | SOUND_MASK_CD |
+				SOUND_MASK_LINE | SOUND_MASK_MIC |
+				SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_RECMASK:
+			data = SOUND_MASK_LINE | SOUND_MASK_MIC
+				| SOUND_MASK_CD;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_RECSRC:
+			data = 0;
+			if (awacs_reg[0] & MASK_MUX_AUDIN)
+				data |= SOUND_MASK_LINE;
+			if (awacs_reg[0] & MASK_MUX_MIC)
+				data |= SOUND_MASK_MIC;
+			if (awacs_reg[0] & MASK_MUX_CD)
+				data |= SOUND_MASK_CD;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_RECSRC:
+			IOCTL_IN(arg, data);
+			data &= (SOUND_MASK_LINE
+				 | SOUND_MASK_MIC | SOUND_MASK_CD);
+			awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
+					  | MASK_MUX_AUDIN);
+			if (data & SOUND_MASK_LINE)
+				awacs_reg[0] |= MASK_MUX_AUDIN;
+			if (data & SOUND_MASK_MIC)
+				awacs_reg[0] |= MASK_MUX_MIC;
+			if (data & SOUND_MASK_CD)
+				awacs_reg[0] |= MASK_MUX_CD;
+			awacs_write(awacs_reg[0] | MASK_ADDR0);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_STEREODEVS:
+			data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+				| SOUND_MASK_RECLEV | SOUND_MASK_CD
+				| SOUND_MASK_LINE;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_CAPS:
+			return IOCTL_OUT(arg, 0);
+		case SOUND_MIXER_WRITE_VOLUME:
+			IOCTL_IN(arg, data);
+			awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data);
+			/* Fall through */
+		case SOUND_MIXER_READ_VOLUME:
+			return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME));
+		case SOUND_MIXER_WRITE_SPEAKER:
+			IOCTL_IN(arg, data);
+
+			if (!(data & 0xff)) {
+			  /* Mute the left speaker */
+			  awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+					     awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2);
+			} else {
+			  /* Unmute the left speaker */
+			  awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+					     awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2);
+			}
+			if (!(data & 0xff00)) {
+			  /* Mute the right speaker */
+			  awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+					     awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4);
+			} else {
+			  /* Unmute the right speaker */
+			  awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+					     awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4);
+			}
+
+			data = (((data&0xff)*16)/100 > 0xf ? 0xf :
+				(((data&0xff)*16)/100)) +
+				 ((((data>>8)*16)/100 > 0xf ? 0xf :
+				((((data>>8)*16)/100)))<<4);
+
+			awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data);
+			/* Fall through */
+		case SOUND_MIXER_READ_SPEAKER:
+			data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER);
+			data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8);
+			return IOCTL_OUT(arg, ~data);
+		case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */
+			IOCTL_IN(arg, data);
+			beep_volume = data & 0xff;
+			/* fall through */
+		case SOUND_MIXER_READ_ALTPCM:
+			return IOCTL_OUT(arg, beep_volume);
+		case SOUND_MIXER_WRITE_LINE:
+			IOCTL_IN(arg, data);
+			awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data);
+
+			/* fall through */
+		case SOUND_MIXER_READ_LINE:
+			data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_MIC:
+			IOCTL_IN(arg, data);
+			/* Mic is mono device */
+			data = (data << 8) + (data << 24);
+			awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data);
+			/* fall through */
+		case SOUND_MIXER_READ_MIC:
+			data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC);
+			data <<= 24;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_CD:
+			IOCTL_IN(arg, data);
+			awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data);
+			/* fall through */
+		case SOUND_MIXER_READ_CD:
+			data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_RECLEV:
+			IOCTL_IN(arg, data);
+			data = awacs_volume_setter(data, 0, 0, 4);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_RECLEV:
+			data = awacs_get_volume(awacs_reg[0], 4);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_OUTMASK:
+			break;
+		case SOUND_MIXER_OUTSRC:
+			break;
+		}
+	}
+	return -EINVAL;
+}
+
+
+static void PMacWriteSqSetup(void)
+{
+	int i;
+	volatile struct dbdma_cmd *cp;
+
+	cp = awacs_tx_cmds;
+	memset((void *)cp, 0, (write_sq.numBufs+1) * sizeof(struct dbdma_cmd));
+	for (i = 0; i < write_sq.numBufs; ++i, ++cp) {
+		st_le32(&cp->phy_addr, virt_to_bus(write_sq.buffers[i]));
+	}
+	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+	st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
+	out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
+}
+
+static void PMacReadSqSetup(void)
+{
+	int i;
+	volatile struct dbdma_cmd *cp;
+
+	cp = awacs_rx_cmds;
+	memset((void *)cp, 0, (read_sq.numBufs+1) * sizeof(struct dbdma_cmd));
+
+	/* Set dma buffers up in a loop */
+	for (i = 0; i < read_sq.numBufs; i++,cp++) {
+		st_le32(&cp->phy_addr, virt_to_bus(read_sq.buffers[i]));
+		st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);
+		st_le16(&cp->req_count, read_sq.block_size);
+		st_le16(&cp->xfer_status, 0);
+	}
+
+	/* The next two lines make the thing loop around.
+	*/
+	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+	st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));
+
+	/* Don't start until the first read is done.
+	 * This will also abort any operations in progress if the DMA
+	 * happens to be running (and it shouldn't).
+	 */
+	out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));
+
+}
+
+static void PMacAbortRead(void)
+{
+	int i;
+	volatile struct dbdma_cmd *cp;
+
+	cp = awacs_rx_cmds;
+	for (i = 0; i < read_sq.numBufs; i++,cp++)
+		st_le16(&cp->command, DBDMA_STOP);
+	/*
+	 * We should probably wait for the thing to stop before we
+	 * release the memory
+	 */
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machPMac = {
+	name:		awacs_name,
+	name2:		"AWACS",
+	open:		PMacOpen,
+	release:	PMacRelease,
+	dma_alloc:	PMacAlloc,
+	dma_free:	PMacFree,
+	irqinit:	PMacIrqInit,
+#ifdef MODULE
+	irqcleanup:	PMacIrqCleanup,
+#endif /* MODULE */
+	init:		PMacInit,
+	silence:	PMacSilence,
+	setFormat:	PMacSetFormat,
+	setVolume:	PMacSetVolume,
+	play:		PMacPlay,
+	record:		PMacRecord,
+	mixer_ioctl:	PMacMixerIoctl,
+	write_sq_setup:	PMacWriteSqSetup,
+	read_sq_setup:	PMacReadSqSetup,
+	abort_read:	PMacAbortRead,
+	min_dsp_speed:	8000
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+int __init dmasound_awacs_init(void)
+{
+	struct device_node *np;
+
+	if (_machine != _MACH_Pmac)
+		return -ENODEV;
+
+	awacs_subframe = 0;
+	awacs_revision = 0;
+	np = find_devices("awacs");
+	if (np == 0) {
+		/*
+		 * powermac G3 models have a node called "davbus"
+		 * with a child called "sound".
+		 */
+		struct device_node *sound;
+		np = find_devices("davbus");
+		sound = find_devices("sound");
+		if (sound != 0 && sound->parent == np) {
+			unsigned int *prop, l, i;
+			prop = (unsigned int *)
+				get_property(sound, "sub-frame", 0);
+			if (prop != 0 && *prop >= 0 && *prop < 16)
+				awacs_subframe = *prop;
+			if (device_is_compatible(sound, "burgundy"))
+				awacs_revision = AWACS_BURGUNDY;
+
+			/* look for a property saying what sample rates
+			   are available */
+			for (i = 0; i < 8; ++i)
+				awacs_freqs_ok[i] = 0;
+			prop = (unsigned int *) get_property
+				(sound, "sample-rates", &l);
+			if (prop == 0)
+				prop = (unsigned int *) get_property
+					(sound, "output-frame-rates", &l);
+			if (prop != 0) {
+				for (l /= sizeof(int); l > 0; --l) {
+					/* sometimes the rate is in the
+					   high-order 16 bits (?) */
+					unsigned int r = *prop++;
+					if (r >= 0x10000)
+						r >>= 16;
+					for (i = 0; i < 8; ++i) {
+						if (r == awacs_freqs[i]) {
+							awacs_freqs_ok[i] = 1;
+							break;
+						}
+					}
+				}
+			} else {
+				/* assume just 44.1k is OK */
+				awacs_freqs_ok[0] = 1;
+			}
+		}
+	}
+	if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
+		int vol;
+		dmasound.mach = machPMac;
+
+		awacs = (volatile struct awacs_regs *)
+			ioremap(np->addrs[0].address, 0x80);
+		awacs_txdma = (volatile struct dbdma_regs *)
+			ioremap(np->addrs[1].address, 0x100);
+		awacs_rxdma = (volatile struct dbdma_regs *)
+			ioremap(np->addrs[2].address, 0x100);
+
+		awacs_irq = np->intrs[0].line;
+		awacs_tx_irq = np->intrs[1].line;
+		awacs_rx_irq = np->intrs[2].line;
+
+		awacs_tx_cmd_space = kmalloc((write_sq.numBufs + 4) * sizeof(struct dbdma_cmd),
+					     GFP_KERNEL);
+		if (awacs_tx_cmd_space == NULL) {
+			printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
+			return -ENOMEM;
+		}
+		awacs_node = np;
+#ifdef CONFIG_PMAC_PBOOK
+		if (machine_is_compatible("PowerBook1,1")
+		    || machine_is_compatible("AAPL,PowerBook1998")) {
+			feature_set(np, FEATURE_Sound_CLK_enable);
+			feature_set(np, FEATURE_Sound_power);
+			/* Shorter delay will not work */
+			mdelay(1000);
+		}
+#endif
+		awacs_tx_cmds = (volatile struct dbdma_cmd *)
+			DBDMA_ALIGN(awacs_tx_cmd_space);
+
+
+		awacs_rx_cmd_space = kmalloc((read_sq.numBufs + 4) * sizeof(struct dbdma_cmd),
+					     GFP_KERNEL);
+		if (awacs_rx_cmd_space == NULL) {
+		  printk("DMA sound driver: No memory for input");
+		}
+		awacs_rx_cmds = (volatile struct dbdma_cmd *)
+		  DBDMA_ALIGN(awacs_rx_cmd_space);
+
+
+
+		awacs_reg[0] = MASK_MUX_CD;
+		awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
+		/* get default volume from nvram */
+		vol = (~nvram_read_byte(0x1308) & 7) << 1;
+		awacs_reg[2] = vol + (vol << 6);
+		awacs_reg[4] = vol + (vol << 6);
+		out_le32(&awacs->control, 0x11);
+		awacs_write(awacs_reg[0] + MASK_ADDR0);
+		awacs_write(awacs_reg[1] + MASK_ADDR1);
+		awacs_write(awacs_reg[2] + MASK_ADDR2);
+		awacs_write(awacs_reg[4] + MASK_ADDR4);
+
+		/* Initialize recent versions of the awacs */
+		if (awacs_revision == 0) {
+			awacs_revision =
+				(in_le32(&awacs->codec_stat) >> 12) & 0xf;
+			if (awacs_revision == 3) {
+				mdelay(100);
+				awacs_write(0x6000);
+				mdelay(2);
+				awacs_write(awacs_reg[1] + MASK_ADDR1);
+				awacs_enable_amp(100 * 0x101);
+			}
+		}
+		if (awacs_revision >= AWACS_BURGUNDY)
+			awacs_burgundy_init();
+
+		/* Initialize beep stuff */
+		beep_dbdma_cmd = awacs_tx_cmds + (write_sq.numBufs + 1);
+		orig_mksound = kd_mksound;
+		kd_mksound = awacs_mksound;
+		beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
+		if (beep_buf == NULL)
+			printk(KERN_WARNING "dmasound: no memory for "
+			       "beep buffer\n");
+#ifdef CONFIG_PMAC_PBOOK
+		pmu_register_sleep_notifier(&awacs_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+		/* Powerbooks have odd ways of enabling inputs such as
+		   an expansion-bay CD or sound from an internal modem
+		   or a PC-card modem. */
+		if (machine_is_compatible("AAPL,3400/2400")
+			|| machine_is_compatible("AAPL,3500")) {
+			is_pbook_3400 = 1;
+			/*
+			 * Enable CD and PC-card sound inputs.
+			 * This is done by reading from address
+			 * f301a000, + 0x10 to enable the expansion-bay
+			 * CD sound input, + 0x80 to enable the PC-card
+			 * sound input.  The 0x100 enables the SCSI bus
+			 * terminator power.
+			 */
+			latch_base = (unsigned char *) ioremap
+				(0xf301a000, 0x1000);
+			in_8(latch_base + 0x190);
+		} else if (machine_is_compatible("PowerBook1,1")
+			   || machine_is_compatible("AAPL,PowerBook1998")) {
+			struct device_node* mio;
+			macio_base = 0;
+			is_pbook_G3 = 1;
+			for (mio = np->parent; mio; mio = mio->parent) {
+				if (strcmp(mio->name, "mac-io") == 0
+				    && mio->n_addrs > 0) {
+					macio_base = (unsigned char *) ioremap
+						(mio->addrs[0].address, 0x40);
+					break;
+				}
+			}
+			/* enable CD sound input */
+			if (macio_base)
+				out_8(macio_base + 0x37, 3);
+		}
+		sprintf(awacs_name, "PowerMac (AWACS rev %d) ",
+			awacs_revision);
+		return dmasound_init();
+	}
+	return -ENODEV;
+}
+
+static void __exit dmasound_awacs_cleanup(void)
+{
+	dmasound_deinit();
+}
+
+module_init(dmasound_awacs_init);
+module_exit(dmasound_awacs_cleanup);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound_core.c linux/drivers/sound/dmasound/dmasound_core.c
--- v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound_core.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/dmasound/dmasound_core.c	Mon Apr 10 22:58:59 2000
@@ -0,0 +1,1313 @@
+
+/*
+ *  linux/drivers/sound/dmasound.c
+ *
+ *
+ *  OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for
+ *  Linux/m68k
+ *  Extended to support Power Macintosh for Linux/ppc by Paul Mackerras
+ *
+ *  (c) 1995 by Michael Schlueter & Michael Marte
+ *
+ *  Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS
+ *  interface and the u-law to signed byte conversion.
+ *
+ *  Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue,
+ *  /dev/mixer, /dev/sndstat and complemented the VFS interface. He would like
+ *  to thank:
+ *    - Michael Schlueter for initial ideas and documentation on the MFP and
+ *	the DMA sound hardware.
+ *    - Therapy? for their CD 'Troublegum' which really made me rock.
+ *
+ *  /dev/sndstat is based on code by Hannu Savolainen, the author of the
+ *  VoxWare family of drivers.
+ *
+ *  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.
+ *
+ *  History:
+ *
+ *	1995/8/25	First release
+ *
+ *	1995/9/02	Roman Hodek:
+ *			  - Fixed atari_stram_alloc() call, the timer
+ *			    programming and several race conditions
+ *	1995/9/14	Roman Hodek:
+ *			  - After some discussion with Michael Schlueter,
+ *			    revised the interrupt disabling
+ *			  - Slightly speeded up U8->S8 translation by using
+ *			    long operations where possible
+ *			  - Added 4:3 interpolation for /dev/audio
+ *
+ *	1995/9/20	Torsten Scherer:
+ *			  - Fixed a bug in sq_write and changed /dev/audio
+ *			    converting to play at 12517Hz instead of 6258Hz.
+ *
+ *	1995/9/23	Torsten Scherer:
+ *			  - Changed sq_interrupt() and sq_play() to pre-program
+ *			    the DMA for another frame while there's still one
+ *			    running. This allows the IRQ response to be
+ *			    arbitrarily delayed and playing will still continue.
+ *
+ *	1995/10/14	Guenther Kelleter, Torsten Scherer:
+ *			  - Better support for Falcon audio (the Falcon doesn't
+ *			    raise an IRQ at the end of a frame, but at the
+ *			    beginning instead!). uses 'if (codec_dma)' in lots
+ *			    of places to simply switch between Falcon and TT
+ *			    code.
+ *
+ *	1995/11/06	Torsten Scherer:
+ *			  - Started introducing a hardware abstraction scheme
+ *			    (may perhaps also serve for Amigas?)
+ *			  - Can now play samples at almost all frequencies by
+ *			    means of a more generalized expand routine
+ *			  - Takes a good deal of care to cut data only at
+ *			    sample sizes
+ *			  - Buffer size is now a kernel runtime option
+ *			  - Implemented fsync() & several minor improvements
+ *			Guenther Kelleter:
+ *			  - Useful hints and bug fixes
+ *			  - Cross-checked it for Falcons
+ *
+ *	1996/3/9	Geert Uytterhoeven:
+ *			  - Support added for Amiga, A-law, 16-bit little
+ *			    endian.
+ *			  - Unification to drivers/sound/dmasound.c.
+ *
+ *	1996/4/6	Martin Mitchell:
+ *			  - Updated to 1.3 kernel.
+ *
+ *	1996/6/13       Topi Kanerva:
+ *			  - Fixed things that were broken (mainly the amiga
+ *			    14-bit routines)
+ *			  - /dev/sndstat shows now the real hardware frequency
+ *			  - The lowpass filter is disabled by default now
+ *
+ *	1996/9/25	Geert Uytterhoeven:
+ *			  - Modularization
+ *
+ *	1998/6/10	Andreas Schwab:
+ *			  - Converted to use sound_core
+ *
+ *	1999/12/28	Richard Zidlicky:
+ *			  - Added support for Q40
+ *
+ *	2000/2/27	Geert Uytterhoeven:
+ *			  - Clean up and split the code into 4 parts:
+ *			      o dmasound_core: machine-independent code
+ *			      o dmasound_atari: Atari TT and Falcon support
+ *			      o dmasound_awacs: Apple PowerMac support
+ *			      o dmasound_paula: Amiga support
+ *
+ *	2000/3/25	Geert Uytterhoeven:
+ *			  - Integration of dmasound_q40
+ *			  - Small clean ups
+ */
+
+
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/sound.h>
+#include <linux/init.h>
+#include <linux/soundcard.h>
+
+#include <asm/uaccess.h>
+
+#include "dmasound.h"
+
+
+    /*
+     *  Declarations
+     */
+
+int dmasound_catchRadius = 0;
+static unsigned int numWriteBufs = 4;
+static unsigned int writeBufSize = 32;	/* in KB! */
+#ifdef HAS_RECORD
+static unsigned int numReadBufs = 4;
+static unsigned int readBufSize = 32;	/* in KB! */
+#endif
+
+MODULE_PARM(dmasound_catchRadius, "i");
+MODULE_PARM(numWriteBufs, "i");
+MODULE_PARM(writeBufSize, "i");
+MODULE_PARM(numReadBufs, "i");
+MODULE_PARM(readBufSize, "i");
+
+#ifdef MODULE
+static int sq_unit = -1;
+static int mixer_unit = -1;
+static int state_unit = -1;
+static int irq_installed = 0;
+#endif /* MODULE */
+
+
+    /*
+     *  Conversion tables
+     */
+
+#ifdef HAS_8BIT_TABLES
+/* 8 bit mu-law */
+
+char dmasound_ulaw2dma8[] = {
+	-126,	-122,	-118,	-114,	-110,	-106,	-102,	-98,
+	-94,	-90,	-86,	-82,	-78,	-74,	-70,	-66,
+	-63,	-61,	-59,	-57,	-55,	-53,	-51,	-49,
+	-47,	-45,	-43,	-41,	-39,	-37,	-35,	-33,
+	-31,	-30,	-29,	-28,	-27,	-26,	-25,	-24,
+	-23,	-22,	-21,	-20,	-19,	-18,	-17,	-16,
+	-16,	-15,	-15,	-14,	-14,	-13,	-13,	-12,
+	-12,	-11,	-11,	-10,	-10,	-9,	-9,	-8,
+	-8,	-8,	-7,	-7,	-7,	-7,	-6,	-6,
+	-6,	-6,	-5,	-5,	-5,	-5,	-4,	-4,
+	-4,	-4,	-4,	-4,	-3,	-3,	-3,	-3,
+	-3,	-3,	-3,	-3,	-2,	-2,	-2,	-2,
+	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	0,
+	125,	121,	117,	113,	109,	105,	101,	97,
+	93,	89,	85,	81,	77,	73,	69,	65,
+	62,	60,	58,	56,	54,	52,	50,	48,
+	46,	44,	42,	40,	38,	36,	34,	32,
+	30,	29,	28,	27,	26,	25,	24,	23,
+	22,	21,	20,	19,	18,	17,	16,	15,
+	15,	14,	14,	13,	13,	12,	12,	11,
+	11,	10,	10,	9,	9,	8,	8,	7,
+	7,	7,	6,	6,	6,	6,	5,	5,
+	5,	5,	4,	4,	4,	4,	3,	3,
+	3,	3,	3,	3,	2,	2,	2,	2,
+	2,	2,	2,	2,	1,	1,	1,	1,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0
+};
+
+/* 8 bit A-law */
+
+char dmasound_alaw2dma8[] = {
+	-22,	-21,	-24,	-23,	-18,	-17,	-20,	-19,
+	-30,	-29,	-32,	-31,	-26,	-25,	-28,	-27,
+	-11,	-11,	-12,	-12,	-9,	-9,	-10,	-10,
+	-15,	-15,	-16,	-16,	-13,	-13,	-14,	-14,
+	-86,	-82,	-94,	-90,	-70,	-66,	-78,	-74,
+	-118,	-114,	-126,	-122,	-102,	-98,	-110,	-106,
+	-43,	-41,	-47,	-45,	-35,	-33,	-39,	-37,
+	-59,	-57,	-63,	-61,	-51,	-49,	-55,	-53,
+	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
+	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-6,	-6,	-6,	-6,	-5,	-5,	-5,	-5,
+	-8,	-8,	-8,	-8,	-7,	-7,	-7,	-7,
+	-3,	-3,	-3,	-3,	-3,	-3,	-3,	-3,
+	-4,	-4,	-4,	-4,	-4,	-4,	-4,	-4,
+	21,	20,	23,	22,	17,	16,	19,	18,
+	29,	28,	31,	30,	25,	24,	27,	26,
+	10,	10,	11,	11,	8,	8,	9,	9,
+	14,	14,	15,	15,	12,	12,	13,	13,
+	86,	82,	94,	90,	70,	66,	78,	74,
+	118,	114,	126,	122,	102,	98,	110,	106,
+	43,	41,	47,	45,	35,	33,	39,	37,
+	59,	57,	63,	61,	51,	49,	55,	53,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	5,	5,	5,	5,	4,	4,	4,	4,
+	7,	7,	7,	7,	6,	6,	6,	6,
+	2,	2,	2,	2,	2,	2,	2,	2,
+	3,	3,	3,	3,	3,	3,	3,	3
+};
+#endif /* HAS_8BIT_TABLES */
+
+#ifdef HAS_16BIT_TABLES
+
+/* 16 bit mu-law */
+
+short dmasound_ulaw2dma16[] = {
+	-32124,	-31100,	-30076,	-29052,	-28028,	-27004,	-25980,	-24956,
+	-23932,	-22908,	-21884,	-20860,	-19836,	-18812,	-17788,	-16764,
+	-15996,	-15484,	-14972,	-14460,	-13948,	-13436,	-12924,	-12412,
+	-11900,	-11388,	-10876,	-10364,	-9852,	-9340,	-8828,	-8316,
+	-7932,	-7676,	-7420,	-7164,	-6908,	-6652,	-6396,	-6140,
+	-5884,	-5628,	-5372,	-5116,	-4860,	-4604,	-4348,	-4092,
+	-3900,	-3772,	-3644,	-3516,	-3388,	-3260,	-3132,	-3004,
+	-2876,	-2748,	-2620,	-2492,	-2364,	-2236,	-2108,	-1980,
+	-1884,	-1820,	-1756,	-1692,	-1628,	-1564,	-1500,	-1436,
+	-1372,	-1308,	-1244,	-1180,	-1116,	-1052,	-988,	-924,
+	-876,	-844,	-812,	-780,	-748,	-716,	-684,	-652,
+	-620,	-588,	-556,	-524,	-492,	-460,	-428,	-396,
+	-372,	-356,	-340,	-324,	-308,	-292,	-276,	-260,
+	-244,	-228,	-212,	-196,	-180,	-164,	-148,	-132,
+	-120,	-112,	-104,	-96,	-88,	-80,	-72,	-64,
+	-56,	-48,	-40,	-32,	-24,	-16,	-8,	0,
+	32124,	31100,	30076,	29052,	28028,	27004,	25980,	24956,
+	23932,	22908,	21884,	20860,	19836,	18812,	17788,	16764,
+	15996,	15484,	14972,	14460,	13948,	13436,	12924,	12412,
+	11900,	11388,	10876,	10364,	9852,	9340,	8828,	8316,
+	7932,	7676,	7420,	7164,	6908,	6652,	6396,	6140,
+	5884,	5628,	5372,	5116,	4860,	4604,	4348,	4092,
+	3900,	3772,	3644,	3516,	3388,	3260,	3132,	3004,
+	2876,	2748,	2620,	2492,	2364,	2236,	2108,	1980,
+	1884,	1820,	1756,	1692,	1628,	1564,	1500,	1436,
+	1372,	1308,	1244,	1180,	1116,	1052,	988,	924,
+	876,	844,	812,	780,	748,	716,	684,	652,
+	620,	588,	556,	524,	492,	460,	428,	396,
+	372,	356,	340,	324,	308,	292,	276,	260,
+	244,	228,	212,	196,	180,	164,	148,	132,
+	120,	112,	104,	96,	88,	80,	72,	64,
+	56,	48,	40,	32,	24,	16,	8,	0,
+};
+
+/* 16 bit A-law */
+
+short dmasound_alaw2dma16[] = {
+	-5504,	-5248,	-6016,	-5760,	-4480,	-4224,	-4992,	-4736,
+	-7552,	-7296,	-8064,	-7808,	-6528,	-6272,	-7040,	-6784,
+	-2752,	-2624,	-3008,	-2880,	-2240,	-2112,	-2496,	-2368,
+	-3776,	-3648,	-4032,	-3904,	-3264,	-3136,	-3520,	-3392,
+	-22016,	-20992,	-24064,	-23040,	-17920,	-16896,	-19968,	-18944,
+	-30208,	-29184,	-32256,	-31232,	-26112,	-25088,	-28160,	-27136,
+	-11008,	-10496,	-12032,	-11520,	-8960,	-8448,	-9984,	-9472,
+	-15104,	-14592,	-16128,	-15616,	-13056,	-12544,	-14080,	-13568,
+	-344,	-328,	-376,	-360,	-280,	-264,	-312,	-296,
+	-472,	-456,	-504,	-488,	-408,	-392,	-440,	-424,
+	-88,	-72,	-120,	-104,	-24,	-8,	-56,	-40,
+	-216,	-200,	-248,	-232,	-152,	-136,	-184,	-168,
+	-1376,	-1312,	-1504,	-1440,	-1120,	-1056,	-1248,	-1184,
+	-1888,	-1824,	-2016,	-1952,	-1632,	-1568,	-1760,	-1696,
+	-688,	-656,	-752,	-720,	-560,	-528,	-624,	-592,
+	-944,	-912,	-1008,	-976,	-816,	-784,	-880,	-848,
+	5504,	5248,	6016,	5760,	4480,	4224,	4992,	4736,
+	7552,	7296,	8064,	7808,	6528,	6272,	7040,	6784,
+	2752,	2624,	3008,	2880,	2240,	2112,	2496,	2368,
+	3776,	3648,	4032,	3904,	3264,	3136,	3520,	3392,
+	22016,	20992,	24064,	23040,	17920,	16896,	19968,	18944,
+	30208,	29184,	32256,	31232,	26112,	25088,	28160,	27136,
+	11008,	10496,	12032,	11520,	8960,	8448,	9984,	9472,
+	15104,	14592,	16128,	15616,	13056,	12544,	14080,	13568,
+	344,	328,	376,	360,	280,	264,	312,	296,
+	472,	456,	504,	488,	408,	392,	440,	424,
+	88,	72,	120,	104,	24,	8,	56,	40,
+	216,	200,	248,	232,	152,	136,	184,	168,
+	1376,	1312,	1504,	1440,	1120,	1056,	1248,	1184,
+	1888,	1824,	2016,	1952,	1632,	1568,	1760,	1696,
+	688,	656,	752,	720,	560,	528,	624,	592,
+	944,	912,	1008,	976,	816,	784,	880,	848,
+};
+#endif /* HAS_16BIT_TABLES */
+
+
+#ifdef HAS_14BIT_TABLES
+
+    /*
+     *  Unused for now. Where are the MSB parts anyway??
+     */
+
+/* 14 bit mu-law (LSB) */
+
+char dmasound_ulaw2dma14l[] = {
+	33,	33,	33,	33,	33,	33,	33,	33,
+	33,	33,	33,	33,	33,	33,	33,	33,
+	33,	33,	33,	33,	33,	33,	33,	33,
+	33,	33,	33,	33,	33,	33,	33,	33,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	49,	17,	49,	17,	49,	17,	49,	17,
+	49,	17,	49,	17,	49,	17,	49,	17,
+	41,	57,	9,	25,	41,	57,	9,	25,
+	41,	57,	9,	25,	41,	57,	9,	25,
+	37,	45,	53,	61,	5,	13,	21,	29,
+	37,	45,	53,	61,	5,	13,	21,	29,
+	35,	39,	43,	47,	51,	55,	59,	63,
+	3,	7,	11,	15,	19,	23,	27,	31,
+	34,	36,	38,	40,	42,	44,	46,	48,
+	50,	52,	54,	56,	58,	60,	62,	0,
+	31,	31,	31,	31,	31,	31,	31,	31,
+	31,	31,	31,	31,	31,	31,	31,	31,
+	31,	31,	31,	31,	31,	31,	31,	31,
+	31,	31,	31,	31,	31,	31,	31,	31,
+	63,	63,	63,	63,	63,	63,	63,	63,
+	63,	63,	63,	63,	63,	63,	63,	63,
+	15,	47,	15,	47,	15,	47,	15,	47,
+	15,	47,	15,	47,	15,	47,	15,	47,
+	23,	7,	55,	39,	23,	7,	55,	39,
+	23,	7,	55,	39,	23,	7,	55,	39,
+	27,	19,	11,	3,	59,	51,	43,	35,
+	27,	19,	11,	3,	59,	51,	43,	35,
+	29,	25,	21,	17,	13,	9,	5,	1,
+	61,	57,	53,	49,	45,	41,	37,	33,
+	30,	28,	26,	24,	22,	20,	18,	16,
+	14,	12,	10,	8,	6,	4,	2,	0
+};
+
+/* 14 bit A-law (LSB) */
+
+char dmasound_alaw2dma14l[] = {
+	32,	32,	32,	32,	32,	32,	32,	32,
+	32,	32,	32,	32,	32,	32,	32,	32,
+	16,	48,	16,	48,	16,	48,	16,	48,
+	16,	48,	16,	48,	16,	48,	16,	48,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	42,	46,	34,	38,	58,	62,	50,	54,
+	10,	14,	2,	6,	26,	30,	18,	22,
+	42,	46,	34,	38,	58,	62,	50,	54,
+	10,	14,	2,	6,	26,	30,	18,	22,
+	40,	56,	8,	24,	40,	56,	8,	24,
+	40,	56,	8,	24,	40,	56,	8,	24,
+	20,	28,	4,	12,	52,	60,	36,	44,
+	20,	28,	4,	12,	52,	60,	36,	44,
+	32,	32,	32,	32,	32,	32,	32,	32,
+	32,	32,	32,	32,	32,	32,	32,	32,
+	48,	16,	48,	16,	48,	16,	48,	16,
+	48,	16,	48,	16,	48,	16,	48,	16,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	22,	18,	30,	26,	6,	2,	14,	10,
+	54,	50,	62,	58,	38,	34,	46,	42,
+	22,	18,	30,	26,	6,	2,	14,	10,
+	54,	50,	62,	58,	38,	34,	46,	42,
+	24,	8,	56,	40,	24,	8,	56,	40,
+	24,	8,	56,	40,	24,	8,	56,	40,
+	44,	36,	60,	52,	12,	4,	28,	20,
+	44,	36,	60,	52,	12,	4,	28,	20
+};
+#endif /* HAS_14BIT_TABLES */
+
+
+    /*
+     *  Common stuff
+     */
+
+static long long sound_lseek(struct file *file, long long offset, int orig)
+{
+	return -ESPIPE;
+}
+
+
+    /*
+     *  Mid level stuff
+     */
+
+struct sound_settings dmasound;
+
+static inline void sound_silence(void)
+{
+	/* update hardware settings one more */
+	dmasound.mach.init();
+
+	dmasound.mach.silence();
+}
+
+static inline void sound_init(void)
+{
+	dmasound.mach.init();
+}
+
+static inline int sound_set_format(int format)
+{
+	return dmasound.mach.setFormat(format);
+}
+
+static int sound_set_speed(int speed)
+{
+	if (speed < 0)
+		return dmasound.soft.speed;
+
+	dmasound.soft.speed = speed;
+	dmasound.mach.init();
+	if (dmasound.minDev == SND_DEV_DSP)
+		dmasound.dsp.speed = dmasound.soft.speed;
+
+	return dmasound.soft.speed;
+}
+
+static int sound_set_stereo(int stereo)
+{
+	if (stereo < 0)
+		return dmasound.soft.stereo;
+
+	stereo = !!stereo;    /* should be 0 or 1 now */
+
+	dmasound.soft.stereo = stereo;
+	if (dmasound.minDev == SND_DEV_DSP)
+		dmasound.dsp.stereo = stereo;
+	dmasound.mach.init();
+
+	return stereo;
+}
+
+static ssize_t sound_copy_translate(TRANS *trans, const u_char *userPtr,
+				    size_t userCount, u_char frame[],
+				    ssize_t *frameUsed, ssize_t frameLeft)
+{
+	ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+
+	switch (dmasound.soft.format) {
+	    case AFMT_MU_LAW:
+		ct_func = trans->ct_ulaw;
+		break;
+	    case AFMT_A_LAW:
+		ct_func = trans->ct_alaw;
+		break;
+	    case AFMT_S8:
+		ct_func = trans->ct_s8;
+		break;
+	    case AFMT_U8:
+		ct_func = trans->ct_u8;
+		break;
+	    case AFMT_S16_BE:
+		ct_func = trans->ct_s16be;
+		break;
+	    case AFMT_U16_BE:
+		ct_func = trans->ct_u16be;
+		break;
+	    case AFMT_S16_LE:
+		ct_func = trans->ct_s16le;
+		break;
+	    case AFMT_U16_LE:
+		ct_func = trans->ct_u16le;
+		break;
+	    default:
+		return 0;
+	}
+	return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
+}
+
+
+    /*
+     *  /dev/mixer abstraction
+     */
+
+static struct {
+    int busy;
+    int modify_counter;
+} mixer;
+
+static int mixer_open(struct inode *inode, struct file *file)
+{
+	MOD_INC_USE_COUNT;
+	dmasound.mach.open();
+	mixer.busy = 1;
+	return 0;
+}
+
+static int mixer_release(struct inode *inode, struct file *file)
+{
+	mixer.busy = 0;
+	dmasound.mach.release();
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg)
+{
+	if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+	    mixer.modify_counter++;
+	switch (cmd) {
+	    case OSS_GETVERSION:
+		return IOCTL_OUT(arg, SOUND_VERSION);
+	    case SOUND_MIXER_INFO:
+		{
+		    mixer_info info;
+		    strncpy(info.id, dmasound.mach.name2, sizeof(info.id));
+		    strncpy(info.name, dmasound.mach.name2, sizeof(info.name));
+		    info.name[sizeof(info.name)-1] = 0;
+		    info.modify_counter = mixer.modify_counter;
+		    copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
+		    return 0;
+		}
+	}
+	if (dmasound.mach.mixer_ioctl)
+	    return dmasound.mach.mixer_ioctl(cmd, arg);
+	return -EINVAL;
+}
+
+static struct file_operations mixer_fops =
+{
+	llseek:		sound_lseek,
+	ioctl:		mixer_ioctl,
+	open:		mixer_open,
+	release:	mixer_release,
+};
+
+static void __init mixer_init(void)
+{
+#ifndef MODULE
+	int mixer_unit;
+#endif
+	mixer_unit = register_sound_mixer(&mixer_fops, -1);
+	if (mixer_unit < 0)
+		return;
+
+	mixer.busy = 0;
+	dmasound.treble = 0;
+	dmasound.bass = 0;
+	if (dmasound.mach.mixer_init)
+	    dmasound.mach.mixer_init();
+}
+
+
+    /*
+     *  Sound queue stuff, the heart of the driver
+     */
+
+struct sound_queue dmasound_write_sq;
+#ifdef HAS_RECORD
+struct sound_queue dmasound_read_sq;
+#endif
+
+static int sq_allocate_buffers(struct sound_queue *sq, int num, int size)
+{
+	int i;
+
+	if (sq->buffers)
+		return 0;
+	sq->numBufs = num;
+	sq->bufSize = size;
+	sq->buffers = kmalloc (num * sizeof(char *), GFP_KERNEL);
+	if (!sq->buffers)
+		return -ENOMEM;
+	for (i = 0; i < num; i++) {
+		sq->buffers[i] = dmasound.mach.dma_alloc(size, GFP_KERNEL);
+		if (!sq->buffers[i]) {
+			while (i--)
+				dmasound.mach.dma_free(sq->buffers[i], size);
+			kfree(sq->buffers);
+			sq->buffers = 0;
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+static void sq_release_buffers(struct sound_queue *sq)
+{
+	int i;
+
+	if (sq->buffers) {
+		if (sq != &write_sq && dmasound.mach.abort_read)
+			dmasound.mach.abort_read();
+		for (i = 0; i < sq->numBufs; i++)
+			dmasound.mach.dma_free(sq->buffers[i], sq->bufSize);
+		kfree(sq->buffers);
+		sq->buffers = NULL;
+	}
+}
+
+static void sq_setup(struct sound_queue *sq, int max_count, int max_active,
+		     int block_size)
+{
+	void (*setup_func)(void);
+
+	sq->max_count = max_count;
+	sq->max_active = max_active;
+	sq->block_size = block_size;
+
+	sq->front = sq->count = sq->rear_size = 0;
+	sq->syncing = 0;
+	sq->active = 0;
+
+	if (sq == &write_sq) {
+	    sq->rear = -1;
+	    setup_func = dmasound.mach.write_sq_setup;
+	} else {
+	    sq->rear = 0;
+	    setup_func = dmasound.mach.read_sq_setup;
+	}
+	if (setup_func)
+	    setup_func();
+}
+
+static inline void sq_play(void)
+{
+	dmasound.mach.play();
+}
+
+static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
+			loff_t *ppos)
+{
+	ssize_t uWritten = 0;
+	u_char *dest;
+	ssize_t uUsed, bUsed, bLeft;
+
+	/* ++TeSche: Is something like this necessary?
+	 * Hey, that's an honest question! Or does any other part of the
+	 * filesystem already checks this situation? I really don't know.
+	 */
+	if (uLeft == 0)
+		return 0;
+
+	/* The interrupt doesn't start to play the last, incomplete frame.
+	 * Thus we can append to it without disabling the interrupts! (Note
+	 * also that write_sq.rear isn't affected by the interrupt.)
+	 */
+
+	if (write_sq.count > 0 &&
+	    (bLeft = write_sq.block_size-write_sq.rear_size) > 0) {
+		dest = write_sq.buffers[write_sq.rear];
+		bUsed = write_sq.rear_size;
+		uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,
+					     dest, &bUsed, bLeft);
+		if (uUsed <= 0)
+			return uUsed;
+		src += uUsed;
+		uWritten += uUsed;
+		uLeft -= uUsed;
+		write_sq.rear_size = bUsed;
+	}
+
+	do {
+		while (write_sq.count == write_sq.max_active) {
+			sq_play();
+			if (write_sq.open_mode & O_NONBLOCK)
+				return uWritten > 0 ? uWritten : -EAGAIN;
+			SLEEP(write_sq.action_queue);
+			if (signal_pending(current))
+				return uWritten > 0 ? uWritten : -EINTR;
+		}
+
+		/* Here, we can avoid disabling the interrupt by first
+		 * copying and translating the data, and then updating
+		 * the write_sq variables. Until this is done, the interrupt
+		 * won't see the new frame and we can work on it
+		 * undisturbed.
+		 */
+
+		dest = write_sq.buffers[(write_sq.rear+1) % write_sq.max_count];
+		bUsed = 0;
+		bLeft = write_sq.block_size;
+		uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,
+					     dest, &bUsed, bLeft);
+		if (uUsed <= 0)
+			break;
+		src += uUsed;
+		uWritten += uUsed;
+		uLeft -= uUsed;
+		if (bUsed) {
+			write_sq.rear = (write_sq.rear+1) % write_sq.max_count;
+			write_sq.rear_size = bUsed;
+			write_sq.count++;
+		}
+	} while (bUsed);   /* uUsed may have been 0 */
+
+	sq_play();
+
+	return uUsed < 0? uUsed: uWritten;
+}
+
+#ifdef HAS_RECORD
+    /*
+     *  Here is how the values are used for reading.
+     *  The value 'active' simply indicates the DMA is running.  This is done
+     *  so the driver semantics are DMA starts when the first read is posted.
+     *  The value 'front' indicates the buffer we should next send to the user.
+     *  The value 'rear' indicates the buffer the DMA is currently filling.
+     *  When 'front' == 'rear' the buffer "ring" is empty (we always have an
+     *  empty available).  The 'rear_size' is used to track partial offsets
+     *  into the current buffer.  Right now, I just keep the DMA running.  If
+     *  the reader can't keep up, the interrupt tosses the oldest buffer.  We
+     *  could also shut down the DMA in this case.
+     */
+
+static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
+		       loff_t *ppos)
+{
+
+	ssize_t	uRead, bLeft, bUsed, uUsed;
+
+	if (uLeft == 0)
+		return 0;
+
+	if (!read_sq.active && dmasound.mach.record)
+		dmasound.mach.record();	/* Kick off the record process. */
+
+	uRead = 0;
+
+	/* Move what the user requests, depending upon other options.
+	*/
+	while (uLeft > 0) {
+
+		/* When front == rear, the DMA is not done yet.
+		*/
+		while (read_sq.front == read_sq.rear) {
+			if (read_sq.open_mode & O_NONBLOCK) {
+			       return uRead > 0 ? uRead : -EAGAIN;
+			}
+			SLEEP(read_sq.action_queue);
+			if (signal_pending(current))
+				return uRead > 0 ? uRead : -EINTR;
+		}
+
+		/* The amount we move is either what is left in the
+		 * current buffer or what the user wants.
+		 */
+		bLeft = read_sq.block_size - read_sq.rear_size;
+		bUsed = read_sq.rear_size;
+		uUsed = sound_copy_translate(dmasound.trans_read, dst, uLeft,
+					     read_sq.buffers[read_sq.front],
+					     &bUsed, bLeft);
+		if (uUsed <= 0)
+			return uUsed;
+		dst += uUsed;
+		uRead += uUsed;
+		uLeft -= uUsed;
+		read_sq.rear_size += bUsed;
+		if (read_sq.rear_size >= read_sq.block_size) {
+			read_sq.rear_size = 0;
+			read_sq.front++;
+			if (read_sq.front >= read_sq.max_active)
+				read_sq.front = 0;
+		}
+	}
+	return uRead;
+}
+#endif /* HAS_RECORD */
+
+static inline void sq_init_waitqueue(struct sound_queue *sq)
+{
+	init_waitqueue_head(&sq->action_queue);
+	init_waitqueue_head(&sq->open_queue);
+	init_waitqueue_head(&sq->sync_queue);
+	sq->busy = 0;
+}
+
+static inline void sq_wake_up(struct sound_queue *sq, struct file *file,
+			      mode_t mode)
+{
+	if (file->f_mode & mode) {
+		sq->busy = 0;
+		WAKE_UP(sq->open_queue);
+	}
+}
+
+static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode,
+		    int numbufs, int bufsize)
+{
+	int rc = 0;
+
+	if (file->f_mode & mode) {
+		if (sq->busy) {
+			rc = -EBUSY;
+			if (file->f_flags & O_NONBLOCK)
+				return rc;
+			rc = -EINTR;
+			while (sq->busy) {
+				SLEEP(sq->open_queue);
+				if (signal_pending(current))
+					return rc;
+			}
+			rc = 0;
+		}
+		sq->busy = 1; /* Let's play spot-the-race-condition */
+
+		if (sq_allocate_buffers(sq, numbufs, bufsize)) {
+			sq_wake_up(sq, file, mode);
+			return rc;
+		}
+
+		sq_setup(sq, numbufs, numbufs, bufsize);
+		sq->open_mode = file->f_mode;
+	}
+	return rc;
+}
+
+#define write_sq_init_waitqueue()	sq_init_waitqueue(&write_sq)
+#define write_sq_wake_up(file)		sq_wake_up(&write_sq, file, FMODE_WRITE)
+#define write_sq_release_buffers()	sq_release_buffers(&write_sq)
+#define write_sq_open(file)	\
+	sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize << 10)
+
+#ifdef HAS_RECORD
+#define read_sq_init_waitqueue()	sq_init_waitqueue(&read_sq)
+#define read_sq_wake_up(file)		sq_wake_up(&read_sq, file, FMODE_READ)
+#define read_sq_release_buffers()	sq_release_buffers(&read_sq)
+#define read_sq_open(file)	\
+	sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize << 10)
+#else /* !HAS_RECORD */
+#define read_sq_init_waitqueue()	do {} while (0)
+#define read_sq_wake_up(file)		do {} while (0)
+#define read_sq_release_buffers()	do {} while (0)
+#define read_sq_open(file)		(0)
+#endif /* !HAS_RECORD */
+
+static int sq_open(struct inode *inode, struct file *file)
+{
+	int rc;
+
+	MOD_INC_USE_COUNT;
+	dmasound.mach.open();
+	if ((rc = write_sq_open(file)) || (rc = read_sq_open(file))) {
+		dmasound.mach.release();
+		MOD_DEC_USE_COUNT;
+		return rc;
+	}
+
+	if (dmasound.mach.sq_open)
+	    dmasound.mach.sq_open();
+	dmasound.minDev = MINOR(inode->i_rdev) & 0x0f;
+	dmasound.soft = dmasound.dsp;
+	dmasound.hard = dmasound.dsp;
+	sound_init();
+	if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
+		sound_set_speed(8000);
+		sound_set_stereo(0);
+		sound_set_format(AFMT_MU_LAW);
+	}
+
+#if 0
+	if (file->f_mode == FMODE_READ && dmasound.mach.record) {
+		/* Start dma'ing straight away */
+		dmasound.mach.record();
+	}
+#endif
+
+	return 0;
+}
+
+static void sq_reset(void)
+{
+	sound_silence();
+	write_sq.active = 0;
+	write_sq.count = 0;
+	write_sq.front = (write_sq.rear+1) % write_sq.max_count;
+}
+
+static int sq_fsync(struct file *filp, struct dentry *dentry)
+{
+	int rc = 0;
+
+	write_sq.syncing = 1;
+	sq_play();	/* there may be an incomplete frame waiting */
+
+	while (write_sq.active) {
+		SLEEP(write_sq.sync_queue);
+		if (signal_pending(current)) {
+			/* While waiting for audio output to drain, an
+			 * interrupt occurred.  Stop audio output immediately
+			 * and clear the queue. */
+			sq_reset();
+			rc = -EINTR;
+			break;
+		}
+	}
+
+	write_sq.syncing = 0;
+	return rc;
+}
+
+static int sq_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	if (write_sq.busy)
+		rc = sq_fsync(file, file->f_dentry);
+	dmasound.soft = dmasound.dsp;
+	dmasound.hard = dmasound.dsp;
+	sound_silence();
+
+	write_sq_release_buffers();
+	read_sq_release_buffers();
+	dmasound.mach.release();
+	MOD_DEC_USE_COUNT;
+
+	/* There is probably a DOS atack here. They change the mode flag. */
+	/* XXX add check here */
+	read_sq_wake_up(file);
+	write_sq_wake_up(file);
+
+	/* Wake up a process waiting for the queue being released.
+	 * Note: There may be several processes waiting for a call
+	 * to open() returning. */
+
+	return rc;
+}
+
+static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		    u_long arg)
+{
+	u_long fmt;
+	int data;
+	int size, nbufs;
+	audio_buf_info info;
+
+	switch (cmd) {
+	case SNDCTL_DSP_RESET:
+		sq_reset();
+		return 0;
+	case SNDCTL_DSP_POST:
+	case SNDCTL_DSP_SYNC:
+		return sq_fsync(file, file->f_dentry);
+
+		/* ++TeSche: before changing any of these it's
+		 * probably wise to wait until sound playing has
+		 * settled down. */
+	case SNDCTL_DSP_SPEED:
+		sq_fsync(file, file->f_dentry);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, sound_set_speed(data));
+	case SNDCTL_DSP_STEREO:
+		sq_fsync(file, file->f_dentry);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, sound_set_stereo(data));
+	case SOUND_PCM_WRITE_CHANNELS:
+		sq_fsync(file, file->f_dentry);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
+	case SNDCTL_DSP_SETFMT:
+		sq_fsync(file, file->f_dentry);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, sound_set_format(data));
+	case SNDCTL_DSP_GETFMTS:
+		fmt = 0;
+		if (dmasound.trans_write) {
+			if (dmasound.trans_write->ct_ulaw)
+				fmt |= AFMT_MU_LAW;
+			if (dmasound.trans_write->ct_alaw)
+				fmt |= AFMT_A_LAW;
+			if (dmasound.trans_write->ct_s8)
+				fmt |= AFMT_S8;
+			if (dmasound.trans_write->ct_u8)
+				fmt |= AFMT_U8;
+			if (dmasound.trans_write->ct_s16be)
+				fmt |= AFMT_S16_BE;
+			if (dmasound.trans_write->ct_u16be)
+				fmt |= AFMT_U16_BE;
+			if (dmasound.trans_write->ct_s16le)
+				fmt |= AFMT_S16_LE;
+			if (dmasound.trans_write->ct_u16le)
+				fmt |= AFMT_U16_LE;
+		}
+		return IOCTL_OUT(arg, fmt);
+	case SNDCTL_DSP_GETBLKSIZE:
+		size = write_sq.block_size
+			* dmasound.soft.size * (dmasound.soft.stereo + 1)
+			/ (dmasound.hard.size * (dmasound.hard.stereo + 1));
+		return IOCTL_OUT(arg, size);
+	case SNDCTL_DSP_SUBDIVIDE:
+		break;
+	case SNDCTL_DSP_SETFRAGMENT:
+		if (write_sq.count || write_sq.active || write_sq.syncing)
+			return -EINVAL;
+		IOCTL_IN(arg, size);
+		nbufs = size >> 16;
+		if (nbufs < 2 || nbufs > write_sq.numBufs)
+			nbufs = write_sq.numBufs;
+		size &= 0xffff;
+		if (size >= 8 && size <= 29) {
+			size = 1 << size;
+			size *= dmasound.hard.size * (dmasound.hard.stereo + 1);
+			size /= dmasound.soft.size * (dmasound.soft.stereo + 1);
+			if (size > write_sq.bufSize)
+				size = write_sq.bufSize;
+		} else
+			size = write_sq.bufSize;
+		sq_setup(&write_sq, write_sq.numBufs, nbufs, size);
+		return 0;
+	case SNDCTL_DSP_GETOSPACE:
+		info.fragments = write_sq.max_active - write_sq.count;
+		info.fragstotal = write_sq.max_active;
+		info.fragsize = write_sq.block_size;
+		info.bytes = info.fragments * info.fragsize;
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+
+	default:
+		return mixer_ioctl(inode, file, cmd, arg);
+	}
+	return -EINVAL;
+}
+
+static struct file_operations sq_fops =
+{
+	llseek:		sound_lseek,
+	write:		sq_write,
+	ioctl:		sq_ioctl,
+	open:		sq_open,
+	release:	sq_release,
+#ifdef HAS_RECORD
+	read:		sq_read,
+#endif
+};
+
+static void __init sq_init(void)
+{
+#ifndef MODULE
+	int sq_unit;
+#endif
+	sq_unit = register_sound_dsp(&sq_fops, -1);
+	if (sq_unit < 0)
+		return;
+
+	write_sq_init_waitqueue();
+	read_sq_init_waitqueue();
+
+	/* whatever you like as startup mode for /dev/dsp,
+	 * (/dev/audio hasn't got a startup mode). note that
+	 * once changed a new open() will *not* restore these!
+	 */
+	dmasound.dsp.format = AFMT_U8;
+	dmasound.dsp.stereo = 0;
+	dmasound.dsp.size = 8;
+
+	/* set minimum rate possible without expanding */
+	dmasound.dsp.speed = dmasound.mach.min_dsp_speed;
+
+	/* before the first open to /dev/dsp this wouldn't be set */
+	dmasound.soft = dmasound.dsp;
+	dmasound.hard = dmasound.dsp;
+
+	sound_silence();
+}
+
+
+    /*
+     *  /dev/sndstat
+     */
+
+static struct {
+    int busy;
+    char buf[512];	/* state.buf should not overflow! */
+    int len, ptr;
+} state;
+
+static int state_open(struct inode *inode, struct file *file)
+{
+	char *buffer = state.buf;
+	int len = 0;
+
+	if (state.busy)
+		return -EBUSY;
+
+	MOD_INC_USE_COUNT;
+	dmasound.mach.open();
+	state.ptr = 0;
+	state.busy = 1;
+
+	len += sprintf(buffer+len, "%sDMA sound driver:\n", dmasound.mach.name);
+
+	len += sprintf(buffer+len, "\tsound.format = 0x%x",
+		       dmasound.soft.format);
+	switch (dmasound.soft.format) {
+	    case AFMT_MU_LAW:
+		len += sprintf(buffer+len, " (mu-law)");
+		break;
+	    case AFMT_A_LAW:
+		len += sprintf(buffer+len, " (A-law)");
+		break;
+	    case AFMT_U8:
+		len += sprintf(buffer+len, " (unsigned 8 bit)");
+		break;
+	    case AFMT_S8:
+		len += sprintf(buffer+len, " (signed 8 bit)");
+		break;
+	    case AFMT_S16_BE:
+		len += sprintf(buffer+len, " (signed 16 bit big)");
+		break;
+	    case AFMT_U16_BE:
+		len += sprintf(buffer+len, " (unsigned 16 bit big)");
+		break;
+	    case AFMT_S16_LE:
+		len += sprintf(buffer+len, " (signed 16 bit little)");
+		break;
+	    case AFMT_U16_LE:
+		len += sprintf(buffer+len, " (unsigned 16 bit little)");
+		break;
+	}
+	len += sprintf(buffer+len, "\n");
+	len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
+		       dmasound.soft.speed, dmasound.hard.speed);
+	len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+		       dmasound.soft.stereo,
+		       dmasound.soft.stereo ? "stereo" : "mono");
+	if (dmasound.mach.state_info)
+	    len += dmasound.mach.state_info(buffer);
+	len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
+		       " sq.max_active = %d\n",
+		       write_sq.block_size, write_sq.max_count,
+		       write_sq.max_active);
+	len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n",
+		       write_sq.count, write_sq.rear_size);
+	len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
+		       write_sq.active, write_sq.syncing);
+	state.len = len;
+	return 0;
+}
+
+static int state_release(struct inode *inode, struct file *file)
+{
+	state.busy = 0;
+	dmasound.mach.release();
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static ssize_t state_read(struct file *file, char *buf, size_t count,
+			  loff_t *ppos)
+{
+	int n = state.len - state.ptr;
+	if (n > count)
+		n = count;
+	if (n <= 0)
+		return 0;
+	if (copy_to_user(buf, &state.buf[state.ptr], n))
+		return -EFAULT;
+	state.ptr += n;
+	return n;
+}
+
+static struct file_operations state_fops =
+{
+	llseek:		sound_lseek,
+	read:		state_read,
+	open:		state_open,
+	release:	state_release,
+};
+
+static void __init state_init(void)
+{
+#ifndef MODULE
+	int state_unit;
+#endif
+	state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
+	if (state_unit < 0)
+		return;
+	state.busy = 0;
+}
+
+
+    /*
+     *  Config & Setup
+     *
+     *  This function is called by _one_ chipset-specific driver
+     */
+
+int __init dmasound_init(void)
+{
+	if (irq_installed)
+		return -EBUSY;
+
+	/* Set up sound queue, /dev/audio and /dev/dsp. */
+
+	/* Set default settings. */
+	sq_init();
+
+	/* Set up /dev/sndstat. */
+	state_init();
+
+	/* Set up /dev/mixer. */
+	mixer_init();
+
+	if (!dmasound.mach.irqinit()) {
+		printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
+		return -ENODEV;
+	}
+#ifdef MODULE
+	irq_installed = 1;
+#endif
+
+	printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
+	       numWriteBufs, writeBufSize);
+
+	return 0;
+}
+
+#ifdef MODULE
+
+void dmasound_deinit(void)
+{
+	if (irq_installed) {
+		sound_silence();
+		dmasound.mach.irqcleanup();
+	}
+
+	write_sq_release_buffers();
+	read_sq_release_buffers();
+
+	if (mixer_unit >= 0)
+		unregister_sound_mixer(mixer_unit);
+	if (state_unit >= 0)
+		unregister_sound_special(state_unit);
+	if (sq_unit >= 0)
+		unregister_sound_dsp(sq_unit);
+}
+
+#else /* !MODULE */
+
+static int __init dmasound_setup(char *str)
+{
+	int ints[6];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	/* check the bootstrap parameter for "dmasound=" */
+
+	switch (ints[0]) {
+	case 3:
+		if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
+			printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+		else
+			catchRadius = ints[3];
+		/* fall through */
+	case 2:
+		if (ints[1] < MIN_BUFFERS)
+			printk("dmasound_setup: illegal number of buffers, using default = %d\n", numWriteBufs);
+		else
+			numWriteBufs = ints[1];
+		if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
+			printk("dmasound_setup: illegal buffer size, using default = %dK\n", writeBufSize);
+		else
+			writeBufSize = ints[2];
+		break;
+	case 0:
+		break;
+	default:
+		printk("dmasound_setup: illegal number of arguments\n");
+		return 0;
+	}
+	return 1;
+}
+
+__setup("dmasound=", dmasound_setup);
+
+#endif /* !MODULE */
+
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(dmasound);
+EXPORT_SYMBOL(dmasound_init);
+#ifdef MODULE
+EXPORT_SYMBOL(dmasound_deinit);
+#endif
+EXPORT_SYMBOL(dmasound_write_sq);
+#ifdef HAS_RECORD
+EXPORT_SYMBOL(dmasound_read_sq);
+#endif
+EXPORT_SYMBOL(dmasound_catchRadius);
+#ifdef HAS_8BIT_TABLES
+EXPORT_SYMBOL(dmasound_ulaw2dma8);
+EXPORT_SYMBOL(dmasound_alaw2dma8);
+#endif
+#ifdef HAS_16BIT_TABLES
+EXPORT_SYMBOL(dmasound_ulaw2dma16);
+EXPORT_SYMBOL(dmasound_alaw2dma16);
+#endif
+#ifdef HAS_14BIT_TABLES
+EXPORT_SYMBOL(dmasound_ulaw2dma14l);
+EXPORT_SYMBOL(dmasound_ulaw2dma14h);
+EXPORT_SYMBOL(dmasound_alaw2dma14l);
+EXPORT_SYMBOL(dmasound_alaw2dma14h);
+#endif
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound_paula.c linux/drivers/sound/dmasound/dmasound_paula.c
--- v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound_paula.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/dmasound/dmasound_paula.c	Mon Apr 10 22:58:59 2000
@@ -0,0 +1,690 @@
+
+/*
+ *  linux/drivers/sound/dmasound_paula.c
+ *
+ *  Amiga DMA Sound Driver
+ *
+ *  See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/soundcard.h>
+
+#include <asm/uaccess.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+#include "dmasound.h"
+
+
+   /*
+    *	The minimum period for audio depends on htotal (for OCS/ECS/AGA)
+    *	(Imported from arch/m68k/amiga/amisound.c)
+    *
+    *	FIXME: if amifb is not used, there should be a method to change htotal
+    */
+
+extern volatile u_short amiga_audio_min_period;
+
+
+   /*
+    *	amiga_mksound() should be able to restore the period after beeping
+    *	(Imported from arch/m68k/amiga/amisound.c)
+    */
+
+extern u_short amiga_audio_period;
+
+
+   /*
+    *	Audio DMA masks
+    */
+
+#define AMI_AUDIO_OFF	(DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
+#define AMI_AUDIO_8	(DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
+#define AMI_AUDIO_14	(AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
+
+
+    /*
+     *  Helper pointers for 16(14)-bit sound
+     */
+
+static int write_sq_block_size_half, write_sq_block_size_quarter;
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void AmiOpen(void);
+static void AmiRelease(void);
+static void *AmiAlloc(unsigned int size, int flags);
+static void AmiFree(void *obj, unsigned int size);
+static int AmiIrqInit(void);
+#ifdef MODULE
+static void AmiIrqCleanUp(void);
+#endif
+static void AmiSilence(void);
+static void AmiInit(void);
+static int AmiSetFormat(int format);
+static int AmiSetVolume(int volume);
+static int AmiSetTreble(int treble);
+static void AmiPlayNextFrame(int index);
+static void AmiPlay(void);
+static void AmiInterrupt(int irq, void *dummy, struct pt_regs *fp);
+
+
+/*** Mid level stuff *********************************************************/
+
+static void AmiMixerInit(void);
+static int AmiMixerIoctl(u_int cmd, u_long arg);
+static void AmiWriteSqSetup(void);
+static int AmiStateInfo(char *buffer);
+
+
+/*** Translations ************************************************************/
+
+/* ++TeSche: radically changed for new expanding purposes...
+ *
+ * These two routines now deal with copying/expanding/translating the samples
+ * from user space into our buffer at the right frequency. They take care about
+ * how much data there's actually to read, how much buffer space there is and
+ * to convert samples into the right frequency/encoding. They will only work on
+ * complete samples so it may happen they leave some bytes in the input stream
+ * if the user didn't write a multiple of the current sample size. They both
+ * return the number of bytes they've used from both streams so you may detect
+ * such a situation. Luckily all programs should be able to cope with that.
+ *
+ * I think I've optimized anything as far as one can do in plain C, all
+ * variables should fit in registers and the loops are really short. There's
+ * one loop for every possible situation. Writing a more generalized and thus
+ * parameterized loop would only produce slower code. Feel free to optimize
+ * this in assembler if you like. :)
+ *
+ * I think these routines belong here because they're not yet really hardware
+ * independent, especially the fact that the Falcon can play 16bit samples
+ * only in stereo is hardcoded in both of them!
+ *
+ * ++geert: split in even more functions (one per format)
+ */
+
+
+    /*
+     *  Native format
+     */
+
+static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
+{
+	ssize_t count, used;
+
+	if (!dmasound.soft.stereo) {
+		void *p = &frame[*frameUsed];
+		count = min(userCount, frameLeft) & ~1;
+		used = count;
+		if (copy_from_user(p, userPtr, count))
+			return -EFAULT;
+	} else {
+		u_char *left = &frame[*frameUsed>>1];
+		u_char *right = left+write_sq_block_size_half;
+		count = min(userCount, frameLeft)>>1 & ~1;
+		used = count*2;
+		while (count > 0) {
+			if (get_user(*left++, userPtr++)
+			    || get_user(*right++, userPtr++))
+				return -EFAULT;
+			count--;
+		}
+	}
+	*frameUsed += used;
+	return used;
+}
+
+
+    /*
+     *  Copy and convert 8 bit data
+     */
+
+#define GENERATE_AMI_CT8(funcname, convsample)				\
+static ssize_t funcname(const u_char *userPtr, size_t userCount,	\
+			u_char frame[], ssize_t *frameUsed,		\
+			ssize_t frameLeft)				\
+{									\
+	ssize_t count, used;						\
+									\
+	if (!dmasound.soft.stereo) {					\
+		u_char *p = &frame[*frameUsed];				\
+		count = min(userCount, frameLeft) & ~1;			\
+		used = count;						\
+		while (count > 0) {					\
+			u_char data;					\
+			if (get_user(data, userPtr++))			\
+				return -EFAULT;				\
+			*p++ = convsample(data);			\
+			count--;					\
+		}							\
+	} else {							\
+		u_char *left = &frame[*frameUsed>>1];			\
+		u_char *right = left+write_sq_block_size_half;		\
+		count = min(userCount, frameLeft)>>1 & ~1;		\
+		used = count*2;						\
+		while (count > 0) {					\
+			u_char data;					\
+			if (get_user(data, userPtr++))			\
+				return -EFAULT;				\
+			*left++ = convsample(data);			\
+			if (get_user(data, userPtr++))			\
+				return -EFAULT;				\
+			*right++ = convsample(data);			\
+			count--;					\
+		}							\
+	}								\
+	*frameUsed += used;						\
+	return used;							\
+}
+
+#define AMI_CT_ULAW(x)	(dmasound_ulaw2dma8[(x)])
+#define AMI_CT_ALAW(x)	(dmasound_alaw2dma8[(x)])
+#define AMI_CT_U8(x)	((x) ^ 0x80)
+
+GENERATE_AMI_CT8(ami_ct_ulaw, AMI_CT_ULAW)
+GENERATE_AMI_CT8(ami_ct_alaw, AMI_CT_ALAW)
+GENERATE_AMI_CT8(ami_ct_u8, AMI_CT_U8)
+
+
+    /*
+     *  Copy and convert 16 bit data
+     */
+
+#define GENERATE_AMI_CT_16(funcname, convsample)			\
+static ssize_t funcname(const u_char *userPtr, size_t userCount,	\
+			u_char frame[], ssize_t *frameUsed,		\
+			ssize_t frameLeft)				\
+{									\
+	ssize_t count, used;						\
+	u_short data;							\
+									\
+	if (!dmasound.soft.stereo) {					\
+		u_char *high = &frame[*frameUsed>>1];			\
+		u_char *low = high+write_sq_block_size_half;		\
+		count = min(userCount, frameLeft)>>1 & ~1;		\
+		used = count*2;						\
+		while (count > 0) {					\
+			if (get_user(data, ((u_short *)userPtr)++))	\
+				return -EFAULT;				\
+			data = convsample(data);			\
+			*high++ = data>>8;				\
+			*low++ = (data>>2) & 0x3f;			\
+			count--;					\
+		}							\
+	} else {							\
+		u_char *lefth = &frame[*frameUsed>>2];			\
+		u_char *leftl = lefth+write_sq_block_size_quarter;	\
+		u_char *righth = lefth+write_sq_block_size_half;	\
+		u_char *rightl = righth+write_sq_block_size_quarter;	\
+		count = min(userCount, frameLeft)>>2 & ~1;		\
+		used = count*4;						\
+		while (count > 0) {					\
+			if (get_user(data, ((u_short *)userPtr)++))	\
+				return -EFAULT;				\
+			data = convsample(data);			\
+			*lefth++ = data>>8;				\
+			*leftl++ = (data>>2) & 0x3f;			\
+			if (get_user(data, ((u_short *)userPtr)++))	\
+				return -EFAULT;				\
+			data = convsample(data);			\
+			*righth++ = data>>8;				\
+			*rightl++ = (data>>2) & 0x3f;			\
+			count--;					\
+		}							\
+	}								\
+	*frameUsed += used;						\
+	return used;							\
+}
+
+#define AMI_CT_S16BE(x)	(x)
+#define AMI_CT_U16BE(x)	((x) ^ 0x8000)
+#define AMI_CT_S16LE(x)	(le2be16((x)))
+#define AMI_CT_U16LE(x)	(le2be16((x)) ^ 0x8000)
+
+GENERATE_AMI_CT_16(ami_ct_s16be, AMI_CT_S16BE)
+GENERATE_AMI_CT_16(ami_ct_u16be, AMI_CT_U16BE)
+GENERATE_AMI_CT_16(ami_ct_s16le, AMI_CT_S16LE)
+GENERATE_AMI_CT_16(ami_ct_u16le, AMI_CT_U16LE)
+
+
+static TRANS transAmiga = {
+	ct_ulaw:	ami_ct_ulaw,
+	ct_alaw:	ami_ct_alaw,
+	ct_s8:		ami_ct_s8,
+	ct_u8:		ami_ct_u8,
+	ct_s16be:	ami_ct_s16be,
+	ct_u16be:	ami_ct_u16be,
+	ct_s16le:	ami_ct_s16le,
+	ct_u16le:	ami_ct_u16le,
+};
+
+/*** Low level stuff *********************************************************/
+
+
+static void AmiOpen(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void AmiRelease(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static inline void StopDMA(void)
+{
+	custom.aud[0].audvol = custom.aud[1].audvol = 0;
+	custom.aud[2].audvol = custom.aud[3].audvol = 0;
+	custom.dmacon = AMI_AUDIO_OFF;
+}
+
+static void *AmiAlloc(unsigned int size, int flags)
+{
+	return amiga_chip_alloc((long)size, "dmasound [Paula]");
+}
+
+static void AmiFree(void *obj, unsigned int size)
+{
+	amiga_chip_free (obj);
+}
+
+static int __init AmiIrqInit(void)
+{
+	/* turn off DMA for audio channels */
+	StopDMA();
+
+	/* Register interrupt handler. */
+	if (request_irq(IRQ_AMIGA_AUD0, AmiInterrupt, 0, "DMA sound",
+			AmiInterrupt))
+		return 0;
+	return 1;
+}
+
+#ifdef MODULE
+static void AmiIrqCleanUp(void)
+{
+	/* turn off DMA for audio channels */
+	StopDMA();
+	/* release the interrupt */
+	free_irq(IRQ_AMIGA_AUD0, AmiInterrupt);
+}
+#endif /* MODULE */
+
+static void AmiSilence(void)
+{
+	/* turn off DMA for audio channels */
+	StopDMA();
+}
+
+
+static void AmiInit(void)
+{
+	int period, i;
+
+	AmiSilence();
+
+	if (dmasound.soft.speed)
+		period = amiga_colorclock/dmasound.soft.speed-1;
+	else
+		period = amiga_audio_min_period;
+	dmasound.hard = dmasound.soft;
+	dmasound.trans_write = &transAmiga;
+
+	if (period < amiga_audio_min_period) {
+		/* we would need to squeeze the sound, but we won't do that */
+		period = amiga_audio_min_period;
+	} else if (period > 65535) {
+		period = 65535;
+	}
+	dmasound.hard.speed = amiga_colorclock/(period+1);
+
+	for (i = 0; i < 4; i++)
+		custom.aud[i].audper = period;
+	amiga_audio_period = period;
+
+	AmiSetTreble(50);  /* recommended for newer amiga models */
+}
+
+
+static int AmiSetFormat(int format)
+{
+	int size;
+
+	/* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
+
+	switch (format) {
+	case AFMT_QUERY:
+		return dmasound.soft.format;
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_U8:
+	case AFMT_S8:
+		size = 8;
+		break;
+	case AFMT_S16_BE:
+	case AFMT_U16_BE:
+	case AFMT_S16_LE:
+	case AFMT_U16_LE:
+		size = 16;
+		break;
+	default: /* :-) */
+		size = 8;
+		format = AFMT_S8;
+	}
+
+	dmasound.soft.format = format;
+	dmasound.soft.size = size;
+	if (dmasound.minDev == SND_DEV_DSP) {
+		dmasound.dsp.format = format;
+		dmasound.dsp.size = dmasound.soft.size;
+	}
+	AmiInit();
+
+	return format;
+}
+
+
+#define VOLUME_VOXWARE_TO_AMI(v) \
+	(((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
+#define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
+
+static int AmiSetVolume(int volume)
+{
+	dmasound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
+	custom.aud[0].audvol = dmasound.volume_left;
+	dmasound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
+	custom.aud[1].audvol = dmasound.volume_right;
+	if (dmasound.hard.size == 16) {
+		if (dmasound.volume_left == 64 && dmasound.volume_right == 64) {
+			custom.aud[2].audvol = 1;
+			custom.aud[3].audvol = 1;
+		} else {
+			custom.aud[2].audvol = 0;
+			custom.aud[3].audvol = 0;
+		}
+	}
+	return VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) |
+	       (VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8);
+}
+
+static int AmiSetTreble(int treble)
+{
+	dmasound.treble = treble;
+	if (treble < 50)
+		ciaa.pra &= ~0x02;
+	else
+		ciaa.pra |= 0x02;
+	return treble;
+}
+
+
+#define AMI_PLAY_LOADED		1
+#define AMI_PLAY_PLAYING	2
+#define AMI_PLAY_MASK		3
+
+
+static void AmiPlayNextFrame(int index)
+{
+	u_char *start, *ch0, *ch1, *ch2, *ch3;
+	u_long size;
+
+	/* used by AmiPlay() if all doubts whether there really is something
+	 * to be played are already wiped out.
+	 */
+	start = write_sq.buffers[write_sq.front];
+	size = (write_sq.count == index ? write_sq.rear_size
+					: write_sq.block_size)>>1;
+
+	if (dmasound.hard.stereo) {
+		ch0 = start;
+		ch1 = start+write_sq_block_size_half;
+		size >>= 1;
+	} else {
+		ch0 = start;
+		ch1 = start;
+	}
+
+	custom.aud[0].audvol = dmasound.volume_left;
+	custom.aud[1].audvol = dmasound.volume_right;
+	if (dmasound.hard.size == 8) {
+		custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+		custom.aud[0].audlen = size;
+		custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+		custom.aud[1].audlen = size;
+		custom.dmacon = AMI_AUDIO_8;
+	} else {
+		size >>= 1;
+		custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+		custom.aud[0].audlen = size;
+		custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+		custom.aud[1].audlen = size;
+		if (dmasound.volume_left == 64 && dmasound.volume_right == 64) {
+			/* We can play pseudo 14-bit only with the maximum volume */
+			ch3 = ch0+write_sq_block_size_quarter;
+			ch2 = ch1+write_sq_block_size_quarter;
+			custom.aud[2].audvol = 1;  /* we are being affected by the beeps */
+			custom.aud[3].audvol = 1;  /* restoring volume here helps a bit */
+			custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
+			custom.aud[2].audlen = size;
+			custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
+			custom.aud[3].audlen = size;
+			custom.dmacon = AMI_AUDIO_14;
+		} else {
+			custom.aud[2].audvol = 0;
+			custom.aud[3].audvol = 0;
+			custom.dmacon = AMI_AUDIO_8;
+		}
+	}
+	write_sq.front = (write_sq.front+1) % write_sq.max_count;
+	write_sq.active |= AMI_PLAY_LOADED;
+}
+
+
+static void AmiPlay(void)
+{
+	int minframes = 1;
+
+	custom.intena = IF_AUD0;
+
+	if (write_sq.active & AMI_PLAY_LOADED) {
+		/* There's already a frame loaded */
+		custom.intena = IF_SETCLR | IF_AUD0;
+		return;
+	}
+
+	if (write_sq.active & AMI_PLAY_PLAYING)
+		/* Increase threshold: frame 1 is already being played */
+		minframes = 2;
+
+	if (write_sq.count < minframes) {
+		/* Nothing to do */
+		custom.intena = IF_SETCLR | IF_AUD0;
+		return;
+	}
+
+	if (write_sq.count <= minframes &&
+	    write_sq.rear_size < write_sq.block_size && !write_sq.syncing) {
+		/* hmmm, the only existing frame is not
+		 * yet filled and we're not syncing?
+		 */
+		custom.intena = IF_SETCLR | IF_AUD0;
+		return;
+	}
+
+	AmiPlayNextFrame(minframes);
+
+	custom.intena = IF_SETCLR | IF_AUD0;
+}
+
+
+static void AmiInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+	int minframes = 1;
+
+	custom.intena = IF_AUD0;
+
+	if (!write_sq.active) {
+		/* Playing was interrupted and sq_reset() has already cleared
+		 * the sq variables, so better don't do anything here.
+		 */
+		WAKE_UP(write_sq.sync_queue);
+		return;
+	}
+
+	if (write_sq.active & AMI_PLAY_PLAYING) {
+		/* We've just finished a frame */
+		write_sq.count--;
+		WAKE_UP(write_sq.action_queue);
+	}
+
+	if (write_sq.active & AMI_PLAY_LOADED)
+		/* Increase threshold: frame 1 is already being played */
+		minframes = 2;
+
+	/* Shift the flags */
+	write_sq.active = (write_sq.active<<1) & AMI_PLAY_MASK;
+
+	if (!write_sq.active)
+		/* No frame is playing, disable audio DMA */
+		StopDMA();
+
+	custom.intena = IF_SETCLR | IF_AUD0;
+
+	if (write_sq.count >= minframes)
+		/* Try to play the next frame */
+		AmiPlay();
+
+	if (!write_sq.active)
+		/* Nothing to play anymore.
+		   Wake up a process waiting for audio output to drain. */
+		WAKE_UP(write_sq.sync_queue);
+}
+
+/*** Mid level stuff *********************************************************/
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+static void __init AmiMixerInit(void)
+{
+	dmasound.volume_left = 64;
+	dmasound.volume_right = 64;
+	custom.aud[0].audvol = dmasound.volume_left;
+	custom.aud[3].audvol = 1;	/* For pseudo 14bit */
+	custom.aud[1].audvol = dmasound.volume_right;
+	custom.aud[2].audvol = 1;	/* For pseudo 14bit */
+	dmasound.treble = 50;
+}
+
+static int AmiMixerIoctl(u_int cmd, u_long arg)
+{
+	int data;
+	switch (cmd) {
+	    case SOUND_MIXER_READ_DEVMASK:
+		    return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE);
+	    case SOUND_MIXER_READ_RECMASK:
+		    return IOCTL_OUT(arg, 0);
+	    case SOUND_MIXER_READ_STEREODEVS:
+		    return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
+	    case SOUND_MIXER_READ_VOLUME:
+		    return IOCTL_OUT(arg,
+			    VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) |
+			    VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8);
+	    case SOUND_MIXER_WRITE_VOLUME:
+		    IOCTL_IN(arg, data);
+		    return IOCTL_OUT(arg, dmasound_set_volume(data));
+	    case SOUND_MIXER_READ_TREBLE:
+		    return IOCTL_OUT(arg, dmasound.treble);
+	    case SOUND_MIXER_WRITE_TREBLE:
+		    IOCTL_IN(arg, data);
+		    return IOCTL_OUT(arg, dmasound_set_treble(data));
+	}
+	return -EINVAL;
+}
+
+
+static void AmiWriteSqSetup(void)
+{
+	write_sq_block_size_half = write_sq.block_size>>1;
+	write_sq_block_size_quarter = write_sq_block_size_half>>1;
+}
+
+
+static int AmiStateInfo(char *buffer)
+{
+	int len = 0;
+	len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
+		       dmasound.volume_left);
+	len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
+		       dmasound.volume_right);
+	return len;
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machAmiga = {
+	name:		"Amiga",
+	name2:		"AMIGA",
+	open:		AmiOpen,
+	release:	AmiRelease,
+	dma_alloc:	AmiAlloc,
+	dma_free:	AmiFree,
+	irqinit:	AmiIrqInit,
+#ifdef MODULE
+	irqcleanup:	AmiIrqCleanUp,
+#endif /* MODULE */
+	init:		AmiInit,
+	silence:	AmiSilence,
+	setFormat:	AmiSetFormat,
+	setVolume:	AmiSetVolume,
+	setTreble:	AmiSetTreble,
+	play:		AmiPlay,
+	mixer_init:	AmiMixerInit,
+	mixer_ioctl:	AmiMixerIoctl,
+	write_sq_setup:	AmiWriteSqSetup,
+	state_info:	AmiStateInfo,
+	min_dsp_speed:	8000
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+int __init dmasound_paula_init(void)
+{
+	int err;
+
+	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_AUDIO)) {
+	    if (!request_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40,
+				    "dmasound [Paula]"))
+		return -EBUSY;
+	    dmasound.mach = machAmiga;
+	    err = dmasound_init();
+	    if (err)
+		release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
+	    return err;
+	} else
+	    return -ENODEV;
+}
+
+static void __exit dmasound_paula_cleanup(void)
+{
+	dmasound_deinit();
+	release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
+}
+
+module_init(dmasound_paula_init);
+module_exit(dmasound_paula_cleanup);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound_q40.c linux/drivers/sound/dmasound/dmasound_q40.c
--- v2.3.99-pre3/linux/drivers/sound/dmasound/dmasound_q40.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/dmasound/dmasound_q40.c	Mon Apr 10 22:58:59 2000
@@ -0,0 +1,587 @@
+
+/*
+ *  linux/drivers/sound/dmasound_q40.c
+ *
+ *  Q40 DMA Sound Driver
+ *
+ *  See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+
+#include <asm/uaccess.h>
+#include <asm/q40_master.h>
+
+#include "dmasound.h"
+
+
+static int expand_bal;	/* Balance factor for expanding (not volume!) */
+static int expand_data;	/* Data for expanding */
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void Q40Open(void);
+static void Q40Release(void);
+static void *Q40Alloc(unsigned int size, int flags);
+static void Q40Free(void *, unsigned int);
+static int Q40IrqInit(void);
+#ifdef MODULE
+static void Q40IrqCleanUp(void);
+#endif
+static void Q40Silence(void);
+static void Q40Init(void);
+static int Q40SetFormat(int format);
+static int Q40SetVolume(int volume);
+static void Q40PlayNextFrame(int index);
+static void Q40Play(void);
+static void Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp);
+static void Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp);
+static void Q40Interrupt(void);
+
+
+/*** Mid level stuff *********************************************************/
+
+
+#if 1
+/* userCount, frameUsed, frameLeft == byte counts */
+static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8;
+	ssize_t count, used;
+	u_char *p = (u_char *) &frame[*frameUsed];
+
+	used = count = min(userCount, frameLeft);
+	if (copy_from_user(p,userPtr,count))
+	  return -EFAULT;
+	while (count > 0) {
+		*p = table[*p]+128;
+		p++;
+		count--;
+	}
+	*frameUsed += used ;
+	return used;
+}
+#else
+static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8;
+	ssize_t count, used;
+	u_char *p = (u_char *) &frame[*frameUsed];
+	u_char val;
+	int stereo = sound.soft.stereo;
+
+
+	frameLeft >>= 1;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		val = table[data]+128;
+		*p++ = val;
+		if (stereo) {
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			val = table[data]+128;
+		}
+		*p++ = val;
+		count--;
+	}
+	*frameUsed += used * 2;
+	return stereo? used * 2: used;
+}
+#endif
+
+#if 1
+static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	ssize_t count, used;
+	u_char *p = (u_char *) &frame[*frameUsed];
+
+	used = count = min(userCount, frameLeft);
+	if (copy_from_user(p,userPtr,count))
+	  return -EFAULT;
+	while (count > 0) {
+		*p = *p + 128;
+		p++;
+		count--;
+	}
+	*frameUsed += used;
+	return used;
+}
+#else
+static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	ssize_t count, used;
+	u_char *p = (u_char *) &frame[*frameUsed];
+	u_char val;
+	int stereo = dmasound.soft.stereo;
+
+	frameLeft >>= 1;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		val = data + 128;
+		*p++ = val;
+		if (stereo) {
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			val = data + 128;
+		}
+		*p++ = val;
+		count--;
+	}
+	*frameUsed += used * 2;
+	return stereo? used * 2: used;
+}
+#endif
+
+#if 1
+static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	ssize_t count, used;
+	u_char *p = (u_char *) &frame[*frameUsed];
+
+	used = count = min(userCount, frameLeft);
+	if (copy_from_user(p,userPtr,count))
+	  return -EFAULT;
+	*frameUsed += used;
+	return used;
+}
+#else
+static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	ssize_t count, used;
+	u_char *p = (u_char *) &frame[*frameUsed];
+	u_char val;
+	int stereo = dmasound.soft.stereo;
+
+
+	frameLeft >>= 1;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		val = data;
+		*p++ = val;
+		if (stereo) {
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			val = data;
+		}
+		*p++ = val;
+		count--;
+	}
+	*frameUsed += used * 2;
+	return stereo? used * 2: used;
+}
+#endif
+
+/* a bit too complicated to optimise right now ..*/
+static ssize_t q40_ctx_law(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
+{
+	unsigned char *table = (unsigned char *)
+		(dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8);
+	unsigned int data = expand_data;
+	u_char *p = (u_char *) &frame[*frameUsed];
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int utotal, ftotal;
+ 
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(c, userPtr++))
+				return -EFAULT;
+			data = table[c];
+			data += 0x80;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft);
+	utotal -= userCount;
+	return utotal;
+}
+
+
+static ssize_t q40_ctx_s8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	u_char *p = (u_char *) &frame[*frameUsed];
+	unsigned int data = expand_data;
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int utotal, ftotal;
+
+
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(c, userPtr++))
+				return -EFAULT;
+			data = c ;
+			data += 0x80;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft);
+	utotal -= userCount;
+	return utotal;
+}
+
+
+static ssize_t q40_ctx_u8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	u_char *p = (u_char *) &frame[*frameUsed];
+	unsigned int data = expand_data;
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int utotal, ftotal;
+
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(c, userPtr++))
+				return -EFAULT;
+			data = c ;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft) ;
+	utotal -= userCount;
+	return utotal;
+}
+
+
+static TRANS transQ40Normal = {
+	q40_ct_law, q40_ct_law, q40_ct_s8, q40_ct_u8, NULL, NULL, NULL, NULL
+};
+
+static TRANS transQ40Expanding = {
+	q40_ctx_law, q40_ctx_law, q40_ctx_s8, q40_ctx_u8, NULL, NULL, NULL, NULL
+};
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void Q40Open(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void Q40Release(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+
+static void *Q40Alloc(unsigned int size, int flags)
+{
+         return kmalloc(size, flags); /* change to vmalloc */
+}
+
+static void Q40Free(void *ptr, unsigned int size)
+{
+	kfree(ptr);
+}
+
+static int __init Q40IrqInit(void)
+{
+	/* Register interrupt handler. */
+	request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
+		    "DMA sound", Q40Interrupt);
+
+	return(1);
+}
+
+
+#ifdef MODULE
+static void Q40IrqCleanUp(void)
+{
+        master_outb(0,SAMPLE_ENABLE_REG);
+	free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
+}
+#endif /* MODULE */
+
+
+static void Q40Silence(void)
+{
+        master_outb(0,SAMPLE_ENABLE_REG);
+	*DAC_LEFT=*DAC_RIGHT=0;
+}
+
+static char *q40_pp=NULL;
+static unsigned int q40_sc=0;
+
+static void Q40PlayNextFrame(int index)
+{
+	u_char *start;
+	u_long size;
+	u_char speed;
+
+	/* used by Q40Play() if all doubts whether there really is something
+	 * to be played are already wiped out.
+	 */
+	start = write_sq.buffers[write_sq.front];
+	size = (write_sq.count == index ? write_sq.rear_size : write_sq.block_size);
+
+	q40_pp=start;
+	q40_sc=size;
+		
+	write_sq.front = (write_sq.front+1) % write_sq.max_count;
+	write_sq.active++;
+
+	speed=(dmasound.hard.speed==10000 ? 0 : 1);
+
+	master_outb( 0,SAMPLE_ENABLE_REG);
+	free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
+	if (dmasound.soft.stereo)
+	  	request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
+		    "Q40 sound", Q40Interrupt);
+	  else
+	        request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0,
+		    "Q40 sound", Q40Interrupt);
+
+	master_outb( speed, SAMPLE_RATE_REG);
+	master_outb( 1,SAMPLE_CLEAR_REG);
+	master_outb( 1,SAMPLE_ENABLE_REG);
+}
+
+static void Q40Play(void)
+{
+        unsigned long flags;
+
+	if (write_sq.active || write_sq.count<=0 ) {
+		/* There's already a frame loaded */
+		return;
+	}
+
+	/* nothing in the queue */
+	if (write_sq.count <= 1 && write_sq.rear_size < write_sq.block_size && !write_sq.syncing) {
+	         /* hmmm, the only existing frame is not
+		  * yet filled and we're not syncing?
+		  */
+	         return;
+	}
+	save_flags(flags); cli();
+	Q40PlayNextFrame(1);
+	restore_flags(flags);
+}
+
+static void Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+        if (q40_sc>1){
+            *DAC_LEFT=*q40_pp++;
+	    *DAC_RIGHT=*q40_pp++;
+	    q40_sc -=2;
+	    master_outb(1,SAMPLE_CLEAR_REG);
+	}else Q40Interrupt();
+}
+static void Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+        if (q40_sc>0){
+            *DAC_LEFT=*q40_pp;
+	    *DAC_RIGHT=*q40_pp++;
+	    q40_sc --;
+	    master_outb(1,SAMPLE_CLEAR_REG);	    
+	}else Q40Interrupt();
+}
+static void Q40Interrupt(void)
+{
+	if (!write_sq.active) {
+	          /* playing was interrupted and sq_reset() has already cleared
+		   * the sq variables, so better don't do anything here.
+		   */
+	           WAKE_UP(write_sq.sync_queue);
+		   master_outb(0,SAMPLE_ENABLE_REG); /* better safe */
+		   goto exit;
+	} else write_sq.active=0;
+	write_sq.count--;
+	Q40Play();
+
+	if (q40_sc<2)
+	      { /* there was nothing to play, disable irq */
+		master_outb(0,SAMPLE_ENABLE_REG);
+		*DAC_LEFT=*DAC_RIGHT=0;
+	      }
+	WAKE_UP(write_sq.action_queue);
+
+ exit:
+	master_outb(1,SAMPLE_CLEAR_REG);
+}
+
+
+static void Q40Init(void)
+{
+	int i, idx;
+	const int freq[] = {10000, 20000};
+
+	/* search a frequency that fits into the allowed error range */
+
+	idx = -1;
+	for (i = 0; i < 2; i++)
+		if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) <= catchRadius)
+			idx = i;
+
+	dmasound.hard = dmasound.soft;
+	/*sound.hard.stereo=1;*/ /* no longer true */
+	dmasound.hard.size=8;
+
+	if (idx > -1) {
+		dmasound.soft.speed = freq[idx];
+		dmasound.trans_write = &transQ40Normal;
+	} else
+		dmasound.trans_write = &transQ40Expanding;
+
+	Q40Silence();
+
+	if (dmasound.hard.speed > 20000) {
+		/* we would need to squeeze the sound, but we won't do that */
+		dmasound.hard.speed = 20000;
+		dmasound.trans_write = &transQ40Normal;
+	} else if (dmasound.hard.speed > 10000) {
+		dmasound.hard.speed = 20000;
+	} else {
+		dmasound.hard.speed = 10000;
+	}
+	expand_bal = -dmasound.soft.speed;
+}
+
+
+static int Q40SetFormat(int format)
+{
+	/* Q40 sound supports only 8bit modes */
+
+	switch (format) {
+	case AFMT_QUERY:
+		return(dmasound.soft.format);
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_S8:
+	case AFMT_U8:
+		break;
+	default:
+		format = AFMT_S8;
+	}
+
+	dmasound.soft.format = format;
+	dmasound.soft.size = 8;
+	if (dmasound.minDev == SND_DEV_DSP) {
+		dmasound.dsp.format = format;
+		dmasound.dsp.size = 8;
+	}
+	Q40Init();
+
+	return(format);
+}
+
+static int Q40SetVolume(int volume)
+{
+    return 0;
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machQ40 = {
+	name:		"Q40",
+	name2:		"Q40",
+	open:		Q40Open,
+	release:	Q40Release,
+	dma_alloc:	Q40Alloc,
+	dma_free:	Q40Free,
+	irqinit:	Q40IrqInit,
+#ifdef MODULE
+	irqcleanup:	Q40IrqCleanUp,
+#endif /* MODULE */
+	init:		Q40Init,
+	silence:	Q40Silence, 
+	setFormat:	Q40SetFormat, 
+	setVolume:	Q40SetVolume,
+	play:		Q40Play
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+int __init dmasound_q40_init(void)
+{
+	if (MACH_IS_Q40) {
+	    dmasound.mach = machQ40;
+	    return dmasound_init();
+	} else
+	    return -ENODEV;
+}
+
+static void __exit dmasound_q40_cleanup(void)
+{
+	dmasound_deinit();
+}
+
+module_init(dmasound_q40_init);
+module_exit(dmasound_q40_cleanup);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.3.99-pre3/linux/drivers/sound/dmasound.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/sound/dmasound.c	Wed Dec 31 16:00:00 1969
@@ -1,5821 +0,0 @@
-
-/* linux/drivers/sound/dmasound.c */
-
-/*
-
-OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k
-Extended to support Power Macintosh for Linux/ppc by Paul Mackerras
-
-(c) 1995 by Michael Schlueter & Michael Marte
-
-Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS
-interface and the u-law to signed byte conversion.
-
-Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue,
-/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like
-to thank:
-Michael Schlueter for initial ideas and documentation on the MFP and
-the DMA sound hardware.
-Therapy? for their CD 'Troublegum' which really made me rock.
-
-/dev/sndstat is based on code by Hannu Savolainen, the author of the
-VoxWare family of drivers.
-
-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.
-
-History:
-1995/8/25	first release
-
-1995/9/02	++roman: fixed atari_stram_alloc() call, the timer programming
-			and several race conditions
-
-1995/9/14	++roman: After some discussion with Michael Schlueter, revised
-			the interrupt disabling
-			Slightly speeded up U8->S8 translation by using long
-			operations where possible
-			Added 4:3 interpolation for /dev/audio
-
-1995/9/20	++TeSche: Fixed a bug in sq_write and changed /dev/audio
-			converting to play at 12517Hz instead of 6258Hz.
-
-1995/9/23	++TeSche: Changed sq_interrupt() and sq_play() to pre-program
-			the DMA for another frame while there's still one
-			running. This allows the IRQ response to be
-			arbitrarily delayed and playing will still continue.
-
-1995/10/14	++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for
-			Falcon audio (the Falcon doesn't raise an IRQ at the
-			end of a frame, but at the beginning instead!). uses
-			'if (codec_dma)' in lots of places to simply switch
-			between Falcon and TT code.
-
-1995/11/06	++TeSche: started introducing a hardware abstraction scheme
-			(may perhaps also serve for Amigas?), can now play
-			samples at almost all frequencies by means of a more
-			generalized expand routine, takes a good deal of care
-			to cut data only at sample sizes, buffer size is now
-			a kernel runtime option, implemented fsync() & several
-			minor improvements
-		++Guenther: useful hints and bug fixes, cross-checked it for
-			Falcons
-
-1996/3/9	++geert: support added for Amiga, A-law, 16-bit little endian.
-			Unification to drivers/sound/dmasound.c.
-
-1996/4/6	++Martin Mitchell: updated to 1.3 kernel.
-
-1996/6/13       ++topi: fixed things that were broken (mainly the amiga
-                        14-bit routines), /dev/sndstat shows now the real
-                        hardware frequency, the lowpass filter is disabled
-			by default now.
-
-1996/9/25	++geert: modularization
-
-1998-06-10	++andreas: converted to use sound_core
-
-*/
-
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/config.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/sound.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-#include <asm/setup.h>
-#endif
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_ATARI
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_stram.h>
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/feature.h>
-#include "awacs_defs.h"
-#include <linux/nvram.h>
-#include <linux/vt_kern.h>
-#endif /* CONFIG_PPC */
-
-#include "dmasound.h"
-#include <linux/soundcard.h>
-
-#define HAS_8BIT_TABLES
-
-#ifdef MODULE
-static int sq_unit = -1;
-static int mixer_unit = -1;
-static int state_unit = -1;
-static int irq_installed = 0;
-#endif /* MODULE */
-static char **sound_buffers = NULL;
-#ifdef CONFIG_PPC
-static char **sound_read_buffers = NULL;
-#endif
-
-#ifdef CONFIG_ATARI
-extern void atari_microwire_cmd(int cmd);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-   /*
-    *	The minimum period for audio depends on htotal (for OCS/ECS/AGA)
-    *	(Imported from arch/m68k/amiga/amisound.c)
-    */
-
-extern volatile u_short amiga_audio_min_period;
-
-
-   /*
-    *	amiga_mksound() should be able to restore the period after beeping
-    *	(Imported from arch/m68k/amiga/amisound.c)
-    */
-
-extern u_short amiga_audio_period;
-
-
-   /*
-    *	Audio DMA masks
-    */
-
-#define AMI_AUDIO_OFF	(DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
-#define AMI_AUDIO_8	(DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
-#define AMI_AUDIO_14	(AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
-
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-/*
- * Interrupt numbers and addresses, obtained from the device tree.
- */
-static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
-static volatile struct awacs_regs *awacs;
-static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
-static int awacs_rate_index;
-static int awacs_subframe;
-static int awacs_spkr_vol;
-static struct device_node* awacs_node;
-
-static int awacs_revision;
-#define AWACS_BURGUNDY	100		/* fake revision # for burgundy */
-
-/*
- * Space for the DBDMA command blocks.
- */
-static void *awacs_tx_cmd_space;
-static volatile struct dbdma_cmd *awacs_tx_cmds;
-
-static void *awacs_rx_cmd_space;
-static volatile struct dbdma_cmd *awacs_rx_cmds;
-
-/*
- * Cached values of AWACS registers (we can't read them).
- * Except on the burgundy. XXX
- */
-int awacs_reg[5];
-
-#define HAS_16BIT_TABLES
-#undef HAS_8BIT_TABLES
-
-/*
- * Stuff for outputting a beep.  The values range from -327 to +327
- * so we can multiply by an amplitude in the range 0..100 to get a
- * signed short value to put in the output buffer.
- */
-static short beep_wform[256] = {
-	0,	40,	79,	117,	153,	187,	218,	245,
-	269,	288,	304,	316,	323,	327,	327,	324,
-	318,	310,	299,	288,	275,	262,	249,	236,
-	224,	213,	204,	196,	190,	186,	183,	182,
-	182,	183,	186,	189,	192,	196,	200,	203,
-	206,	208,	209,	209,	209,	207,	204,	201,
-	197,	193,	188,	183,	179,	174,	170,	166,
-	163,	161,	160,	159,	159,	160,	161,	162,
-	164,	166,	168,	169,	171,	171,	171,	170,
-	169,	167,	163,	159,	155,	150,	144,	139,
-	133,	128,	122,	117,	113,	110,	107,	105,
-	103,	103,	103,	103,	104,	104,	105,	105,
-	105,	103,	101,	97,	92,	86,	78,	68,
-	58,	45,	32,	18,	3,	-11,	-26,	-41,
-	-55,	-68,	-79,	-88,	-95,	-100,	-102,	-102,
-	-99,	-93,	-85,	-75,	-62,	-48,	-33,	-16,
-	0,	16,	33,	48,	62,	75,	85,	93,
-	99,	102,	102,	100,	95,	88,	79,	68,
-	55,	41,	26,	11,	-3,	-18,	-32,	-45,
-	-58,	-68,	-78,	-86,	-92,	-97,	-101,	-103,
-	-105,	-105,	-105,	-104,	-104,	-103,	-103,	-103,
-	-103,	-105,	-107,	-110,	-113,	-117,	-122,	-128,
-	-133,	-139,	-144,	-150,	-155,	-159,	-163,	-167,
-	-169,	-170,	-171,	-171,	-171,	-169,	-168,	-166,
-	-164,	-162,	-161,	-160,	-159,	-159,	-160,	-161,
-	-163,	-166,	-170,	-174,	-179,	-183,	-188,	-193,
-	-197,	-201,	-204,	-207,	-209,	-209,	-209,	-208,
-	-206,	-203,	-200,	-196,	-192,	-189,	-186,	-183,
-	-182,	-182,	-183,	-186,	-190,	-196,	-204,	-213,
-	-224,	-236,	-249,	-262,	-275,	-288,	-299,	-310,
-	-318,	-324,	-327,	-327,	-323,	-316,	-304,	-288,
-	-269,	-245,	-218,	-187,	-153,	-117,	-79,	-40,
-};
-
-#define BEEP_SRATE	22050	/* 22050 Hz sample rate */
-#define BEEP_BUFLEN	512
-#define BEEP_VOLUME	15	/* 0 - 100 */
-
-static int beep_volume = BEEP_VOLUME;
-static int beep_playing = 0;
-static int awacs_beep_state = 0;
-static short *beep_buf;
-static volatile struct dbdma_cmd *beep_dbdma_cmd;
-static void (*orig_mksound)(unsigned int, unsigned int);
-static int is_pbook_3400;
-static unsigned char *latch_base;
-static int is_pbook_G3;
-static unsigned char *macio_base;
-
-/* Burgundy functions */
-static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
-static unsigned awacs_burgundy_rcw(unsigned addr);
-static void awacs_burgundy_write_volume(unsigned address, int volume);
-static int awacs_burgundy_read_volume(unsigned address);
-static void awacs_burgundy_write_mvolume(unsigned address, int volume);
-static int awacs_burgundy_read_mvolume(unsigned address);
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Stuff for restoring after a sleep.
- */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
-struct pmu_sleep_notifier awacs_sleep_notifier = {
-	awacs_sleep_notify, SLEEP_LEVEL_SOUND,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-#endif /* CONFIG_PPC */
-
-/*** Some declarations *******************************************************/
-
-
-#define DMASND_TT		1
-#define DMASND_FALCON		2
-#define DMASND_AMIGA		3
-#define DMASND_AWACS		4
-
-#define MAX_CATCH_RADIUS	10
-#define MIN_BUFFERS		4
-#define MIN_BUFSIZE 		4
-#define MAX_BUFSIZE		128	/* Limit for Amiga */
-
-static int catchRadius = 0;
-static int numBufs = 4, bufSize = 32;
-#ifdef CONFIG_PPC
-static int numReadBufs = 4, readbufSize = 32;
-#endif
-
-MODULE_PARM(catchRadius, "i");
-MODULE_PARM(numBufs, "i");
-MODULE_PARM(bufSize, "i");
-MODULE_PARM(numReadBufs, "i");
-MODULE_PARM(readbufSize, "i");
-
-#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
-#define min(x, y)	((x) < (y) ? (x) : (y))
-#define le2be16(x)	(((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x)	(((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
-	do { int error = get_user(ret, (int *)(arg)); \
-		if (error) return error; \
-	} while (0)
-#define IOCTL_OUT(arg, ret)	ioctl_return((int *)(arg), ret)
-
-
-/*** Some low level helpers **************************************************/
-
-#ifdef HAS_8BIT_TABLES
-/* 8 bit mu-law */
-
-static char ulaw2dma8[] = {
-	-126,	-122,	-118,	-114,	-110,	-106,	-102,	-98,
-	-94,	-90,	-86,	-82,	-78,	-74,	-70,	-66,
-	-63,	-61,	-59,	-57,	-55,	-53,	-51,	-49,
-	-47,	-45,	-43,	-41,	-39,	-37,	-35,	-33,
-	-31,	-30,	-29,	-28,	-27,	-26,	-25,	-24,
-	-23,	-22,	-21,	-20,	-19,	-18,	-17,	-16,
-	-16,	-15,	-15,	-14,	-14,	-13,	-13,	-12,
-	-12,	-11,	-11,	-10,	-10,	-9,	-9,	-8,
-	-8,	-8,	-7,	-7,	-7,	-7,	-6,	-6,
-	-6,	-6,	-5,	-5,	-5,	-5,	-4,	-4,
-	-4,	-4,	-4,	-4,	-3,	-3,	-3,	-3,
-	-3,	-3,	-3,	-3,	-2,	-2,	-2,	-2,
-	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
-	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
-	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
-	-1,	-1,	-1,	-1,	-1,	-1,	-1,	0,
-	125,	121,	117,	113,	109,	105,	101,	97,
-	93,	89,	85,	81,	77,	73,	69,	65,
-	62,	60,	58,	56,	54,	52,	50,	48,
-	46,	44,	42,	40,	38,	36,	34,	32,
-	30,	29,	28,	27,	26,	25,	24,	23,
-	22,	21,	20,	19,	18,	17,	16,	15,
-	15,	14,	14,	13,	13,	12,	12,	11,
-	11,	10,	10,	9,	9,	8,	8,	7,
-	7,	7,	6,	6,	6,	6,	5,	5,
-	5,	5,	4,	4,	4,	4,	3,	3,
-	3,	3,	3,	3,	2,	2,	2,	2,
-	2,	2,	2,	2,	1,	1,	1,	1,
-	1,	1,	1,	1,	1,	1,	1,	1,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0
-};
-
-/* 8 bit A-law */
-
-static char alaw2dma8[] = {
-	-22,	-21,	-24,	-23,	-18,	-17,	-20,	-19,
-	-30,	-29,	-32,	-31,	-26,	-25,	-28,	-27,
-	-11,	-11,	-12,	-12,	-9,	-9,	-10,	-10,
-	-15,	-15,	-16,	-16,	-13,	-13,	-14,	-14,
-	-86,	-82,	-94,	-90,	-70,	-66,	-78,	-74,
-	-118,	-114,	-126,	-122,	-102,	-98,	-110,	-106,
-	-43,	-41,	-47,	-45,	-35,	-33,	-39,	-37,
-	-59,	-57,	-63,	-61,	-51,	-49,	-55,	-53,
-	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
-	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
-	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
-	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
-	-6,	-6,	-6,	-6,	-5,	-5,	-5,	-5,
-	-8,	-8,	-8,	-8,	-7,	-7,	-7,	-7,
-	-3,	-3,	-3,	-3,	-3,	-3,	-3,	-3,
-	-4,	-4,	-4,	-4,	-4,	-4,	-4,	-4,
-	21,	20,	23,	22,	17,	16,	19,	18,
-	29,	28,	31,	30,	25,	24,	27,	26,
-	10,	10,	11,	11,	8,	8,	9,	9,
-	14,	14,	15,	15,	12,	12,	13,	13,
-	86,	82,	94,	90,	70,	66,	78,	74,
-	118,	114,	126,	122,	102,	98,	110,	106,
-	43,	41,	47,	45,	35,	33,	39,	37,
-	59,	57,	63,	61,	51,	49,	55,	53,
-	1,	1,	1,	1,	1,	1,	1,	1,
-	1,	1,	1,	1,	1,	1,	1,	1,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	5,	5,	5,	5,	4,	4,	4,	4,
-	7,	7,	7,	7,	6,	6,	6,	6,
-	2,	2,	2,	2,	2,	2,	2,	2,
-	3,	3,	3,	3,	3,	3,	3,	3
-};
-#endif /* HAS_8BIT_TABLES */
-
-#ifdef HAS_16BIT_TABLES
-
-/* 16 bit mu-law */
-
-static short ulaw2dma16[] = {
-	-32124,	-31100,	-30076,	-29052,	-28028,	-27004,	-25980,	-24956,
-	-23932,	-22908,	-21884,	-20860,	-19836,	-18812,	-17788,	-16764,
-	-15996,	-15484,	-14972,	-14460,	-13948,	-13436,	-12924,	-12412,
-	-11900,	-11388,	-10876,	-10364,	-9852,	-9340,	-8828,	-8316,
-	-7932,	-7676,	-7420,	-7164,	-6908,	-6652,	-6396,	-6140,
-	-5884,	-5628,	-5372,	-5116,	-4860,	-4604,	-4348,	-4092,
-	-3900,	-3772,	-3644,	-3516,	-3388,	-3260,	-3132,	-3004,
-	-2876,	-2748,	-2620,	-2492,	-2364,	-2236,	-2108,	-1980,
-	-1884,	-1820,	-1756,	-1692,	-1628,	-1564,	-1500,	-1436,
-	-1372,	-1308,	-1244,	-1180,	-1116,	-1052,	-988,	-924,
-	-876,	-844,	-812,	-780,	-748,	-716,	-684,	-652,
-	-620,	-588,	-556,	-524,	-492,	-460,	-428,	-396,
-	-372,	-356,	-340,	-324,	-308,	-292,	-276,	-260,
-	-244,	-228,	-212,	-196,	-180,	-164,	-148,	-132,
-	-120,	-112,	-104,	-96,	-88,	-80,	-72,	-64,
-	-56,	-48,	-40,	-32,	-24,	-16,	-8,	0,
-	32124,	31100,	30076,	29052,	28028,	27004,	25980,	24956,
-	23932,	22908,	21884,	20860,	19836,	18812,	17788,	16764,
-	15996,	15484,	14972,	14460,	13948,	13436,	12924,	12412,
-	11900,	11388,	10876,	10364,	9852,	9340,	8828,	8316,
-	7932,	7676,	7420,	7164,	6908,	6652,	6396,	6140,
-	5884,	5628,	5372,	5116,	4860,	4604,	4348,	4092,
-	3900,	3772,	3644,	3516,	3388,	3260,	3132,	3004,
-	2876,	2748,	2620,	2492,	2364,	2236,	2108,	1980,
-	1884,	1820,	1756,	1692,	1628,	1564,	1500,	1436,
-	1372,	1308,	1244,	1180,	1116,	1052,	988,	924,
-	876,	844,	812,	780,	748,	716,	684,	652,
-	620,	588,	556,	524,	492,	460,	428,	396,
-	372,	356,	340,	324,	308,	292,	276,	260,
-	244,	228,	212,	196,	180,	164,	148,	132,
-	120,	112,	104,	96,	88,	80,	72,	64,
-	56,	48,	40,	32,	24,	16,	8,	0,
-};
-
-/* 16 bit A-law */
-
-static short alaw2dma16[] = {
-	-5504,	-5248,	-6016,	-5760,	-4480,	-4224,	-4992,	-4736,
-	-7552,	-7296,	-8064,	-7808,	-6528,	-6272,	-7040,	-6784,
-	-2752,	-2624,	-3008,	-2880,	-2240,	-2112,	-2496,	-2368,
-	-3776,	-3648,	-4032,	-3904,	-3264,	-3136,	-3520,	-3392,
-	-22016,	-20992,	-24064,	-23040,	-17920,	-16896,	-19968,	-18944,
-	-30208,	-29184,	-32256,	-31232,	-26112,	-25088,	-28160,	-27136,
-	-11008,	-10496,	-12032,	-11520,	-8960,	-8448,	-9984,	-9472,
-	-15104,	-14592,	-16128,	-15616,	-13056,	-12544,	-14080,	-13568,
-	-344,	-328,	-376,	-360,	-280,	-264,	-312,	-296,
-	-472,	-456,	-504,	-488,	-408,	-392,	-440,	-424,
-	-88,	-72,	-120,	-104,	-24,	-8,	-56,	-40,
-	-216,	-200,	-248,	-232,	-152,	-136,	-184,	-168,
-	-1376,	-1312,	-1504,	-1440,	-1120,	-1056,	-1248,	-1184,
-	-1888,	-1824,	-2016,	-1952,	-1632,	-1568,	-1760,	-1696,
-	-688,	-656,	-752,	-720,	-560,	-528,	-624,	-592,
-	-944,	-912,	-1008,	-976,	-816,	-784,	-880,	-848,
-	5504,	5248,	6016,	5760,	4480,	4224,	4992,	4736,
-	7552,	7296,	8064,	7808,	6528,	6272,	7040,	6784,
-	2752,	2624,	3008,	2880,	2240,	2112,	2496,	2368,
-	3776,	3648,	4032,	3904,	3264,	3136,	3520,	3392,
-	22016,	20992,	24064,	23040,	17920,	16896,	19968,	18944,
-	30208,	29184,	32256,	31232,	26112,	25088,	28160,	27136,
-	11008,	10496,	12032,	11520,	8960,	8448,	9984,	9472,
-	15104,	14592,	16128,	15616,	13056,	12544,	14080,	13568,
-	344,	328,	376,	360,	280,	264,	312,	296,
-	472,	456,	504,	488,	408,	392,	440,	424,
-	88,	72,	120,	104,	24,	8,	56,	40,
-	216,	200,	248,	232,	152,	136,	184,	168,
-	1376,	1312,	1504,	1440,	1120,	1056,	1248,	1184,
-	1888,	1824,	2016,	1952,	1632,	1568,	1760,	1696,
-	688,	656,	752,	720,	560,	528,	624,	592,
-	944,	912,	1008,	976,	816,	784,	880,	848,
-};
-#endif /* HAS_16BIT_TABLES */
-
-
-#ifdef HAS_14BIT_TABLES
-
-/* 14 bit mu-law (LSB) */
-
-static char alaw2dma14l[] = {
-	33,	33,	33,	33,	33,	33,	33,	33,
-	33,	33,	33,	33,	33,	33,	33,	33,
-	33,	33,	33,	33,	33,	33,	33,	33,
-	33,	33,	33,	33,	33,	33,	33,	33,
-	1,	1,	1,	1,	1,	1,	1,	1,
-	1,	1,	1,	1,	1,	1,	1,	1,
-	49,	17,	49,	17,	49,	17,	49,	17,
-	49,	17,	49,	17,	49,	17,	49,	17,
-	41,	57,	9,	25,	41,	57,	9,	25,
-	41,	57,	9,	25,	41,	57,	9,	25,
-	37,	45,	53,	61,	5,	13,	21,	29,
-	37,	45,	53,	61,	5,	13,	21,	29,
-	35,	39,	43,	47,	51,	55,	59,	63,
-	3,	7,	11,	15,	19,	23,	27,	31,
-	34,	36,	38,	40,	42,	44,	46,	48,
-	50,	52,	54,	56,	58,	60,	62,	0,
-	31,	31,	31,	31,	31,	31,	31,	31,
-	31,	31,	31,	31,	31,	31,	31,	31,
-	31,	31,	31,	31,	31,	31,	31,	31,
-	31,	31,	31,	31,	31,	31,	31,	31,
-	63,	63,	63,	63,	63,	63,	63,	63,
-	63,	63,	63,	63,	63,	63,	63,	63,
-	15,	47,	15,	47,	15,	47,	15,	47,
-	15,	47,	15,	47,	15,	47,	15,	47,
-	23,	7,	55,	39,	23,	7,	55,	39,
-	23,	7,	55,	39,	23,	7,	55,	39,
-	27,	19,	11,	3,	59,	51,	43,	35,
-	27,	19,	11,	3,	59,	51,	43,	35,
-	29,	25,	21,	17,	13,	9,	5,	1,
-	61,	57,	53,	49,	45,	41,	37,	33,
-	30,	28,	26,	24,	22,	20,	18,	16,
-	14,	12,	10,	8,	6,	4,	2,	0
-};
-
-/* 14 bit A-law (LSB) */
-
-static char alaw2dma14l[] = {
-	32,	32,	32,	32,	32,	32,	32,	32,
-	32,	32,	32,	32,	32,	32,	32,	32,
-	16,	48,	16,	48,	16,	48,	16,	48,
-	16,	48,	16,	48,	16,	48,	16,	48,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	42,	46,	34,	38,	58,	62,	50,	54,
-	10,	14,	2,	6,	26,	30,	18,	22,
-	42,	46,	34,	38,	58,	62,	50,	54,
-	10,	14,	2,	6,	26,	30,	18,	22,
-	40,	56,	8,	24,	40,	56,	8,	24,
-	40,	56,	8,	24,	40,	56,	8,	24,
-	20,	28,	4,	12,	52,	60,	36,	44,
-	20,	28,	4,	12,	52,	60,	36,	44,
-	32,	32,	32,	32,	32,	32,	32,	32,
-	32,	32,	32,	32,	32,	32,	32,	32,
-	48,	16,	48,	16,	48,	16,	48,	16,
-	48,	16,	48,	16,	48,	16,	48,	16,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	22,	18,	30,	26,	6,	2,	14,	10,
-	54,	50,	62,	58,	38,	34,	46,	42,
-	22,	18,	30,	26,	6,	2,	14,	10,
-	54,	50,	62,	58,	38,	34,	46,	42,
-	24,	8,	56,	40,	24,	8,	56,	40,
-	24,	8,	56,	40,	24,	8,	56,	40,
-	44,	36,	60,	52,	12,	4,	28,	20,
-	44,	36,	60,	52,	12,	4,	28,	20
-};
-#endif /* HAS_14BIT_TABLES */
-
-
-/*** Translations ************************************************************/
-
-
-#ifdef CONFIG_ATARI
-static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
-			 u_char frame[], ssize_t *frameUsed,
-			 ssize_t frameLeft);
-static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
-			 u_char frame[], ssize_t *frameUsed,
-			 ssize_t frameLeft);
-static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
-			     u_char frame[], ssize_t *frameUsed,
-			     ssize_t frameLeft);
-static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
-			     u_char frame[], ssize_t *frameUsed,
-			     ssize_t frameLeft);
-static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
-			     u_char frame[], ssize_t *frameUsed,
-			     ssize_t frameLeft);
-static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
-			     u_char frame[], ssize_t *frameUsed,
-			     ssize_t frameLeft);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static ssize_t ami_ct_law(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
-			 u_char frame[], ssize_t *frameUsed,
-			 ssize_t frameLeft);
-static ssize_t ami_ct_u8(const u_char *userPtr, size_t userCount,
-			 u_char frame[], ssize_t *frameUsed,
-			 ssize_t frameLeft);
-static ssize_t ami_ct_s16be(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t ami_ct_u16be(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t ami_ct_s16le(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-#endif /* CONFIG_PPC */
-
-/*** Machine definitions *****************************************************/
-
-
-typedef struct {
-	int type;
-	void *(*dma_alloc)(unsigned int, int);
-	void (*dma_free)(void *, unsigned int);
-	int (*irqinit)(void);
-#ifdef MODULE
-	void (*irqcleanup)(void);
-#endif /* MODULE */
-	void (*init)(void);
-	void (*silence)(void);
-	int (*setFormat)(int);
-	int (*setVolume)(int);
-	int (*setBass)(int);
-	int (*setTreble)(int);
-	int (*setGain)(int);
-	void (*play)(void);
-} MACHINE;
-
-
-/*** Low level stuff *********************************************************/
-
-
-typedef struct {
-	int format;		/* AFMT_* */
-	int stereo;		/* 0 = mono, 1 = stereo */
-	int size;		/* 8/16 bit*/
-	int speed;		/* speed */
-} SETTINGS;
-
-typedef struct {
-	ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-	ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-	ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-	ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-	ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-	ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-	ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-	ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-} TRANS;
-
-struct sound_settings {
-	MACHINE mach;		/* machine dependent things */
-	SETTINGS hard;		/* hardware settings */
-	SETTINGS soft;		/* software settings */
-	SETTINGS dsp;		/* /dev/dsp default settings */
-	TRANS *trans;		/* supported translations */
-#if defined(CONFIG_PPC)
-	TRANS *read_trans;	/* supported translations */
-#endif
-	int volume_left;	/* volume (range is machine dependent) */
-	int volume_right;
-	int bass;		/* tone (range is machine dependent) */
-	int treble;
-	int gain;
-	int minDev;		/* minor device number currently open */
-#if defined(CONFIG_ATARI) || defined(CONFIG_PPC)
-	int bal;		/* balance factor for expanding (not volume!) */
-	u_long data;		/* data for expanding */
-#endif /* CONFIG_ATARI */
-};
-
-static struct sound_settings sound;
-
-
-#ifdef CONFIG_ATARI
-static void *AtaAlloc(unsigned int size, int flags);
-static void AtaFree(void *, unsigned int size);
-static int AtaIrqInit(void);
-#ifdef MODULE
-static void AtaIrqCleanUp(void);
-#endif /* MODULE */
-static int AtaSetBass(int bass);
-static int AtaSetTreble(int treble);
-static void TTSilence(void);
-static void TTInit(void);
-static int TTSetFormat(int format);
-static int TTSetVolume(int volume);
-static int TTSetGain(int gain);
-static void FalconSilence(void);
-static void FalconInit(void);
-static int FalconSetFormat(int format);
-static int FalconSetVolume(int volume);
-static void ata_sq_play_next_frame(int index);
-static void AtaPlay(void);
-static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static void *AmiAlloc(unsigned int size, int flags);
-static void AmiFree(void *, unsigned int);
-static int AmiIrqInit(void);
-#ifdef MODULE
-static void AmiIrqCleanUp(void);
-#endif /* MODULE */
-static void AmiSilence(void);
-static void AmiInit(void);
-static int AmiSetFormat(int format);
-static int AmiSetVolume(int volume);
-static int AmiSetTreble(int treble);
-static void ami_sq_play_next_frame(int index);
-static void AmiPlay(void);
-static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static void *PMacAlloc(unsigned int size, int flags);
-static void PMacFree(void *ptr, unsigned int size);
-static int PMacIrqInit(void);
-#ifdef MODULE
-static void PMacIrqCleanup(void);
-#endif /* MODULE */
-static void PMacSilence(void);
-static void PMacInit(void);
-static void PMacPlay(void);
-static void PMacRecord(void);
-static int PMacSetFormat(int format);
-static int PMacSetVolume(int volume);
-static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
-static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);
-static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
-static void awacs_write(int val);
-static int awacs_get_volume(int reg, int lshift);
-static int awacs_volume_setter(int volume, int n, int mute, int lshift);
-static void awacs_mksound(unsigned int hz, unsigned int ticks);
-static void awacs_nosound(unsigned long xx);
-#endif /* CONFIG_PPC */
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void);
-static void sound_init(void);
-static int sound_set_format(int format);
-static int sound_set_speed(int speed);
-static int sound_set_stereo(int stereo);
-static int sound_set_volume(int volume);
-#ifdef CONFIG_ATARI
-static int sound_set_bass(int bass);
-#endif /* CONFIG_ATARI */
-#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
-static int sound_set_treble(int treble);
-#endif /* CONFIG_ATARI || CONFIG_AMIGA */
-static ssize_t sound_copy_translate(const u_char *userPtr,
-				    size_t userCount,
-				    u_char frame[], ssize_t *frameUsed,
-				    ssize_t frameLeft);
-#ifdef CONFIG_PPC
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
-				    size_t userCount,
-				    u_char frame[], ssize_t *frameUsed,
-				    ssize_t frameLeft);
-#endif
-
-
-/*
- * /dev/mixer abstraction
- */
-
-struct sound_mixer {
-    int busy;
-    int modify_counter;
-};
-
-static struct sound_mixer mixer;
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-struct sound_queue {
-	int max_count, block_size;
-	char **buffers;
-	int max_active;
-
-	/* it shouldn't be necessary to declare any of these volatile */
-	int front, rear, count;
-	int rear_size;
-	/*
-	 *	The use of the playing field depends on the hardware
-	 *
-	 *	Atari, PMac: The number of frames that are loaded/playing
-	 *
-	 *	Amiga: Bit 0 is set: a frame is loaded
-	 *	       Bit 1 is set: a frame is playing
-	 */
-	int active;
-	wait_queue_head_t action_queue, open_queue, sync_queue;
-	int open_mode;
-	int busy, syncing;
-#ifdef CONFIG_ATARI
-	int ignore_int;		/* ++TeSche: used for Falcon */
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-	int block_size_half, block_size_quarter;
-#endif /* CONFIG_AMIGA */
-};
-
-static struct sound_queue sq;
-#ifdef CONFIG_PPC
-static struct sound_queue read_sq;
-#endif
-
-#define sq_block_address(i)	(sq.buffers[i])
-#define SIGNAL_RECEIVED	(signal_pending(current))
-#define NON_BLOCKING(open_mode)	(open_mode & O_NONBLOCK)
-#define ONE_SECOND	HZ	/* in jiffies (100ths of a second) */
-#define NO_TIME_LIMIT	0xffffffff
-#define SLEEP(queue, time_limit) \
-	interruptible_sleep_on_timeout(&queue, (time_limit));
-#define WAKE_UP(queue)	(wake_up_interruptible(&queue))
-
-/*
- * /dev/sndstat
- */
-
-struct sound_state {
-	int busy;
-	char buf[512];
-	int len, ptr;
-};
-
-static struct sound_state state;
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig);
-static inline int ioctl_return(int *addr, int value)
-{
-	if (value < 0)
-		return(value);
-
-	return put_user(value, addr);
-}
-
-
-/*** Config & Setup **********************************************************/
-
-
-void dmasound_init(void);
-static int dmasound_setup(char *str);
-
-
-/*** Translations ************************************************************/
-
-
-/* ++TeSche: radically changed for new expanding purposes...
- *
- * These two routines now deal with copying/expanding/translating the samples
- * from user space into our buffer at the right frequency. They take care about
- * how much data there's actually to read, how much buffer space there is and
- * to convert samples into the right frequency/encoding. They will only work on
- * complete samples so it may happen they leave some bytes in the input stream
- * if the user didn't write a multiple of the current sample size. They both
- * return the number of bytes they've used from both streams so you may detect
- * such a situation. Luckily all programs should be able to cope with that.
- *
- * I think I've optimized anything as far as one can do in plain C, all
- * variables should fit in registers and the loops are really short. There's
- * one loop for every possible situation. Writing a more generalized and thus
- * parameterized loop would only produce slower code. Feel free to optimize
- * this in assembler if you like. :)
- *
- * I think these routines belong here because they're not yet really hardware
- * independent, especially the fact that the Falcon can play 16bit samples
- * only in stereo is hardcoded in both of them!
- *
- * ++geert: split in even more functions (one per format)
- */
-
-#ifdef CONFIG_ATARI
-static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-	ssize_t count, used;
-	u_char *p = &frame[*frameUsed];
-
-	count = min(userCount, frameLeft);
-	if (sound.soft.stereo)
-		count &= ~1;
-	used = count;
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		*p++ = table[data];
-		count--;
-	}
-	*frameUsed += used;
-	return used;
-}
-
-
-static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
-			 u_char frame[], ssize_t *frameUsed,
-			 ssize_t frameLeft)
-{
-	ssize_t count, used;
-	void *p = &frame[*frameUsed];
-
-	count = min(userCount, frameLeft);
-	if (sound.soft.stereo)
-		count &= ~1;
-	used = count;
-	if (copy_from_user(p, userPtr, count))
-		return -EFAULT;
-	*frameUsed += used;
-	return(used);
-}
-
-
-static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
-			 u_char frame[], ssize_t *frameUsed,
-			 ssize_t frameLeft)
-{
-	ssize_t count, used;
-
-	if (!sound.soft.stereo) {
-		u_char *p = &frame[*frameUsed];
-		count = min(userCount, frameLeft);
-		used = count;
-		while (count > 0) {
-			u_char data;
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			*p++ = data ^ 0x80;
-			count--;
-		}
-	} else {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		count = min(userCount, frameLeft)>>1;
-		used = count*2;
-		while (count > 0) {
-			u_short data;
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			*p++ = data ^ 0x8080;
-			count--;
-		}
-	}
-	*frameUsed += used;
-	return(used);
-}
-
-
-static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	ssize_t count, used;
-
-	if (!sound.soft.stereo) {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		count = min(userCount, frameLeft)>>1;
-		used = count*2;
-		while (count > 0) {
-			u_short data;
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			*p++ = data;
-			*p++ = data;
-			count--;
-		}
-		*frameUsed += used*2;
-	} else {
-		void *p = (u_short *)&frame[*frameUsed];
-		count = min(userCount, frameLeft) & ~3;
-		used = count;
-		if (copy_from_user(p, userPtr, count))
-			return -EFAULT;
-		*frameUsed += used;
-	}
-	return(used);
-}
-
-
-static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	ssize_t count, used;
-
-	if (!sound.soft.stereo) {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		count = min(userCount, frameLeft)>>1;
-		used = count*2;
-		while (count > 0) {
-			u_short data;
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data ^= 0x8000;
-			*p++ = data;
-			*p++ = data;
-			count--;
-		}
-		*frameUsed += used*2;
-	} else {
-		u_long *p = (u_long *)&frame[*frameUsed];
-		count = min(userCount, frameLeft)>>2;
-		used = count*4;
-		while (count > 0) {
-			u_long data;
-			if (get_user(data, ((u_int *)userPtr)++))
-				return -EFAULT;
-			*p++ = data ^ 0x80008000;
-			count--;
-		}
-		*frameUsed += used;
-	}
-	return(used);
-}
-
-
-static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	ssize_t count, used;
-
-	count = frameLeft;
-	if (!sound.soft.stereo) {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		count = min(userCount, frameLeft)>>1;
-		used = count*2;
-		while (count > 0) {
-			u_short data;
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data = le2be16(data);
-			*p++ = data;
-			*p++ = data;
-			count--;
-		}
-		*frameUsed += used*2;
-	} else {
-		u_long *p = (u_long *)&frame[*frameUsed];
-		count = min(userCount, frameLeft)>>2;
-		used = count*4;
-		while (count > 0) {
-			u_long data;
-			if (get_user(data, ((u_int *)userPtr)++))
-				return -EFAULT;
-			data = le2be16dbl(data);
-			*p++ = data;
-			count--;
-		}
-		*frameUsed += used;
-	}
-	return(used);
-}
-
-
-static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	ssize_t count, used;
-
-	count = frameLeft;
-	if (!sound.soft.stereo) {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		count = min(userCount, frameLeft)>>1;
-		used = count*2;
-		while (count > 0) {
-			u_short data;
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data = le2be16(data) ^ 0x8000;
-			*p++ = data;
-			*p++ = data;
-		}
-		*frameUsed += used*2;
-	} else {
-		u_long *p = (u_long *)&frame[*frameUsed];
-		count = min(userCount, frameLeft)>>2;
-		used = count;
-		while (count > 0) {
-			u_long data;
-			if (get_user(data, ((u_int *)userPtr)++))
-				return -EFAULT;
-			data = le2be16dbl(data) ^ 0x80008000;
-			*p++ = data;
-			count--;
-		}
-		*frameUsed += used;
-	}
-	return(used);
-}
-
-
-static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-	/* this should help gcc to stuff everything into registers */
-	long bal = sound.bal;
-	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	ssize_t used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo) {
-		u_char *p = &frame[*frameUsed];
-		u_char data = sound.data;
-		while (frameLeft) {
-			u_char c;
-			if (bal < 0) {
-				if (!userCount)
-					break;
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = table[c];
-				userCount--;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			frameLeft--;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	} else {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		u_short data = sound.data;
-		while (frameLeft >= 2) {
-			u_char c;
-			if (bal < 0) {
-				if (userCount < 2)
-					break;
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = table[c] << 8;
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data |= table[c];
-				userCount -= 2;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			frameLeft -= 2;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	}
-	sound.bal = bal;
-	used -= userCount;
-	*frameUsed += usedf-frameLeft;
-	return(used);
-}
-
-
-static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	long bal = sound.bal;
-	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	ssize_t used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo) {
-		u_char *p = &frame[*frameUsed];
-		u_char data = sound.data;
-		while (frameLeft) {
-			if (bal < 0) {
-				if (!userCount)
-					break;
-				if (get_user(data, userPtr++))
-					return -EFAULT;
-				userCount--;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			frameLeft--;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	} else {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		u_short data = sound.data;
-		while (frameLeft >= 2) {
-			if (bal < 0) {
-				if (userCount < 2)
-					break;
-				if (get_user(data, ((u_short *)userPtr)++))
-					return -EFAULT;
-				userCount -= 2;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			frameLeft -= 2;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	}
-	sound.bal = bal;
-	used -= userCount;
-	*frameUsed += usedf-frameLeft;
-	return(used);
-}
-
-
-static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	long bal = sound.bal;
-	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	ssize_t used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo) {
-		u_char *p = &frame[*frameUsed];
-		u_char data = sound.data;
-		while (frameLeft) {
-			if (bal < 0) {
-				if (!userCount)
-					break;
-				if (get_user(data, userPtr++))
-					return -EFAULT;
-				data ^= 0x80;
-				userCount--;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			frameLeft--;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	} else {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		u_short data = sound.data;
-		while (frameLeft >= 2) {
-			if (bal < 0) {
-				if (userCount < 2)
-					break;
-				if (get_user(data, ((u_short *)userPtr)++))
-					return -EFAULT;
-				data ^= 0x8080;
-				userCount -= 2;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			frameLeft -= 2;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	}
-	sound.bal = bal;
-	used -= userCount;
-	*frameUsed += usedf-frameLeft;
-	return(used);
-}
-
-
-static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
-			     u_char frame[], ssize_t *frameUsed,
-			     ssize_t frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	long bal = sound.bal;
-	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	ssize_t used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo) {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		u_short data = sound.data;
-		while (frameLeft >= 4) {
-			if (bal < 0) {
-				if (userCount < 2)
-					break;
-				if (get_user(data, ((u_short *)userPtr)++))
-					return -EFAULT;
-				userCount -= 2;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			*p++ = data;
-			frameLeft -= 4;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	} else {
-		u_long *p = (u_long *)&frame[*frameUsed];
-		u_long data = sound.data;
-		while (frameLeft >= 4) {
-			if (bal < 0) {
-				if (userCount < 4)
-					break;
-				if (get_user(data, ((u_int *)userPtr)++))
-					return -EFAULT;
-				userCount -= 4;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			frameLeft -= 4;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	}
-	sound.bal = bal;
-	used -= userCount;
-	*frameUsed += usedf-frameLeft;
-	return(used);
-}
-
-
-static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
-			     u_char frame[], ssize_t *frameUsed,
-			     ssize_t frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	long bal = sound.bal;
-	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	ssize_t used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo) {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		u_short data = sound.data;
-		while (frameLeft >= 4) {
-			if (bal < 0) {
-				if (userCount < 2)
-					break;
-				if (get_user(data, ((u_short *)userPtr)++))
-					return -EFAULT;
-				data ^= 0x8000;
-				userCount -= 2;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			*p++ = data;
-			frameLeft -= 4;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	} else {
-		u_long *p = (u_long *)&frame[*frameUsed];
-		u_long data = sound.data;
-		while (frameLeft >= 4) {
-			if (bal < 0) {
-				if (userCount < 4)
-					break;
-				if (get_user(data, ((u_int *)userPtr)++))
-					return -EFAULT;
-				data ^= 0x80008000;
-				userCount -= 4;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			frameLeft -= 4;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	}
-	sound.bal = bal;
-	used -= userCount;
-	*frameUsed += usedf-frameLeft;
-	return(used);
-}
-
-
-static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
-			     u_char frame[], ssize_t *frameUsed,
-			     ssize_t frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	long bal = sound.bal;
-	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	ssize_t used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo) {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		u_short data = sound.data;
-		while (frameLeft >= 4) {
-			if (bal < 0) {
-				if (userCount < 2)
-					break;
-				if (get_user(data, ((u_short *)userPtr)++))
-					return -EFAULT;
-				data = le2be16(data);
-				userCount -= 2;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			*p++ = data;
-			frameLeft -= 4;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	} else {
-		u_long *p = (u_long *)&frame[*frameUsed];
-		u_long data = sound.data;
-		while (frameLeft >= 4) {
-			if (bal < 0) {
-				if (userCount < 4)
-					break;
-				if (get_user(data, ((u_int *)userPtr)++))
-					return -EFAULT;
-				data = le2be16dbl(data);
-				userCount -= 4;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			frameLeft -= 4;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	}
-	sound.bal = bal;
-	used -= userCount;
-	*frameUsed += usedf-frameLeft;
-	return(used);
-}
-
-
-static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
-			     u_char frame[], ssize_t *frameUsed,
-			     ssize_t frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	long bal = sound.bal;
-	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	ssize_t used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo) {
-		u_short *p = (u_short *)&frame[*frameUsed];
-		u_short data = sound.data;
-		while (frameLeft >= 4) {
-			if (bal < 0) {
-				if (userCount < 2)
-					break;
-				if (get_user(data, ((u_short *)userPtr)++))
-					return -EFAULT;
-				data = le2be16(data) ^ 0x8000;
-				userCount -= 2;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			*p++ = data;
-			frameLeft -= 4;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	} else {
-		u_long *p = (u_long *)&frame[*frameUsed];
-		u_long data = sound.data;
-		while (frameLeft >= 4) {
-			if (bal < 0) {
-				if (userCount < 4)
-					break;
-				if (get_user(data, ((u_int *)userPtr)++))
-					return -EFAULT;
-				data = le2be16dbl(data) ^ 0x80008000;
-				userCount -= 4;
-				bal += hSpeed;
-			}
-			*p++ = data;
-			frameLeft -= 4;
-			bal -= sSpeed;
-		}
-		sound.data = data;
-	}
-	sound.bal = bal;
-	used -= userCount;
-	*frameUsed += usedf-frameLeft;
-	return(used);
-}
-#endif /* CONFIG_ATARI */
-
-
-#ifdef CONFIG_AMIGA
-static ssize_t ami_ct_law(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-	ssize_t count, used;
-
-	if (!sound.soft.stereo) {
-		u_char *p = &frame[*frameUsed];
-		count = min(userCount, frameLeft) & ~1;
-		used = count;
-		while (count > 0) {
-			u_char data;
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			*p++ = table[data];
-			count--;
-		}
-	} else {
-		u_char *left = &frame[*frameUsed>>1];
-		u_char *right = left+sq.block_size_half;
-		count = min(userCount, frameLeft)>>1 & ~1;
-		used = count*2;
-		while (count > 0) {
-			u_char data;
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			*left++ = table[data];
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			*right++ = table[data];
-			count--;
-		}
-	}
-	*frameUsed += used;
-	return(used);
-}
-
-
-static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
-			 u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
-{
-	ssize_t count, used;
-
-	if (!sound.soft.stereo) {
-		void *p = &frame[*frameUsed];
-		count = min(userCount, frameLeft) & ~1;
-		used = count;
-		if (copy_from_user(p, userPtr, count))
-			return -EFAULT;
-	} else {
-		u_char *left = &frame[*frameUsed>>1];
-		u_char *right = left+sq.block_size_half;
-		count = min(userCount, frameLeft)>>1 & ~1;
-		used = count*2;
-		while (count > 0) {
-			if (get_user(*left++, userPtr++)
-			    || get_user(*right++, userPtr++))
-				return -EFAULT;
-			count--;
-		}
-	}
-	*frameUsed += used;
-	return(used);
-}
-
-
-static ssize_t ami_ct_u8(const u_char *userPtr, size_t userCount,
-			 u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
-{
-	ssize_t count, used;
-
-	if (!sound.soft.stereo) {
-		char *p = &frame[*frameUsed];
-		count = min(userCount, frameLeft) & ~1;
-		used = count;
-		while (count > 0) {
-			u_char data;
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			*p++ = data ^ 0x80;
-			count--;
-		}
-	} else {
-		u_char *left = &frame[*frameUsed>>1];
-		u_char *right = left+sq.block_size_half;
-		count = min(userCount, frameLeft)>>1 & ~1;
-		used = count*2;
-		while (count > 0) {
-			u_char data;
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			*left++ = data ^ 0x80;
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			*right++ = data ^ 0x80;
-			count--;
-		}
-	}
-	*frameUsed += used;
-	return(used);
-}
-
-
-static ssize_t ami_ct_s16be(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	ssize_t count, used;
-	u_short data;
-
-	if (!sound.soft.stereo) {
-		u_char *high = &frame[*frameUsed>>1];
-		u_char *low = high+sq.block_size_half;
-		count = min(userCount, frameLeft)>>1 & ~1;
-		used = count*2;
-		while (count > 0) {
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			*high++ = data>>8;
-			*low++ = (data>>2) & 0x3f;
-			count--;
-		}
-	} else {
-		u_char *lefth = &frame[*frameUsed>>2];
-		u_char *leftl = lefth+sq.block_size_quarter;
-		u_char *righth = lefth+sq.block_size_half;
-		u_char *rightl = righth+sq.block_size_quarter;
-		count = min(userCount, frameLeft)>>2 & ~1;
-		used = count*4;
-		while (count > 0) {
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			*lefth++ = data>>8;
-			*leftl++ = (data>>2) & 0x3f;
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			*righth++ = data>>8;
-			*rightl++ = (data>>2) & 0x3f;
-			count--;
-		}
-	}
-	*frameUsed += used;
-	return(used);
-}
-
-
-static ssize_t ami_ct_u16be(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	ssize_t count, used;
-	u_short data;
-
-	if (!sound.soft.stereo) {
-		u_char *high = &frame[*frameUsed>>1];
-		u_char *low = high+sq.block_size_half;
-		count = min(userCount, frameLeft)>>1 & ~1;
-		used = count*2;
-		while (count > 0) {
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data ^= 0x8000;
-			*high++ = data>>8;
-			*low++ = (data>>2) & 0x3f;
-			count--;
-		}
-	} else {
-		u_char *lefth = &frame[*frameUsed>>2];
-		u_char *leftl = lefth+sq.block_size_quarter;
-		u_char *righth = lefth+sq.block_size_half;
-		u_char *rightl = righth+sq.block_size_quarter;
-		count = min(userCount, frameLeft)>>2 & ~1;
-		used = count*4;
-		while (count > 0) {
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data ^= 0x8000;
-			*lefth++ = data>>8;
-			*leftl++ = (data>>2) & 0x3f;
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data ^= 0x8000;
-			*righth++ = data>>8;
-			*rightl++ = (data>>2) & 0x3f;
-			count--;
-		}
-	}
-	*frameUsed += used;
-	return(used);
-}
-
-
-static ssize_t ami_ct_s16le(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	ssize_t count, used;
-	u_short data;
-
-	if (!sound.soft.stereo) {
-		u_char *high = &frame[*frameUsed>>1];
-		u_char *low = high+sq.block_size_half;
-		count = min(userCount, frameLeft)>>1 & ~1;
-		used = count*2;
-		while (count > 0) {
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data = le2be16(data);
-			*high++ = data>>8;
-			*low++ = (data>>2) & 0x3f;
-			count--;
-		}
-	} else {
-		u_char *lefth = &frame[*frameUsed>>2];
-		u_char *leftl = lefth+sq.block_size_quarter;
-		u_char *righth = lefth+sq.block_size_half;
-		u_char *rightl = righth+sq.block_size_quarter;
-		count = min(userCount, frameLeft)>>2 & ~1;
-		used = count*4;
-		while (count > 0) {
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data = le2be16(data);
-			*lefth++ = data>>8;
-			*leftl++ = (data>>2) & 0x3f;
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data = le2be16(data);
-			*righth++ = data>>8;
-			*rightl++ = (data>>2) & 0x3f;
-			count--;
-		}
-	}
-	*frameUsed += used;
-	return(used);
-}
-
-
-static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	ssize_t count, used;
-	u_short data;
-
-	if (!sound.soft.stereo) {
-		u_char *high = &frame[*frameUsed>>1];
-		u_char *low = high+sq.block_size_half;
-		count = min(userCount, frameLeft)>>1 & ~1;
-		used = count*2;
-		while (count > 0) {
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data = le2be16(data) ^ 0x8000;
-			*high++ = data>>8;
-			*low++ = (data>>2) & 0x3f;
-			count--;
-		}
-	} else {
-		u_char *lefth = &frame[*frameUsed>>2];
-		u_char *leftl = lefth+sq.block_size_quarter;
-		u_char *righth = lefth+sq.block_size_half;
-		u_char *rightl = righth+sq.block_size_quarter;
-		count = min(userCount, frameLeft)>>2 & ~1;
-		used = count*4;
-		while (count > 0) {
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data = le2be16(data) ^ 0x8000;
-			*lefth++ = data>>8;
-			*leftl++ = (data>>2) & 0x3f;
-			if (get_user(data, ((u_short *)userPtr)++))
-				return -EFAULT;
-			data = le2be16(data) ^ 0x8000;
-			*righth++ = data>>8;
-			*rightl++ = (data>>2) & 0x3f;
-			count--;
-		}
-	}
-	*frameUsed += used;
-	return(used);
-}
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = table[data];
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = table[data];
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = data << 8;
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = data << 8;
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = (data ^ 0x80) << 8;
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = (data ^ 0x80) << 8;
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int stereo = sound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min(userCount, frameLeft);
-	if (!stereo) {
-		short *up = (short *) userPtr;
-		while (count > 0) {
-			short data;
-			if (get_user(data, up++))
-				return -EFAULT;
-			*fp++ = data;
-			*fp++ = data;
-			count--;
-		}
-	} else {
-		if (copy_from_user(fp, userPtr, count * 4))
-			return -EFAULT;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
-}
-
-static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-	int stereo = sound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-	short *up = (short *) userPtr;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		int data;
-		if (get_user(data, up++))
-			return -EFAULT;
-		data ^= mask;
-		*fp++ = data;
-		if (stereo) {
-			if (get_user(data, up++))
-				return -EFAULT;
-			data ^= mask;
-		}
-		*fp++ = data;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
-}
-
-
-static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	unsigned short *table = (unsigned short *)
-		(sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
-	unsigned int data = sound.data;
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	int bal = sound.bal;
-	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	int utotal, ftotal;
-	int stereo = sound.soft.stereo;
- 
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		u_char c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(c, userPtr++))
-				return -EFAULT;
-			data = table[c];
-			if (stereo) {
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = (data << 16) + table[c];
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	sound.bal = bal;
-	sound.data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = sound.data;
-	int bal = sound.bal;
-	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	int stereo = sound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		u_char c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(c, userPtr++))
-				return -EFAULT;
-			data = c << 8;
-			if (stereo) {
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = (data << 16) + (c << 8);
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	sound.bal = bal;
-	sound.data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = sound.data;
-	int bal = sound.bal;
-	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	int stereo = sound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		u_char c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(c, userPtr++))
-				return -EFAULT;
-			data = (c ^ 0x80) << 8;
-			if (stereo) {
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = (data << 16) + ((c ^ 0x80) << 8);
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	sound.bal = bal;
-	sound.data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = sound.data;
-	unsigned short *up = (unsigned short *) userPtr;
-	int bal = sound.bal;
-	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	int stereo = sound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		unsigned short c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(data, up++))
-				return -EFAULT;
-			if (stereo) {
-				if (get_user(c, up++))
-					return -EFAULT;
-				data = (data << 16) + c;
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	sound.bal = bal;
-	sound.data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 4: utotal * 2;
-}
-
-
-static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = sound.data;
-	unsigned short *up = (unsigned short *) userPtr;
-	int bal = sound.bal;
-	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	int stereo = sound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		unsigned short c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(data, up++))
-				return -EFAULT;
-			data ^= mask;
-			if (stereo) {
-				if (get_user(c, up++))
-					return -EFAULT;
-				data = (data << 16) + (c ^ mask);
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	sound.bal = bal;
-	sound.data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 4: utotal * 2;
-}
-
-static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-
-		val = *p++;
-		data = val >> 8;
-		if (put_user(data, (u_char *)userPtr++))
-			return -EFAULT;
-		if (stereo) {
-			val = *p;
-			data = val >> 8;
-			if (put_user(data, (u_char *)userPtr++))
-				return -EFAULT;
-		}
-		p++;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-
-		val = *p++;
-		data = (val >> 8) ^ 0x80;
-		if (put_user(data, (u_char *)userPtr++))
-			return -EFAULT;
-		if (stereo) {
-			val = *p;
-			data = (val >> 8) ^ 0x80;
-			if (put_user(data, (u_char *)userPtr++))
-				return -EFAULT;
-		}
-		p++;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int stereo = sound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min(userCount, frameLeft);
-	if (!stereo) {
-		short *up = (short *) userPtr;
-		while (count > 0) {
-			short data;
-			data = *fp;
-			if (put_user(data, up++))
-				return -EFAULT;
-			fp+=2;
-			count--;
-		}
-	} else {
-		if (copy_to_user((u_char *)userPtr, fp, count * 4))
-			return -EFAULT;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
-}
-
-static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-	int stereo = sound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-	short *up = (short *) userPtr;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		int data;
-
-		data = *fp++;
-		data ^= mask;
-		if (put_user(data, up++))
-			return -EFAULT;
-		if (stereo) {
-			data = *fp;
-			data ^= mask;
-			if (put_user(data, up++))
-				return -EFAULT;
-		}
-		fp++;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
-}
-
-
-#endif /* CONFIG_PPC */
-
-
-#ifdef CONFIG_ATARI
-static TRANS transTTNormal = {
-	ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
-};
-
-static TRANS transTTExpanding = {
-	ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
-};
-
-static TRANS transFalconNormal = {
-	ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8,
-	ata_ct_s16be, ata_ct_u16be, ata_ct_s16le, ata_ct_u16le
-};
-
-static TRANS transFalconExpanding = {
-	ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8,
-	ata_ctx_s16be, ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
-};
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static TRANS transAmiga = {
-	ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8,
-	ami_ct_s16be, ami_ct_u16be, ami_ct_s16le, ami_ct_u16le
-};
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static TRANS transAwacsNormal = {
-	pmac_ct_law, pmac_ct_law, pmac_ct_s8, pmac_ct_u8,
-	pmac_ct_s16, pmac_ct_u16, pmac_ct_s16, pmac_ct_u16
-};
-
-static TRANS transAwacsExpand = {
-	pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8,
-	pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16
-};
-
-static TRANS transAwacsNormalRead = {
-	NULL, NULL, pmac_ct_s8_read, pmac_ct_u8_read,
-	pmac_ct_s16_read, pmac_ct_u16_read, pmac_ct_s16_read, pmac_ct_u16_read
-};
-#endif /* CONFIG_PPC */
-
-/*** Low level stuff *********************************************************/
-
-
-#ifdef CONFIG_ATARI
-
-/*
- * Atari (TT/Falcon)
- */
-
-static void *AtaAlloc(unsigned int size, int flags)
-{
-	return( atari_stram_alloc( size, NULL, "dmasound" ));
-}
-
-static void AtaFree(void *obj, unsigned int size)
-{
-	atari_stram_free( obj );
-}
-
-static int __init AtaIrqInit(void)
-{
-	/* Set up timer A. Timer A
-	   will receive a signal upon end of playing from the sound
-	   hardware. Furthermore Timer A is able to count events
-	   and will cause an interrupt after a programmed number
-	   of events. So all we need to keep the music playing is
-	   to provide the sound hardware with new data upon
-	   an interrupt from timer A. */
-	mfp.tim_ct_a = 0;	/* ++roman: Stop timer before programming! */
-	mfp.tim_dt_a = 1;	/* Cause interrupt after first event. */
-	mfp.tim_ct_a = 8;	/* Turn on event counting. */
-	/* Register interrupt handler. */
-	request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
-		    "DMA sound", ata_sq_interrupt);
-	mfp.int_en_a |= 0x20;	/* Turn interrupt on. */
-	mfp.int_mk_a |= 0x20;
-	return(1);
-}
-
-#ifdef MODULE
-static void AtaIrqCleanUp(void)
-{
-	mfp.tim_ct_a = 0;	/* stop timer */
-	mfp.int_en_a &= ~0x20;	/* turn interrupt off */
-	free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
-}
-#endif /* MODULE */
-
-
-#define TONE_VOXWARE_TO_DB(v) \
-	(((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25)
-#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)
-
-
-static int AtaSetBass(int bass)
-{
-	sound.bass = TONE_VOXWARE_TO_DB(bass);
-	atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
-	return(TONE_DB_TO_VOXWARE(sound.bass));
-}
-
-
-static int AtaSetTreble(int treble)
-{
-	sound.treble = TONE_VOXWARE_TO_DB(treble);
-	atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
-	return(TONE_DB_TO_VOXWARE(sound.treble));
-}
-
-
-
-/*
- * TT
- */
-
-
-static void TTSilence(void)
-{
-	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-	atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
-}
-
-
-static void TTInit(void)
-{
-	int mode, i, idx;
-	const int freq[4] = {50066, 25033, 12517, 6258};
-
-	/* search a frequency that fits into the allowed error range */
-
-	idx = -1;
-	for (i = 0; i < arraysize(freq); i++)
-		/* this isn't as much useful for a TT than for a Falcon, but
-		 * then it doesn't hurt very much to implement it for a TT too.
-		 */
-		if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
-			idx = i;
-	if (idx > -1) {
-		sound.soft.speed = freq[idx];
-		sound.trans = &transTTNormal;
-	} else
-		sound.trans = &transTTExpanding;
-
-	TTSilence();
-	sound.hard = sound.soft;
-
-	if (sound.hard.speed > 50066) {
-		/* we would need to squeeze the sound, but we won't do that */
-		sound.hard.speed = 50066;
-		mode = DMASND_MODE_50KHZ;
-		sound.trans = &transTTNormal;
-	} else if (sound.hard.speed > 25033) {
-		sound.hard.speed = 50066;
-		mode = DMASND_MODE_50KHZ;
-	} else if (sound.hard.speed > 12517) {
-		sound.hard.speed = 25033;
-		mode = DMASND_MODE_25KHZ;
-	} else if (sound.hard.speed > 6258) {
-		sound.hard.speed = 12517;
-		mode = DMASND_MODE_12KHZ;
-	} else {
-		sound.hard.speed = 6258;
-		mode = DMASND_MODE_6KHZ;
-	}
-
-	tt_dmasnd.mode = (sound.hard.stereo ?
-			  DMASND_MODE_STEREO : DMASND_MODE_MONO) |
-		DMASND_MODE_8BIT | mode;
-
-	sound.bal = -sound.soft.speed;
-}
-
-
-static int TTSetFormat(int format)
-{
-	/* TT sound DMA supports only 8bit modes */
-
-	switch (format) {
-	case AFMT_QUERY:
-		return(sound.soft.format);
-	case AFMT_MU_LAW:
-	case AFMT_A_LAW:
-	case AFMT_S8:
-	case AFMT_U8:
-		break;
-	default:
-		format = AFMT_S8;
-	}
-
-	sound.soft.format = format;
-	sound.soft.size = 8;
-	if (sound.minDev == SND_DEV_DSP) {
-		sound.dsp.format = format;
-		sound.dsp.size = 8;
-	}
-	TTInit();
-
-	return(format);
-}
-
-
-#define VOLUME_VOXWARE_TO_DB(v) \
-	(((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
-#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
-
-
-static int TTSetVolume(int volume)
-{
-	sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
-	atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
-	sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
-	atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
-	return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
-	       (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
-}
-
-
-#define GAIN_VOXWARE_TO_DB(v) \
-	(((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80)
-#define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4)
-
-static int TTSetGain(int gain)
-{
-	sound.gain = GAIN_VOXWARE_TO_DB(gain);
-	atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain));
-	return GAIN_DB_TO_VOXWARE(sound.gain);
-}
-
-
-
-/*
- * Falcon
- */
-
-
-static void FalconSilence(void)
-{
-	/* stop playback, set sample rate 50kHz for PSG sound */
-	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-	tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
-	tt_dmasnd.int_div = 0; /* STE compatible divider */
-	tt_dmasnd.int_ctrl = 0x0;
-	tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
-	tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
-	tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
-	tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
-}
-
-
-static void FalconInit(void)
-{
-	int divider, i, idx;
-	const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
-
-	/* search a frequency that fits into the allowed error range */
-
-	idx = -1;
-	for (i = 0; i < arraysize(freq); i++)
-		/* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
-		 * be playable without expanding, but that now a kernel runtime
-		 * option
-		 */
-		if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
-			idx = i;
-	if (idx > -1) {
-		sound.soft.speed = freq[idx];
-		sound.trans = &transFalconNormal;
-	} else
-		sound.trans = &transFalconExpanding;
-
-	FalconSilence();
-	sound.hard = sound.soft;
-
-	if (sound.hard.size == 16) {
-		/* the Falcon can play 16bit samples only in stereo */
-		sound.hard.stereo = 1;
-	}
-
-	if (sound.hard.speed > 49170) {
-		/* we would need to squeeze the sound, but we won't do that */
-		sound.hard.speed = 49170;
-		divider = 1;
-		sound.trans = &transFalconNormal;
-	} else if (sound.hard.speed > 32780) {
-		sound.hard.speed = 49170;
-		divider = 1;
-	} else if (sound.hard.speed > 24585) {
-		sound.hard.speed = 32780;
-		divider = 2;
-	} else if (sound.hard.speed > 19668) {
-		sound.hard.speed = 24585;
-		divider = 3;
-	} else if (sound.hard.speed > 16390) {
-		sound.hard.speed = 19668;
-		divider = 4;
-	} else if (sound.hard.speed > 12292) {
-		sound.hard.speed = 16390;
-		divider = 5;
-	} else if (sound.hard.speed > 9834) {
-		sound.hard.speed = 12292;
-		divider = 7;
-	} else if (sound.hard.speed > 8195) {
-		sound.hard.speed = 9834;
-		divider = 9;
-	} else {
-		sound.hard.speed = 8195;
-		divider = 11;
-	}
-	tt_dmasnd.int_div = divider;
-
-	/* Setup Falcon sound DMA for playback */
-	tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
-	tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
-	tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
-	tt_dmasnd.cbar_dst = 0x0000;
-	tt_dmasnd.rec_track_select = 0;
-	tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
-	tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
-
-	tt_dmasnd.mode = (sound.hard.stereo ?
-			  DMASND_MODE_STEREO : DMASND_MODE_MONO) |
-		((sound.hard.size == 8) ?
-		 DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
-		DMASND_MODE_6KHZ;
-
-	sound.bal = -sound.soft.speed;
-}
-
-
-static int FalconSetFormat(int format)
-{
-	int size;
-	/* Falcon sound DMA supports 8bit and 16bit modes */
-
-	switch (format) {
-	case AFMT_QUERY:
-		return(sound.soft.format);
-	case AFMT_MU_LAW:
-	case AFMT_A_LAW:
-	case AFMT_U8:
-	case AFMT_S8:
-		size = 8;
-		break;
-	case AFMT_S16_BE:
-	case AFMT_U16_BE:
-	case AFMT_S16_LE:
-	case AFMT_U16_LE:
-		size = 16;
-		break;
-	default: /* :-) */
-		size = 8;
-		format = AFMT_S8;
-	}
-
-	sound.soft.format = format;
-	sound.soft.size = size;
-	if (sound.minDev == SND_DEV_DSP) {
-		sound.dsp.format = format;
-		sound.dsp.size = sound.soft.size;
-	}
-
-	FalconInit();
-
-	return(format);
-}
-
-
-/* This is for the Falcon output *attenuation* in 1.5dB steps,
- * i.e. output level from 0 to -22.5dB in -1.5dB steps.
- */
-#define VOLUME_VOXWARE_TO_ATT(v) \
-	((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)
-#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)
-
-
-static int FalconSetVolume(int volume)
-{
-	sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
-	sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
-	tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
-	return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
-	       VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
-}
-
-
-static void ata_sq_play_next_frame(int index)
-{
-	char *start, *end;
-
-	/* used by AtaPlay() if all doubts whether there really is something
-	 * to be played are already wiped out.
-	 */
-	start = sq_block_address(sq.front);
-	end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
-	/* end might not be a legal virtual address. */
-	DMASNDSetEnd(virt_to_phys(end - 1) + 1);
-	DMASNDSetBase(virt_to_phys(start));
-	/* Since only an even number of samples per frame can
-	   be played, we might lose one byte here. (TO DO) */
-	sq.front = (sq.front+1) % sq.max_count;
-	sq.active++;
-	tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
-}
-
-
-static void AtaPlay(void)
-{
-	/* ++TeSche: Note that sq.active is no longer just a flag but holds
-	 * the number of frames the DMA is currently programmed for instead,
-	 * may be 0, 1 (currently being played) or 2 (pre-programmed).
-	 *
-	 * Changes done to sq.count and sq.active are a bit more subtle again
-	 * so now I must admit I also prefer disabling the irq here rather
-	 * than considering all possible situations. But the point is that
-	 * disabling the irq doesn't have any bad influence on this version of
-	 * the driver as we benefit from having pre-programmed the DMA
-	 * wherever possible: There's no need to reload the DMA at the exact
-	 * time of an interrupt but only at some time while the pre-programmed
-	 * frame is playing!
-	 */
-	atari_disable_irq(IRQ_MFP_TIMA);
-
-	if (sq.active == 2 ||	/* DMA is 'full' */
-	    sq.count <= 0) {	/* nothing to do */
-		atari_enable_irq(IRQ_MFP_TIMA);
-		return;
-	}
-
-	if (sq.active == 0) {
-		/* looks like there's nothing 'in' the DMA yet, so try
-		 * to put two frames into it (at least one is available).
-		 */
-		if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
-			/* hmmm, the only existing frame is not
-			 * yet filled and we're not syncing?
-			 */
-			atari_enable_irq(IRQ_MFP_TIMA);
-			return;
-		}
-		ata_sq_play_next_frame(1);
-		if (sq.count == 1) {
-			/* no more frames */
-			atari_enable_irq(IRQ_MFP_TIMA);
-			return;
-		}
-		if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
-			/* hmmm, there were two frames, but the second
-			 * one is not yet filled and we're not syncing?
-			 */
-			atari_enable_irq(IRQ_MFP_TIMA);
-			return;
-		}
-		ata_sq_play_next_frame(2);
-	} else {
-		/* there's already a frame being played so we may only stuff
-		 * one new into the DMA, but even if this may be the last
-		 * frame existing the previous one is still on sq.count.
-		 */
-		if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
-			/* hmmm, the only existing frame is not
-			 * yet filled and we're not syncing?
-			 */
-			atari_enable_irq(IRQ_MFP_TIMA);
-			return;
-		}
-		ata_sq_play_next_frame(2);
-	}
-	atari_enable_irq(IRQ_MFP_TIMA);
-}
-
-
-static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
-#if 0
-	/* ++TeSche: if you should want to test this... */
-	static int cnt = 0;
-	if (sq.active == 2)
-		if (++cnt == 10) {
-			/* simulate losing an interrupt */
-			cnt = 0;
-			return;
-		}
-#endif
-
-	if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
-		/* ++TeSche: Falcon only: ignore first irq because it comes
-		 * immediately after starting a frame. after that, irqs come
-		 * (almost) like on the TT.
-		 */
-		sq.ignore_int = 0;
-		return;
-	}
-
-	if (!sq.active) {
-		/* playing was interrupted and sq_reset() has already cleared
-		 * the sq variables, so better don't do anything here.
-		 */
-		WAKE_UP(sq.sync_queue);
-		return;
-	}
-
-	/* Probably ;) one frame is finished. Well, in fact it may be that a
-	 * pre-programmed one is also finished because there has been a long
-	 * delay in interrupt delivery and we've completely lost one, but
-	 * there's no way to detect such a situation. In such a case the last
-	 * frame will be played more than once and the situation will recover
-	 * as soon as the irq gets through.
-	 */
-	sq.count--;
-	sq.active--;
-
-	if (!sq.active) {
-		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-		sq.ignore_int = 1;
-	}
-
-	WAKE_UP(sq.action_queue);
-	/* At least one block of the queue is free now
-	   so wake up a writing process blocked because
-	   of a full queue. */
-
-	if ((sq.active != 1) || (sq.count != 1))
-		/* We must be a bit carefully here: sq.count indicates the
-		 * number of buffers used and not the number of frames to
-		 * be played. If sq.count==1 and sq.active==1 that means
-		 * the only remaining frame was already programmed earlier
-		 * (and is currently running) so we mustn't call AtaPlay()
-		 * here, otherwise we'll play one frame too much.
-		 */
-		AtaPlay();
-
-	if (!sq.active) WAKE_UP(sq.sync_queue);
-	/* We are not playing after AtaPlay(), so there
-	   is nothing to play any more. Wake up a process
-	   waiting for audio output to drain. */
-}
-#endif /* CONFIG_ATARI */
-
-
-#ifdef CONFIG_AMIGA
-
-/*
- * Amiga
- */
-
-#define StopDMA() custom.aud[0].audvol = custom.aud[1].audvol = 0; \
-		custom.aud[2].audvol = custom.aud[3].audvol = 0; \
-		custom.dmacon = AMI_AUDIO_OFF;
-
-static void *AmiAlloc(unsigned int size, int flags)
-{
-	return amiga_chip_alloc((long)size, "dmasound");
-}
-
-static void AmiFree(void *obj, unsigned int size)
-{
-	amiga_chip_free (obj);
-}
-
-static int __init AmiIrqInit(void)
-{
-	/* turn off DMA for audio channels */
-	StopDMA();
-
-	/* Register interrupt handler. */
-	if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
-			"DMA sound", ami_sq_interrupt))
-		return(0);
-	return(1);
-}
-
-#ifdef MODULE
-static void AmiIrqCleanUp(void)
-{
-	/* turn off DMA for audio channels */
-	StopDMA();
-	/* release the interrupt */
-	free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
-}
-#endif /* MODULE */
-
-static void AmiSilence(void)
-{
-	/* turn off DMA for audio channels */
-	StopDMA();
-}
-
-
-static void AmiInit(void)
-{
-	int period, i;
-
-	AmiSilence();
-
-	if (sound.soft.speed)
-		period = amiga_colorclock/sound.soft.speed-1;
-	else
-		period = amiga_audio_min_period;
-	sound.hard = sound.soft;
-	sound.trans = &transAmiga;
-
-	if (period < amiga_audio_min_period) {
-		/* we would need to squeeze the sound, but we won't do that */
-		period = amiga_audio_min_period;
-	} else if (period > 65535) {
-		period = 65535;
-	}
-	sound.hard.speed = amiga_colorclock/(period+1);
-
-	for (i = 0; i < 4; i++)
-		custom.aud[i].audper = period;
-	amiga_audio_period = period;
-
-	AmiSetTreble(50);  /* recommended for newer amiga models */
-}
-
-
-static int AmiSetFormat(int format)
-{
-	int size;
-
-	/* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
-
-	switch (format) {
-	case AFMT_QUERY:
-		return(sound.soft.format);
-	case AFMT_MU_LAW:
-	case AFMT_A_LAW:
-	case AFMT_U8:
-	case AFMT_S8:
-		size = 8;
-		break;
-	case AFMT_S16_BE:
-	case AFMT_U16_BE:
-	case AFMT_S16_LE:
-	case AFMT_U16_LE:
-		size = 16;
-		break;
-	default: /* :-) */
-		size = 8;
-		format = AFMT_S8;
-	}
-
-	sound.soft.format = format;
-	sound.soft.size = size;
-	if (sound.minDev == SND_DEV_DSP) {
-		sound.dsp.format = format;
-		sound.dsp.size = sound.soft.size;
-	}
-	AmiInit();
-
-	return(format);
-}
-
-
-#define VOLUME_VOXWARE_TO_AMI(v) \
-	(((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
-#define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
-
-static int AmiSetVolume(int volume)
-{
-	sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
-	custom.aud[0].audvol = sound.volume_left;
-	sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
-	custom.aud[1].audvol = sound.volume_right;
-	if (sound.hard.size == 16) {
-		if (sound.volume_left == 64 && sound.volume_right == 64) {
-			custom.aud[2].audvol = 1;
-			custom.aud[3].audvol = 1;
-		} else {
-			custom.aud[2].audvol = 0;
-			custom.aud[3].audvol = 0;
-		}
-	}
-	return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
-	       (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
-}
-
-static int AmiSetTreble(int treble)
-{
-	sound.treble = treble;
-	if (treble < 50)
-		ciaa.pra &= ~0x02;
-	else
-		ciaa.pra |= 0x02;
-	return(treble);
-}
-
-
-#define AMI_PLAY_LOADED		1
-#define AMI_PLAY_PLAYING	2
-#define AMI_PLAY_MASK		3
-
-
-static void ami_sq_play_next_frame(int index)
-{
-	u_char *start, *ch0, *ch1, *ch2, *ch3;
-	u_long size;
-
-	/* used by AmiPlay() if all doubts whether there really is something
-	 * to be played are already wiped out.
-	 */
-	start = sq_block_address(sq.front);
-	size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
-
-	if (sound.hard.stereo) {
-		ch0 = start;
-		ch1 = start+sq.block_size_half;
-		size >>= 1;
-	} else {
-		ch0 = start;
-		ch1 = start;
-	}
-
-	custom.aud[0].audvol = sound.volume_left;
-	custom.aud[1].audvol = sound.volume_right;
-	if (sound.hard.size == 8) {
-		custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
-		custom.aud[0].audlen = size;
-		custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
-		custom.aud[1].audlen = size;
-		custom.dmacon = AMI_AUDIO_8;
-	} else {
-		size >>= 1;
-		custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
-		custom.aud[0].audlen = size;
-		custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
-		custom.aud[1].audlen = size;
-		if (sound.volume_left == 64 && sound.volume_right == 64) {
-			/* We can play pseudo 14-bit only with the maximum volume */
-			ch3 = ch0+sq.block_size_quarter;
-			ch2 = ch1+sq.block_size_quarter;
-			custom.aud[2].audvol = 1;  /* we are being affected by the beeps */
-			custom.aud[3].audvol = 1;  /* restoring volume here helps a bit */
-			custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
-			custom.aud[2].audlen = size;
-			custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
-			custom.aud[3].audlen = size;
-			custom.dmacon = AMI_AUDIO_14;
-		} else {
-			custom.aud[2].audvol = 0;
-			custom.aud[3].audvol = 0;
-			custom.dmacon = AMI_AUDIO_8;
-		}
-	}
-	sq.front = (sq.front+1) % sq.max_count;
-	sq.active |= AMI_PLAY_LOADED;
-}
-
-
-static void AmiPlay(void)
-{
-	int minframes = 1;
-
-	custom.intena = IF_AUD0;
-
-	if (sq.active & AMI_PLAY_LOADED) {
-		/* There's already a frame loaded */
-		custom.intena = IF_SETCLR | IF_AUD0;
-		return;
-	}
-
-	if (sq.active & AMI_PLAY_PLAYING)
-		/* Increase threshold: frame 1 is already being played */
-		minframes = 2;
-
-	if (sq.count < minframes) {
-		/* Nothing to do */
-		custom.intena = IF_SETCLR | IF_AUD0;
-		return;
-	}
-
-	if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
-		/* hmmm, the only existing frame is not
-		 * yet filled and we're not syncing?
-		 */
-		custom.intena = IF_SETCLR | IF_AUD0;
-		return;
-	}
-
-	ami_sq_play_next_frame(minframes);
-
-	custom.intena = IF_SETCLR | IF_AUD0;
-}
-
-
-static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
-	int minframes = 1;
-
-	custom.intena = IF_AUD0;
-
-	if (!sq.active) {
-		/* Playing was interrupted and sq_reset() has already cleared
-		 * the sq variables, so better don't do anything here.
-		 */
-		WAKE_UP(sq.sync_queue);
-		return;
-	}
-
-	if (sq.active & AMI_PLAY_PLAYING) {
-		/* We've just finished a frame */
-		sq.count--;
-		WAKE_UP(sq.action_queue);
-	}
-
-	if (sq.active & AMI_PLAY_LOADED)
-		/* Increase threshold: frame 1 is already being played */
-		minframes = 2;
-
-	/* Shift the flags */
-	sq.active = (sq.active<<1) & AMI_PLAY_MASK;
-
-	if (!sq.active)
-		/* No frame is playing, disable audio DMA */
-		StopDMA();
-
-	custom.intena = IF_SETCLR | IF_AUD0;
-
-	if (sq.count >= minframes)
-		/* Try to play the next frame */
-		AmiPlay();
-
-	if (!sq.active)
-		/* Nothing to play anymore.
-		   Wake up a process waiting for audio output to drain. */
-		WAKE_UP(sq.sync_queue);
-}
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-
-/*
- * PCI PowerMac, with AWACS and DBDMA.
- */
-
-static void *PMacAlloc(unsigned int size, int flags)
-{
-	return kmalloc(size, flags);
-}
-
-static void PMacFree(void *ptr, unsigned int size)
-{
-	kfree(ptr);
-}
-
-static int __init PMacIrqInit(void)
-{
-	if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
-	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0)
-	    || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0))
-		return 0;
-	return 1;
-}
-
-#ifdef MODULE
-static void PMacIrqCleanup(void)
-{
-	/* turn off output dma */
-	out_le32(&awacs_txdma->control, RUN<<16);
-	/* disable interrupts from awacs interface */
-	out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
-#ifdef CONFIG_PMAC_PBOOK
-	if (is_pbook_G3) {
-		feature_clear(awacs_node, FEATURE_Sound_power);
-		feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
-	}
-#endif
-	free_irq(awacs_irq, 0);
-	free_irq(awacs_tx_irq, 0);
-	free_irq(awacs_rx_irq, 0);
-	kfree(awacs_tx_cmd_space);
-	if (awacs_rx_cmd_space)
-		kfree(awacs_rx_cmd_space);
-	if (beep_buf)
-		kfree(beep_buf);
-	kd_mksound = orig_mksound;
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
-#endif
-}
-#endif /* MODULE */
-
-static void PMacSilence(void)
-{
-	/* turn off output dma */
-	out_le32(&awacs_txdma->control, RUN<<16);
-}
-
-static int awacs_freqs[8] = {
-	44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
-};
-static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
-
-static void PMacInit(void)
-{
-	int i, tolerance;
-
-	switch (sound.soft.format) {
-	case AFMT_S16_LE:
-	case AFMT_U16_LE:
-		sound.hard.format = AFMT_S16_LE;
-		break;
-	default:
-		sound.hard.format = AFMT_S16_BE;
-		break;
-	}
-	sound.hard.stereo = 1;
-	sound.hard.size = 16;
-
-	/*
-	 * If we have a sample rate which is within catchRadius percent
-	 * of the requested value, we don't have to expand the samples.
-	 * Otherwise choose the next higher rate.
-	 * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz.
-	 */
-	i = 8;
-	do {
-		tolerance = catchRadius * awacs_freqs[--i] / 100;
-		if (awacs_freqs_ok[i]
-		    && sound.soft.speed <= awacs_freqs[i] + tolerance)
-			break;
-	} while (i > 0);
-	if (sound.soft.speed >= awacs_freqs[i] - tolerance)
-		sound.trans = &transAwacsNormal;
-	else
-		sound.trans = &transAwacsExpand;
-	sound.read_trans = &transAwacsNormalRead;
-	sound.hard.speed = awacs_freqs[i];
-	awacs_rate_index = i;
-
-	/* XXX disable error interrupt on burgundy for now */
-	out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11
-		 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
-	awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
-	awacs_write(awacs_reg[1] | MASK_ADDR1);
-	out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
-
-	/* We really want to execute a DMA stop command, after the AWACS
-	 * is initialized.
-	 * For reasons I don't understand, it stops the hissing noise
-	 * common to many PowerBook G3 systems (like mine :-).
-	 */
-	out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
-	st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
-	out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
-	out_le32(&awacs_txdma->control, RUN | (RUN << 16));
-
-	sound.bal = -sound.soft.speed;
-}
-
-static int PMacSetFormat(int format)
-{
-	int size;
-
-	switch (format) {
-	case AFMT_QUERY:
-		return sound.soft.format;
-	case AFMT_MU_LAW:
-	case AFMT_A_LAW:
-	case AFMT_U8:
-	case AFMT_S8:
-		size = 8;
-		break;
-	case AFMT_S16_BE:
-	case AFMT_U16_BE:
-	case AFMT_S16_LE:
-	case AFMT_U16_LE:
-		size = 16;
-		break;
-	default: /* :-) */
-		printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
-		       format);
-		size = 8;
-		format = AFMT_U8;
-	}
-
-	sound.soft.format = format;
-	sound.soft.size = size;
-	if (sound.minDev == SND_DEV_DSP) {
-		sound.dsp.format = format;
-		sound.dsp.size = size;
-	}
-
-	PMacInit();
-
-	return format;
-}
-
-#define AWACS_VOLUME_TO_MASK(x)	(15 - ((((x) - 1) * 15) / 99))
-#define AWACS_MASK_TO_VOLUME(y)	(100 - ((y) * 99 / 15))
-
-static int awacs_get_volume(int reg, int lshift)
-{
-	int volume;
-
-	volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
-	volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
-	return volume;
-}
-
-static int awacs_volume_setter(int volume, int n, int mute, int lshift)
-{
-	int r1, rn;
-
-	if (mute && volume == 0) {
-		r1 = awacs_reg[1] | mute;
-	} else {
-		r1 = awacs_reg[1] & ~mute;
-		rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
-		rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
-		rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
-		awacs_reg[n] = rn;
-		awacs_write((n << 12) | rn);
-		volume = awacs_get_volume(rn, lshift);
-	}
-	if (r1 != awacs_reg[1]) {
-		awacs_reg[1] = r1;
-		awacs_write(r1 | MASK_ADDR1);
-	}
-	return volume;
-}
-
-static int PMacSetVolume(int volume)
-{
-	return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);
-}
-
-static void PMacPlay(void)
-{
-	volatile struct dbdma_cmd *cp;
-	int i, count;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	if (awacs_beep_state) {
-		/* sound takes precedence over beeps */
-		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
-		out_le32(&awacs->control,
-			 (in_le32(&awacs->control) & ~0x1f00)
-			 | (awacs_rate_index << 8));
-		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
-		out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count])));
-
-		beep_playing = 0;
-		awacs_beep_state = 0;
-	}
-	i = sq.front + sq.active;
-	if (i >= sq.max_count)
-		i -= sq.max_count;
-	while (sq.active < 2 && sq.active < sq.count) {
-		count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size;
-		if (count < sq.block_size && !sq.syncing)
-			/* last block not yet filled, and we're not syncing. */
-			break;
-		cp = &awacs_tx_cmds[i];
-		st_le16(&cp->req_count, count);
-		st_le16(&cp->xfer_status, 0);
-		if (++i >= sq.max_count)
-			i = 0;
-		out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
-		out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
-		if (sq.active == 0)
-			out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
-		out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
-		++sq.active;
-	}
-	restore_flags(flags);
-}
-
-
-static void PMacRecord(void)
-{
-	unsigned long flags;
-
-	if (read_sq.active)
-		return;
-
-	save_flags(flags); cli();
-
-	/* This is all we have to do......Just start it up.
-	*/
-	out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
-	read_sq.active = 1;
-
-        restore_flags(flags);
-}
-
-
-static void
-pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
-{
-	int i = sq.front;
-	int stat;
-	volatile struct dbdma_cmd *cp;
-
-	while (sq.active > 0) {
-		cp = &awacs_tx_cmds[i];
-		stat = ld_le16(&cp->xfer_status);
-		if ((stat & ACTIVE) == 0)
-			break;	/* this frame is still going */
-		--sq.count;
-		--sq.active;
-		if (++i >= sq.max_count)
-			i = 0;
-	}
-	if (i != sq.front)
-		WAKE_UP(sq.action_queue);
-	sq.front = i;
-
-	PMacPlay();
-
-	if (!sq.active)
-		WAKE_UP(sq.sync_queue);
-}
-
-
-static void
-pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
-{
-
-	/* For some reason on my PowerBook G3, I get one interrupt
-	 * when the interrupt vector is installed (like something is
-	 * pending).  This happens before the dbdma is initialize by
-	 * us, so I just check the command pointer and if it is zero,
-	 * just blow it off.
-	 */
-	if (in_le32(&awacs_rxdma->cmdptr) == 0)
-		return;
-	
-	/* We also want to blow 'em off when shutting down.
-	*/
-	if (read_sq.active == 0)
-		return;
-
-	/* Check multiple buffers in case we were held off from
-	 * interrupt processing for a long time.  Geeze, I really hope
-	 * this doesn't happen.
-	 */
-	while (awacs_rx_cmds[read_sq.rear].xfer_status) {
-
-		/* Clear status and move on to next buffer.
-		*/
-		awacs_rx_cmds[read_sq.rear].xfer_status = 0;
-		read_sq.rear++;
-
-		/* Wrap the buffer ring.
-		*/
-		if (read_sq.rear >= read_sq.max_active)
-			read_sq.rear = 0;
-
-		/* If we have caught up to the front buffer, bump it.
-		 * This will cause weird (but not fatal) results if the
-		 * read loop is currently using this buffer.  The user is
-		 * behind in this case anyway, so weird things are going
-		 * to happen.
-		 */
-		if (read_sq.rear == read_sq.front) {
-			read_sq.front++;
-			if (read_sq.front >= read_sq.max_active)
-				read_sq.front = 0;
-		}
-	}
-
-	WAKE_UP(read_sq.action_queue);
-}
-
-
-static void
-pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
-{
-	int ctrl = in_le32(&awacs->control);
-
-	if (ctrl & MASK_PORTCHG) {
-		/* do something when headphone is plugged/unplugged? */
-	}
-	if (ctrl & MASK_CNTLERR) {
-		int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16;
-		if (err != 0 && awacs_revision < AWACS_BURGUNDY)
-			printk(KERN_ERR "AWACS: error %x\n", err);
-	}
-	/* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
-	out_le32(&awacs->control, ctrl);
-}
-
-static void
-awacs_write(int val)
-{
-	if (awacs_revision >= AWACS_BURGUNDY)
-		return;
-	while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
-		;	/* XXX should have timeout */
-	out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));
-}
-
-static void awacs_nosound(unsigned long xx)
-{
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	if (beep_playing) {
-		st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
-		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
-		out_le32(&awacs->control,
-			 (in_le32(&awacs->control) & ~0x1f00)
-			 | (awacs_rate_index << 8));
-		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
-		beep_playing = 0;
-	}
-	restore_flags(flags);
-}
-
-static struct timer_list beep_timer = {
-	NULL, NULL, 0, 0, awacs_nosound
-};
-
-static void awacs_mksound(unsigned int hz, unsigned int ticks)
-{
-	unsigned long flags;
-	int beep_speed = 0;
-	int srate;
-	int period, ncycles, nsamples;
-	int i, j, f;
-	short *p;
-	static int beep_hz_cache;
-	static int beep_nsamples_cache;
-	static int beep_volume_cache;
-
-	for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)
-		if (awacs_freqs_ok[i])
-			beep_speed = i;
-	srate = awacs_freqs[beep_speed];
-
-	if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
-#if 1
-		/* this is a hack for broken X server code */
-		hz = 750;
-		ticks = 12;
-#else
-		/* cancel beep currently playing */
-		awacs_nosound(0);
-		return;
-#endif
-	}
-	save_flags(flags); cli();
-	del_timer(&beep_timer);
-	if (ticks) {
-		beep_timer.expires = jiffies + ticks;
-		add_timer(&beep_timer);
-	}
-	if (beep_playing || sq.active || beep_buf == NULL) {
-		restore_flags(flags);
-		return;		/* too hard, sorry :-( */
-	}
-	beep_playing = 1;
-	st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
-	restore_flags(flags);
-
-	if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
-		nsamples = beep_nsamples_cache;
-	} else {
-		period = srate * 256 / hz;	/* fixed point */
-		ncycles = BEEP_BUFLEN * 256 / period;
-		nsamples = (period * ncycles) >> 8;
-		f = ncycles * 65536 / nsamples;
-		j = 0;
-		p = beep_buf;
-		for (i = 0; i < nsamples; ++i, p += 2) {
-			p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
-			j = (j + f) & 0xffff;
-		}
-		beep_hz_cache = hz;
-		beep_volume_cache = beep_volume;
-		beep_nsamples_cache = nsamples;
-	}
-
-	st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
-	st_le16(&beep_dbdma_cmd->xfer_status, 0);
-	st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
-	st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
-	awacs_beep_state = 1;
-
-	save_flags(flags); cli();
-	if (beep_playing) {	/* i.e. haven't been terminated already */
-		out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
-		out_le32(&awacs->control,
-			 (in_le32(&awacs->control) & ~0x1f00)
-			 | (beep_speed << 8));
-		out_le32(&awacs->byteswap, 0);
-		out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
-		out_le32(&awacs_txdma->control, RUN | (RUN << 16));
-	}
-	restore_flags(flags);
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Save state when going to sleep, restore it afterwards.
- */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-	switch (when) {
-	case PBOOK_SLEEP_NOW:
-		/* XXX we should stop any dma in progress when going to sleep
-		   and restart it when we wake. */
-		PMacSilence();
-		disable_irq(awacs_irq);
-		disable_irq(awacs_tx_irq);
-		if (is_pbook_G3) {
-			feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
-			feature_clear(awacs_node, FEATURE_Sound_power);
-		}
-		break;
-	case PBOOK_WAKE:
-		/* There is still a problem on wake. Sound seems to work fine
-		   if I launch mpg123 and resumes fine if mpg123 was playing,
-		   but the console beep is dead until I do something with the
-		   mixer. Probably yet another timing issue */
-		if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
-		    || !feature_test(awacs_node, FEATURE_Sound_power)) {
-			/* these aren't present on the 3400 AFAIK -- paulus */
-			feature_set(awacs_node, FEATURE_Sound_CLK_enable);
-			feature_set(awacs_node, FEATURE_Sound_power);
-			mdelay(1000);
-		}
-		out_le32(&awacs->control, MASK_IEPC
-			 | (awacs_rate_index << 8) | 0x11
-			 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
-		awacs_write(awacs_reg[0] | MASK_ADDR0);
-		awacs_write(awacs_reg[1] | MASK_ADDR1);
-		awacs_write(awacs_reg[2] | MASK_ADDR2);
-		awacs_write(awacs_reg[4] | MASK_ADDR4);
-		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
-		enable_irq(awacs_irq);
-		enable_irq(awacs_tx_irq);
-		if (awacs_revision == 3) {
-			mdelay(100);
-			awacs_write(0x6000);
-			mdelay(2);
-			awacs_write(awacs_reg[1] | MASK_ADDR1);
-		}
-		/* enable CD sound input */
-		if (macio_base && is_pbook_G3) {
-			out_8(macio_base + 0x37, 3);
-		} else if (is_pbook_3400) {
-			feature_set(awacs_node, FEATURE_IOBUS_enable);
-			udelay(10);
-			in_8(latch_base + 0x190);
-		}
- 		/* Resume pending sounds. */
- 		PMacPlay();
-	}
-	return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
-
-/* All the burgundy functions: */
-
-/* Waits for busy flag to clear */
-inline static void
-awacs_burgundy_busy_wait(void)
-{
-	while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
-		;
-}
-
-inline static void
-awacs_burgundy_extend_wait(void)
-{
-	while (!(in_le32(&awacs->codec_stat) & MASK_EXTEND))
-		;
-	while (in_le32(&awacs->codec_stat) & MASK_EXTEND)
-		;
-}
-
-static void
-awacs_burgundy_wcw(unsigned addr, unsigned val)
-{
-	out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
-	awacs_burgundy_busy_wait();
-	out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
-	awacs_burgundy_busy_wait();	     	 
-	out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
-	awacs_burgundy_busy_wait();	     	 
-	out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
-	awacs_burgundy_busy_wait();
-}
-
-static unsigned
-awacs_burgundy_rcw(unsigned addr)
-{
-	unsigned val = 0;
-	unsigned long flags;
-
-	/* should have timeouts here */
-	save_flags(flags); cli();
-
-	out_le32(&awacs->codec_ctrl, addr + 0x100000);
-	awacs_burgundy_busy_wait();
-	awacs_burgundy_extend_wait();
-	val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
-
-	out_le32(&awacs->codec_ctrl, addr + 0x100100);
-	awacs_burgundy_busy_wait();	     	 
-	awacs_burgundy_extend_wait();
-	val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8;
-
-	out_le32(&awacs->codec_ctrl, addr + 0x100200);
-	awacs_burgundy_busy_wait();	     	 
-	awacs_burgundy_extend_wait();
-	val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16;
-
-	out_le32(&awacs->codec_ctrl, addr + 0x100300);
-	awacs_burgundy_busy_wait();
-	awacs_burgundy_extend_wait();
-	val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24;
-
-	restore_flags(flags);
-
-	return val;
-}
-
-
-static void
-awacs_burgundy_wcb(unsigned addr, unsigned val)
-{
-	out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
-	awacs_burgundy_busy_wait();
-}
-
-static unsigned
-awacs_burgundy_rcb(unsigned addr)
-{
-	unsigned val = 0;
-	unsigned long flags;
-
-	/* should have timeouts here */
-	save_flags(flags); cli();
-
-	out_le32(&awacs->codec_ctrl, addr + 0x100000);
-	awacs_burgundy_busy_wait();
-	awacs_burgundy_extend_wait();
-	val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
-
-	restore_flags(flags);
-
-	return val;
-}
-
-static int
-awacs_burgundy_check(void)
-{
-	/* Checks to see the chip is alive and kicking */
-	int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE;
-  
-	return error == 0xf0000;
-}
-
-static int
-awacs_burgundy_init(void)
-{
-	if (awacs_burgundy_check()) {
-		printk(KERN_WARNING "AWACS: disabled by MacOS :-(\n");
-		return 1;
-	}
-
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES,
-			   DEF_BURGUNDY_OUTPUTENABLES);
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
-			   DEF_BURGUNDY_MORE_OUTPUTENABLES);
-	awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
-			   DEF_BURGUNDY_OUTPUTSELECTS);
-	
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21,
-			   DEF_BURGUNDY_INPSEL21);
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3,
-			   DEF_BURGUNDY_INPSEL3);
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD,
-			   DEF_BURGUNDY_GAINCD);
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE,
-			   DEF_BURGUNDY_GAINLINE);
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC,
-			   DEF_BURGUNDY_GAINMIC);
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM,
-			   DEF_BURGUNDY_GAINMODEM);
-	
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER,
-			   DEF_BURGUNDY_ATTENSPEAKER);
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT,
-			   DEF_BURGUNDY_ATTENLINEOUT);
-	awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP,
-			   DEF_BURGUNDY_ATTENHP);
-	
-	awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME,
-			   DEF_BURGUNDY_MASTER_VOLUME);
-	awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD,
-			   DEF_BURGUNDY_VOLCD);
-	awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE,
-			   DEF_BURGUNDY_VOLLINE);
-	awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC,
-			   DEF_BURGUNDY_VOLMIC);
-	return 0;
-}
-
-static void
-awacs_burgundy_write_volume(unsigned address, int volume)
-{
-	int hardvolume,lvolume,rvolume;
-
-	lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0;
-	rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0;
-
-	hardvolume = lvolume + (rvolume << 16);
-
-	awacs_burgundy_wcw(address, hardvolume);
-}
-
-static int
-awacs_burgundy_read_volume(unsigned address)
-{
-	int softvolume,wvolume;
-
-	wvolume = awacs_burgundy_rcw(address);
-
-	softvolume = (wvolume & 0xff) - 155;
-	softvolume += (((wvolume >> 16) & 0xff) - 155)<<8;
-
-	return softvolume > 0 ? softvolume : 0;
-}
-
-
-
-
-static int
-awacs_burgundy_read_mvolume(unsigned address)
-{
-	int lvolume,rvolume,wvolume;
-
-	wvolume = awacs_burgundy_rcw(address);
-
-	wvolume &= 0xffff;
-	
-	rvolume = (wvolume & 0xff) - 155;
-	lvolume = ((wvolume & 0xff00)>>8) - 155;
-
-	return lvolume + (rvolume << 8);
-}
-
-
-static void
-awacs_burgundy_write_mvolume(unsigned address, int volume)
-{
-	int lvolume,rvolume,hardvolume;
-
-	lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0;
-	rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0;
-
-	hardvolume = lvolume + (rvolume << 8);
-	hardvolume += (hardvolume << 16);
-
-	awacs_burgundy_wcw(address, hardvolume);
-}
-
-/* End burgundy functions */
-
-
-
-
-
-/* Turn on sound output, needed on G3 desktop powermacs */
-static void
-awacs_enable_amp(int spkr_vol)
-{
-	struct adb_request req;
-
-	awacs_spkr_vol = spkr_vol;
-	if (sys_ctrler != SYS_CTRLER_CUDA)
-		return;
-
-	/* turn on headphones */
-	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
-		     0x8a, 4, 0);
-	while (!req.complete) cuda_poll();
-	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
-		     0x8a, 6, 0);
-	while (!req.complete) cuda_poll();
-
-	/* turn on speaker */
-	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
-		     0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100);
-	while (!req.complete) cuda_poll();
-	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
-		     0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100);
-	while (!req.complete) cuda_poll();
-
-	cuda_request(&req, NULL, 5, CUDA_PACKET,
-		     CUDA_GET_SET_IIC, 0x8a, 1, 0x29);
-	while (!req.complete) cuda_poll();
-}
-
-#endif /* CONFIG_PPC */
-
-/*** Machine definitions *****************************************************/
-
-
-#ifdef CONFIG_ATARI
-static MACHINE machTT = {
-	DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
-#ifdef MODULE
-	AtaIrqCleanUp,
-#endif /* MODULE */
-	TTInit, TTSilence, TTSetFormat, TTSetVolume,
-	AtaSetBass, AtaSetTreble, TTSetGain,
-	AtaPlay
-};
-
-static MACHINE machFalcon = {
-	DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
-#ifdef MODULE
-	AtaIrqCleanUp,
-#endif /* MODULE */
-	FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume,
-	AtaSetBass, AtaSetTreble, NULL,
-	AtaPlay
-};
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static MACHINE machAmiga = {
-	DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
-#ifdef MODULE
-	AmiIrqCleanUp,
-#endif /* MODULE */
-	AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume,
-	NULL, AmiSetTreble, NULL,
-	AmiPlay
-};
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static MACHINE machPMac = {
-	DMASND_AWACS, PMacAlloc, PMacFree, PMacIrqInit,
-#ifdef MODULE
-	PMacIrqCleanup,
-#endif /* MODULE */
-	PMacInit, PMacSilence, PMacSetFormat, PMacSetVolume,
-	NULL, NULL, NULL,	/* bass, treble, gain */
-	PMacPlay
-};
-#endif /* CONFIG_AMIGA */
-
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void)
-{
-	/* update hardware settings one more */
-	(*sound.mach.init)();
-
-	(*sound.mach.silence)();
-}
-
-
-static void sound_init(void)
-{
-	(*sound.mach.init)();
-}
-
-
-static int sound_set_format(int format)
-{
-	return(*sound.mach.setFormat)(format);
-}
-
-
-static int sound_set_speed(int speed)
-{
-	if (speed < 0)
-		return(sound.soft.speed);
-
-	sound.soft.speed = speed;
-	(*sound.mach.init)();
-	if (sound.minDev == SND_DEV_DSP)
-		sound.dsp.speed = sound.soft.speed;
-
-	return(sound.soft.speed);
-}
-
-
-static int sound_set_stereo(int stereo)
-{
-	if (stereo < 0)
-		return(sound.soft.stereo);
-
-	stereo = !!stereo;    /* should be 0 or 1 now */
-
-	sound.soft.stereo = stereo;
-	if (sound.minDev == SND_DEV_DSP)
-		sound.dsp.stereo = stereo;
-	(*sound.mach.init)();
-
-	return(stereo);
-}
-
-
-static int sound_set_volume(int volume)
-{
-	return(*sound.mach.setVolume)(volume);
-}
-
-
-#ifdef CONFIG_ATARI
-static int sound_set_bass(int bass)
-{
-	return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
-}
-
-static int sound_set_gain(int gain)
-{
-	return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
-}
-#endif /* CONFIG_ATARI */
-
-#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
-static int sound_set_treble(int treble)
-{
-	return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
-}
-#endif /* CONFIG_ATARI || CONFIG_AMIGA */
-
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
-				    size_t userCount,
-				    u_char frame[], ssize_t *frameUsed,
-				    ssize_t frameLeft)
-{
-	ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
-	switch (sound.soft.format) {
-	case AFMT_MU_LAW:
-		ct_func = sound.trans->ct_ulaw;
-		break;
-	case AFMT_A_LAW:
-		ct_func = sound.trans->ct_alaw;
-		break;
-	case AFMT_S8:
-		ct_func = sound.trans->ct_s8;
-		break;
-	case AFMT_U8:
-		ct_func = sound.trans->ct_u8;
-		break;
-	case AFMT_S16_BE:
-		ct_func = sound.trans->ct_s16be;
-		break;
-	case AFMT_U16_BE:
-		ct_func = sound.trans->ct_u16be;
-		break;
-	case AFMT_S16_LE:
-		ct_func = sound.trans->ct_s16le;
-		break;
-	case AFMT_U16_LE:
-		ct_func = sound.trans->ct_u16le;
-		break;
-	}
-	if (ct_func)
-		return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
-	else
-		return 0;
-}
-
-#ifdef CONFIG_PPC
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
-				    size_t userCount,
-				    u_char frame[], ssize_t *frameUsed,
-				    ssize_t frameLeft)
-{
-	ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
-	switch (sound.soft.format) {
-	case AFMT_MU_LAW:
-		ct_func = sound.read_trans->ct_ulaw;
-		break;
-	case AFMT_A_LAW:
-		ct_func = sound.read_trans->ct_alaw;
-		break;
-	case AFMT_S8:
-		ct_func = sound.read_trans->ct_s8;
-		break;
-	case AFMT_U8:
-		ct_func = sound.read_trans->ct_u8;
-		break;
-	case AFMT_S16_BE:
-		ct_func = sound.read_trans->ct_s16be;
-		break;
-	case AFMT_U16_BE:
-		ct_func = sound.read_trans->ct_u16be;
-		break;
-	case AFMT_S16_LE:
-		ct_func = sound.read_trans->ct_s16le;
-		break;
-	case AFMT_U16_LE:
-		ct_func = sound.read_trans->ct_u16le;
-		break;
-	}
-	if (ct_func)
-		return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
-	else
-		return 0;
-}
-#endif
-
-
-/*
- * /dev/mixer abstraction
- */
-
-
-#define RECLEVEL_VOXWARE_TO_GAIN(v) \
-	((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
-#define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3)
-
-
-static int mixer_open(struct inode *inode, struct file *file)
-{
-	MOD_INC_USE_COUNT;
-	mixer.busy = 1;
-	return 0;
-}
-
-
-static int mixer_release(struct inode *inode, struct file *file)
-{
-	mixer.busy = 0;
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg)
-{
-	int data;
-	if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-	    mixer.modify_counter++;
-	if (cmd == OSS_GETVERSION)
-	    return IOCTL_OUT(arg, SOUND_VERSION);
-	switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
-	case DMASND_FALCON:
-		switch (cmd) {
-		case SOUND_MIXER_INFO: {
-		    mixer_info info;
-		    strncpy(info.id, "FALCON", sizeof(info.id));
-		    strncpy(info.name, "FALCON", sizeof(info.name));
-		    info.name[sizeof(info.name)-1] = 0;
-		    info.modify_counter = mixer.modify_counter;
-		    copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
-		    return 0;
-		}
-		case SOUND_MIXER_READ_DEVMASK:
-			return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);
-		case SOUND_MIXER_READ_RECMASK:
-			return IOCTL_OUT(arg, SOUND_MASK_MIC);
-		case SOUND_MIXER_READ_STEREODEVS:
-			return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);
-		case SOUND_MIXER_READ_CAPS:
-			return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);
-		case SOUND_MIXER_READ_VOLUME:
-			return IOCTL_OUT(arg,
-				VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
-				VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
-		case SOUND_MIXER_WRITE_MIC:
-			IOCTL_IN(arg, data);
-			tt_dmasnd.input_gain =
-				RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
-				RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
-			/* fall thru, return set value */
-		case SOUND_MIXER_READ_MIC:
-			return IOCTL_OUT(arg,
-				RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
-				RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8);
-		case SOUND_MIXER_READ_SPEAKER:
-			{
-				int porta;
-				cli();
-				sound_ym.rd_data_reg_sel = 14;
-				porta = sound_ym.rd_data_reg_sel;
-				sti();
-				return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
-			}
-		case SOUND_MIXER_WRITE_VOLUME:
-			IOCTL_IN(arg, data);
-			return IOCTL_OUT(arg, sound_set_volume(data));
-		case SOUND_MIXER_WRITE_SPEAKER:
-			{
-				int porta;
-				IOCTL_IN(arg, data);
-				cli();
-				sound_ym.rd_data_reg_sel = 14;
-				porta = (sound_ym.rd_data_reg_sel & ~0x40) |
-					(data < 50 ? 0x40 : 0);
-				sound_ym.wd_data = porta;
-				sti();
-				return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
-			}
-		}
-		break;
-
-	case DMASND_TT:
-		switch (cmd) {
-		case SOUND_MIXER_INFO: {
-		    mixer_info info;
-		    strncpy(info.id, "TT", sizeof(info.id));
-		    strncpy(info.name, "TT", sizeof(info.name));
-		    info.name[sizeof(info.name)-1] = 0;
-		    info.modify_counter = mixer.modify_counter;
-		    copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
-		    return 0;
-		}
-		case SOUND_MIXER_READ_DEVMASK:
-			return IOCTL_OUT(arg,
-					 SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
-					 (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0));
-		case SOUND_MIXER_READ_RECMASK:
-			return IOCTL_OUT(arg, 0);
-		case SOUND_MIXER_READ_STEREODEVS:
-			return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
-		case SOUND_MIXER_READ_VOLUME:
-			return IOCTL_OUT(arg,
-					 VOLUME_DB_TO_VOXWARE(sound.volume_left) |
-					 (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
-		case SOUND_MIXER_READ_BASS:
-			return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass));
-		case SOUND_MIXER_READ_TREBLE:
-			return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble));
-		case SOUND_MIXER_READ_OGAIN:
-			return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain));
-		case SOUND_MIXER_READ_SPEAKER:
-			{
-				int porta;
-				if (MACH_IS_TT) {
-					cli();
-					sound_ym.rd_data_reg_sel = 14;
-					porta = sound_ym.rd_data_reg_sel;
-					sti();
-					return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
-				}
-			}
-			break;
-		case SOUND_MIXER_WRITE_VOLUME:
-			IOCTL_IN(arg, data);
-			return IOCTL_OUT(arg, sound_set_volume(data));
-		case SOUND_MIXER_WRITE_BASS:
-			IOCTL_IN(arg, data);
-			return IOCTL_OUT(arg, sound_set_bass(data));
-		case SOUND_MIXER_WRITE_TREBLE:
-			IOCTL_IN(arg, data);
-			return IOCTL_OUT(arg, sound_set_treble(data));
-		case SOUND_MIXER_WRITE_OGAIN:
-			IOCTL_IN(arg, data);
-			return IOCTL_OUT(arg, sound_set_gain(data));
-		case SOUND_MIXER_WRITE_SPEAKER:
-			if (MACH_IS_TT) {
-				int porta;
-				IOCTL_IN(arg, data);
-				cli();
-				sound_ym.rd_data_reg_sel = 14;
-				porta = (sound_ym.rd_data_reg_sel & ~0x40) |
-					(data < 50 ? 0x40 : 0);
-				sound_ym.wd_data = porta;
-				sti();
-				return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
-			}
-		}
-		break;
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-	case DMASND_AMIGA:
-		switch (cmd) {
-		case SOUND_MIXER_INFO: {
-		    mixer_info info;
-		    strncpy(info.id, "AMIGA", sizeof(info.id));
-		    strncpy(info.name, "AMIGA", sizeof(info.name));
-		    info.name[sizeof(info.name)-1] = 0;
-		    info.modify_counter = mixer.modify_counter;
-		    copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
-		    return 0;
-		}
-		case SOUND_MIXER_READ_DEVMASK:
-			return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE);
-		case SOUND_MIXER_READ_RECMASK:
-			return IOCTL_OUT(arg, 0);
-		case SOUND_MIXER_READ_STEREODEVS:
-			return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
-		case SOUND_MIXER_READ_VOLUME:
-			return IOCTL_OUT(arg,
-				VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
-				VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8);
-		case SOUND_MIXER_WRITE_VOLUME:
-			IOCTL_IN(arg, data);
-			return IOCTL_OUT(arg, sound_set_volume(data));
-		case SOUND_MIXER_READ_TREBLE:
-			return IOCTL_OUT(arg, sound.treble);
-		case SOUND_MIXER_WRITE_TREBLE:
-			IOCTL_IN(arg, data);
-			return IOCTL_OUT(arg, sound_set_treble(data));
-		}
-		break;
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-	case DMASND_AWACS:
-		/* Different IOCTLS for burgundy*/
-		if (awacs_revision < AWACS_BURGUNDY) {
-			switch (cmd) {
-			case SOUND_MIXER_INFO: {
-			    mixer_info info;
-			    strncpy(info.id, "AWACS", sizeof(info.id));
-			    strncpy(info.name, "AWACS", sizeof(info.name));
-			    info.name[sizeof(info.name)-1] = 0;
-			    info.modify_counter = mixer.modify_counter;
-			    copy_to_user_ret((int *)arg, &info, 
-					     sizeof(info), -EFAULT);
-			    return 0;
-			}
-			case SOUND_MIXER_READ_DEVMASK:
-				data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
-					| SOUND_MASK_LINE | SOUND_MASK_MIC
-					| SOUND_MASK_CD | SOUND_MASK_RECLEV
-					| SOUND_MASK_ALTPCM
-					| SOUND_MASK_MONITOR;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_READ_RECMASK:
-				data = SOUND_MASK_LINE | SOUND_MASK_MIC
-					| SOUND_MASK_CD;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_READ_RECSRC:
-				data = 0;
-				if (awacs_reg[0] & MASK_MUX_AUDIN)
-					data |= SOUND_MASK_LINE;
-				if (awacs_reg[0] & MASK_MUX_MIC)
-					data |= SOUND_MASK_MIC;
-				if (awacs_reg[0] & MASK_MUX_CD)
-					data |= SOUND_MASK_CD;
-				if (awacs_reg[1] & MASK_LOOPTHRU)
-					data |= SOUND_MASK_MONITOR;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_RECSRC:
-				IOCTL_IN(arg, data);
-				data &= (SOUND_MASK_LINE
-					 | SOUND_MASK_MIC | SOUND_MASK_CD
-					 | SOUND_MASK_MONITOR);
-				awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
-						  | MASK_MUX_AUDIN);
-				awacs_reg[1] &= ~MASK_LOOPTHRU;
-				if (data & SOUND_MASK_LINE)
-					awacs_reg[0] |= MASK_MUX_AUDIN;
-				if (data & SOUND_MASK_MIC)
-					awacs_reg[0] |= MASK_MUX_MIC;
-				if (data & SOUND_MASK_CD)
-					awacs_reg[0] |= MASK_MUX_CD;
-				if (data & SOUND_MASK_MONITOR)
-					awacs_reg[1] |= MASK_LOOPTHRU;
-				awacs_write(awacs_reg[0] | MASK_ADDR0);
-				awacs_write(awacs_reg[1] | MASK_ADDR1);
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_READ_STEREODEVS:
-				data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
-					| SOUND_MASK_RECLEV;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_READ_CAPS:
-				return IOCTL_OUT(arg, 0);
-			case SOUND_MIXER_READ_VOLUME:
-				data = (awacs_reg[1] & MASK_AMUTE)? 0:
-					awacs_get_volume(awacs_reg[2], 6);
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_VOLUME:
-				IOCTL_IN(arg, data);
-				return IOCTL_OUT(arg, sound_set_volume(data));
-			case SOUND_MIXER_READ_SPEAKER:
-				if (awacs_revision == 3
-				    && sys_ctrler == SYS_CTRLER_CUDA)
-					data = awacs_spkr_vol;
-				else
-					data = (awacs_reg[1] & MASK_CMUTE)? 0:
-						awacs_get_volume(awacs_reg[4], 6);
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_SPEAKER:
-				IOCTL_IN(arg, data);
-				if (awacs_revision == 3
-				    && sys_ctrler == SYS_CTRLER_CUDA)
-					awacs_enable_amp(data);
-				else
-					data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */
-				IOCTL_IN(arg, data);
-				beep_volume = data & 0xff;
-				/* fall through */
-			case SOUND_MIXER_READ_ALTPCM:
-				return IOCTL_OUT(arg, beep_volume);
-			case SOUND_MIXER_WRITE_LINE:
-				IOCTL_IN(arg, data);
-				awacs_reg[0] &= ~MASK_MUX_AUDIN;
-				if ((data & 0xff) >= 50)
-					awacs_reg[0] |= MASK_MUX_AUDIN;
-				awacs_write(MASK_ADDR0 | awacs_reg[0]);
-				/* fall through */
-			case SOUND_MIXER_READ_LINE:
-				data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_MIC:
-				IOCTL_IN(arg, data);
-				data &= 0xff;
-				awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);
-				if (data >= 25) {
-					awacs_reg[0] |= MASK_MUX_MIC;
-					if (data >= 75)
-						awacs_reg[0] |= MASK_GAINLINE;
-				}
-				awacs_write(MASK_ADDR0 | awacs_reg[0]);
-				/* fall through */
-			case SOUND_MIXER_READ_MIC:
-				data = (awacs_reg[0] & MASK_MUX_MIC)?
-					(awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_CD:
-				IOCTL_IN(arg, data);
-				awacs_reg[0] &= ~MASK_MUX_CD;
-				if ((data & 0xff) >= 50)
-					awacs_reg[0] |= MASK_MUX_CD;
-				awacs_write(MASK_ADDR0 | awacs_reg[0]);
-				/* fall through */
-			case SOUND_MIXER_READ_CD:
-				data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_RECLEV:
-				IOCTL_IN(arg, data);
-				data = awacs_volume_setter(data, 0, 0, 4);
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_READ_RECLEV:
-				data = awacs_get_volume(awacs_reg[0], 4);
-				return IOCTL_OUT(arg, data);
-			}
-			break;
-		} else {
-			/* We are, we are, we are... Burgundy or better */
-			switch(cmd) {
-			case SOUND_MIXER_INFO: {
-			    mixer_info info;
-			    strncpy(info.id, "AWACS", sizeof(info.id));
-			    strncpy(info.name, "AWACS", sizeof(info.name));
-			    info.name[sizeof(info.name)-1] = 0;
-			    info.modify_counter = mixer.modify_counter;
-			    copy_to_user_ret((int *)arg, &info, 
-					     sizeof(info), -EFAULT);
-			    return 0;
-			}
-			case SOUND_MIXER_READ_DEVMASK:
-				data = SOUND_MASK_VOLUME | SOUND_MASK_CD |
-					SOUND_MASK_LINE | SOUND_MASK_MIC |
-					SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_READ_RECMASK:
-				data = SOUND_MASK_LINE | SOUND_MASK_MIC
-					| SOUND_MASK_CD;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_READ_RECSRC:
-				data = 0;
-				if (awacs_reg[0] & MASK_MUX_AUDIN)
-					data |= SOUND_MASK_LINE;
-				if (awacs_reg[0] & MASK_MUX_MIC)
-					data |= SOUND_MASK_MIC;
-				if (awacs_reg[0] & MASK_MUX_CD)
-					data |= SOUND_MASK_CD;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_RECSRC:
-				IOCTL_IN(arg, data);
-				data &= (SOUND_MASK_LINE
-					 | SOUND_MASK_MIC | SOUND_MASK_CD);
-				awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
-						  | MASK_MUX_AUDIN);
-				if (data & SOUND_MASK_LINE)
-					awacs_reg[0] |= MASK_MUX_AUDIN;
-				if (data & SOUND_MASK_MIC)
-					awacs_reg[0] |= MASK_MUX_MIC;
-				if (data & SOUND_MASK_CD)
-					awacs_reg[0] |= MASK_MUX_CD;
-				awacs_write(awacs_reg[0] | MASK_ADDR0);
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_READ_STEREODEVS:
-				data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
-					| SOUND_MASK_RECLEV | SOUND_MASK_CD
-					| SOUND_MASK_LINE;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_READ_CAPS:
-				return IOCTL_OUT(arg, 0);
-			case SOUND_MIXER_WRITE_VOLUME:
-				IOCTL_IN(arg, data);
-				awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data);
-				/* Fall through */
-			case SOUND_MIXER_READ_VOLUME:
-				return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME));
-			case SOUND_MIXER_WRITE_SPEAKER:
-				IOCTL_IN(arg, data);
-
-				if (!(data & 0xff)) {
-				  /* Mute the left speaker */
-				  awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
-						     awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2);
-				} else {
-				  /* Unmute the left speaker */
-				  awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
-						     awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2);
-				}
-				if (!(data & 0xff00)) {
-				  /* Mute the right speaker */
-				  awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
-						     awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4);
-				} else {
-				  /* Unmute the right speaker */
-				  awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
-						     awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4);
-				}
-
-				data = (((data&0xff)*16)/100 > 0xf ? 0xf :
-					(((data&0xff)*16)/100)) + 
-					 ((((data>>8)*16)/100 > 0xf ? 0xf :
-					((((data>>8)*16)/100)))<<4);
-
-				awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data);
-				/* Fall through */
-			case SOUND_MIXER_READ_SPEAKER:
-				data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER);
-				data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8);
-				return IOCTL_OUT(arg, ~data);
-			case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */
-				IOCTL_IN(arg, data);
-				beep_volume = data & 0xff;
-				/* fall through */
-			case SOUND_MIXER_READ_ALTPCM:
-				return IOCTL_OUT(arg, beep_volume);
-			case SOUND_MIXER_WRITE_LINE:
-				IOCTL_IN(arg, data);
-				awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data);
-
-				/* fall through */
-			case SOUND_MIXER_READ_LINE:
-				data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE);				
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_MIC:
-				IOCTL_IN(arg, data);
-				/* Mic is mono device */
-				data = (data << 8) + (data << 24);
-				awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data);
-				/* fall through */
-			case SOUND_MIXER_READ_MIC:
-				data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC);				
-				data <<= 24;
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_CD:
-				IOCTL_IN(arg, data);
-				awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data);
-				/* fall through */
-			case SOUND_MIXER_READ_CD:
-				data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD);
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_WRITE_RECLEV:
-				IOCTL_IN(arg, data);
-				data = awacs_volume_setter(data, 0, 0, 4);
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_READ_RECLEV:
-				data = awacs_get_volume(awacs_reg[0], 4);
-				return IOCTL_OUT(arg, data);
-			case SOUND_MIXER_OUTMASK:
-				break;
-			case SOUND_MIXER_OUTSRC:
-				break;
-			}
-			break;
-		}
-#endif
-	}
-
-	return -EINVAL;
-}
-
-
-static struct file_operations mixer_fops =
-{
-	llseek:		sound_lseek,
-	ioctl:		mixer_ioctl,
-	open:		mixer_open,
-	release:	mixer_release,
-};
-
-
-static void __init mixer_init(void)
-{
-#ifndef MODULE
-	int mixer_unit;
-#endif
-	mixer_unit = register_sound_mixer(&mixer_fops, -1);
-	if (mixer_unit < 0)
-		return;
-
-	mixer.busy = 0;
-	sound.treble = 0;
-	sound.bass = 0;
-	switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
-	case DMASND_TT:
-		atari_microwire_cmd(MW_LM1992_VOLUME(0));
-		sound.volume_left = 0;
-		atari_microwire_cmd(MW_LM1992_BALLEFT(0));
-		sound.volume_right = 0;
-		atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
-		atari_microwire_cmd(MW_LM1992_TREBLE(0));
-		atari_microwire_cmd(MW_LM1992_BASS(0));
-		break;
-	case DMASND_FALCON:
-		sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
-		sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
-		break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-	case DMASND_AMIGA:
-		sound.volume_left = 64;
-		sound.volume_right = 64;
-		custom.aud[0].audvol = sound.volume_left;
-		custom.aud[3].audvol = 1;	/* For pseudo 14bit */
-		custom.aud[1].audvol = sound.volume_right;
-		custom.aud[2].audvol = 1;	/* For pseudo 14bit */
-		sound.treble = 50;
-		break;
-#endif /* CONFIG_AMIGA */
-	}
-}
-
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-
-static int sq_allocate_buffers(void)
-{
-	int i;
-
-	if (sound_buffers)
-		return 0;
-	sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
-	if (!sound_buffers)
-		return -ENOMEM;
-	for (i = 0; i < numBufs; i++) {
-		sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
-		if (!sound_buffers[i]) {
-			while (i--)
-				sound.mach.dma_free (sound_buffers[i], bufSize << 10);
-			kfree (sound_buffers);
-			sound_buffers = 0;
-			return -ENOMEM;
-		}
-	}
-	return 0;
-}
-
-
-static void sq_release_buffers(void)
-{
-	int i;
-
-	if (sound_buffers) {
-		for (i = 0; i < numBufs; i++)
-			sound.mach.dma_free (sound_buffers[i], bufSize << 10);
-		kfree (sound_buffers);
-		sound_buffers = 0;
-	}
-}
-
-
-#ifdef CONFIG_PPC
-static int sq_allocate_read_buffers(void)
-{
-	int i;
-	int j;
-
-	if (sound_read_buffers)
-		return 0;
-	sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL);
-	if (!sound_read_buffers)
-		return -ENOMEM;
-	for (i = 0; i < numBufs; i++) {
-		sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10,
-							      GFP_KERNEL);
-		if (!sound_read_buffers[i]) {
-			while (i--)
-				sound.mach.dma_free (sound_read_buffers[i],
-						     readbufSize << 10);
-			kfree (sound_read_buffers);
-			sound_read_buffers = 0;
-			return -ENOMEM;
-		}
-		/* XXXX debugging code */
-		for (j=0; j<readbufSize; j++) {
-			sound_read_buffers[i][j] = 0xef;
-		}
-	}
-	return 0;
-}
-
-static void sq_release_read_buffers(void)
-{
-	int i;
-	volatile struct dbdma_cmd *cp;
-	
-
-	if (sound_read_buffers) {
-		cp = awacs_rx_cmds;
-		for (i = 0; i < numReadBufs; i++,cp++) {
-			st_le16(&cp->command, DBDMA_STOP);
-		}
-		/* We should probably wait for the thing to stop before we
-		   release the memory */
-		for (i = 0; i < numBufs; i++)
-			sound.mach.dma_free (sound_read_buffers[i],
-					     bufSize << 10);
-		kfree (sound_read_buffers);
-		sound_read_buffers = 0;
-	}
-}
-#endif
-
-
-static void sq_setup(int numBufs, int bufSize, char **write_buffers)
-{
-#ifdef CONFIG_PPC
-	int i;
-	volatile struct dbdma_cmd *cp;
-#endif /* CONFIG_PPC */
-
-	sq.max_count = numBufs;
-	sq.max_active = numBufs;
-	sq.block_size = bufSize;
-	sq.buffers = write_buffers;
-
-	sq.front = sq.count = 0;
-	sq.rear = -1;
-	sq.syncing = 0;
-	sq.active = 0;
-
-#ifdef CONFIG_ATARI
-	sq.ignore_int = 0;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-	sq.block_size_half = sq.block_size>>1;
-	sq.block_size_quarter = sq.block_size_half>>1;
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
-	cp = awacs_tx_cmds;
-	memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
-	for (i = 0; i < numBufs; ++i, ++cp) {
-		st_le32(&cp->phy_addr, virt_to_bus(write_buffers[i]));
-	}
-	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
-	st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
-	out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
-	out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
-#endif /* CONFIG_PPC */
-}
-
-#ifdef CONFIG_PPC
-static void read_sq_setup(int numBufs, int bufSize, char **read_buffers)
-{
-	int i;
-	volatile struct dbdma_cmd *cp;
-
-	read_sq.max_count = numBufs;
-	read_sq.max_active = numBufs;
-	read_sq.block_size = bufSize;
-	read_sq.buffers = read_buffers;
-
-	read_sq.front = read_sq.count = 0;
-	read_sq.rear = 0;
-	read_sq.rear_size = 0;
-	read_sq.syncing = 0;
-	read_sq.active = 0;
-
-	cp = awacs_rx_cmds;
-	memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
-
-	/* Set dma buffers up in a loop */
-	for (i = 0; i < numBufs; i++,cp++) {
-		st_le32(&cp->phy_addr, virt_to_bus(read_buffers[i]));
-		st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);
-		st_le16(&cp->req_count, read_sq.block_size);
-		st_le16(&cp->xfer_status, 0);
-	}
-
-	/* The next two lines make the thing loop around.
-	*/
-	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
-	st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));
-
-	/* Don't start until the first read is done.
-	 * This will also abort any operations in progress if the DMA
-	 * happens to be running (and it shouldn't).
-	 */
-	out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
-	out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));
-
-}
-#endif /* CONFIG_PPC */
-
-
-static void sq_play(void)
-{
-	(*sound.mach.play)();
-}
-
-
-/* ++TeSche: radically changed this one too */
-
-static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
-			loff_t *ppos)
-{
-	ssize_t uWritten = 0;
-	u_char *dest;
-	ssize_t uUsed, bUsed, bLeft;
-
-	/* ++TeSche: Is something like this necessary?
-	 * Hey, that's an honest question! Or does any other part of the
-	 * filesystem already checks this situation? I really don't know.
-	 */
-	if (uLeft == 0)
-		return 0;
-
-	/* The interrupt doesn't start to play the last, incomplete frame.
-	 * Thus we can append to it without disabling the interrupts! (Note
-	 * also that sq.rear isn't affected by the interrupt.)
-	 */
-
-	if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
-		dest = sq_block_address(sq.rear);
-		bUsed = sq.rear_size;
-		uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-		if (uUsed <= 0)
-			return uUsed;
-		src += uUsed;
-		uWritten += uUsed;
-		uLeft -= uUsed;
-		sq.rear_size = bUsed;
-	}
-
-	do {
-		while (sq.count == sq.max_active) {
-			sq_play();
-			if (NON_BLOCKING(sq.open_mode))
-				return uWritten > 0 ? uWritten : -EAGAIN;
-			SLEEP(sq.action_queue, ONE_SECOND);
-			if (SIGNAL_RECEIVED)
-				return uWritten > 0 ? uWritten : -EINTR;
-		}
-
-		/* Here, we can avoid disabling the interrupt by first
-		 * copying and translating the data, and then updating
-		 * the sq variables. Until this is done, the interrupt
-		 * won't see the new frame and we can work on it
-		 * undisturbed.
-		 */
-
-		dest = sq_block_address((sq.rear+1) % sq.max_count);
-		bUsed = 0;
-		bLeft = sq.block_size;
-		uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-		if (uUsed <= 0)
-			break;
-		src += uUsed;
-		uWritten += uUsed;
-		uLeft -= uUsed;
-		if (bUsed) {
-			sq.rear = (sq.rear+1) % sq.max_count;
-			sq.rear_size = bUsed;
-			sq.count++;
-		}
-	} while (bUsed);   /* uUsed may have been 0 */
-
-	sq_play();
-
-	return uUsed < 0? uUsed: uWritten;
-}
-
-
-/***********/
-
-#ifdef CONFIG_PPC
-
-/* Here is how the values are used for reading.
- * The value 'active' simply indicates the DMA is running.  This is
- * done so the driver semantics are DMA starts when the first read is
- * posted.  The value 'front' indicates the buffer we should next
- * send to the user.  The value 'rear' indicates the buffer the DMA is
- * currently filling.  When 'front' == 'rear' the buffer "ring" is
- * empty (we always have an empty available).  The 'rear_size' is used
- * to track partial offsets into the current buffer.  Right now, I just keep
- * the DMA running.  If the reader can't keep up, the interrupt tosses
- * the oldest buffer.  We could also shut down the DMA in this case.
- */
-static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
-                       loff_t *ppos)
-{
-
-	ssize_t	uRead, bLeft, bUsed, uUsed;
-
-	if (uLeft == 0)
-		return 0;
-
-	if (!read_sq.active)
-		PMacRecord();	/* Kick off the record process. */
-
-	uRead = 0;
-
-	/* Move what the user requests, depending upon other options.
-	*/
-	while (uLeft > 0) {
-
-		/* When front == rear, the DMA is not done yet.
-		*/
-		while (read_sq.front == read_sq.rear) {
-			if (NON_BLOCKING(read_sq.open_mode)) {
-			       return uRead > 0 ? uRead : -EAGAIN;
-			}
-			SLEEP(read_sq.action_queue, ONE_SECOND);
-			if (SIGNAL_RECEIVED)
-				return uRead > 0 ? uRead : -EINTR;
-		}
-
-		/* The amount we move is either what is left in the
-		 * current buffer or what the user wants.
-		 */
-		bLeft = read_sq.block_size - read_sq.rear_size;
-		bUsed = read_sq.rear_size;
-		uUsed = sound_copy_translate_read(dst, uLeft,
-			read_sq.buffers[read_sq.front], &bUsed, bLeft);
-		if (uUsed <= 0)
-			return uUsed;
-		dst += uUsed;
-		uRead += uUsed;
-		uLeft -= uUsed;
-		read_sq.rear_size += bUsed;
-		if (read_sq.rear_size >= read_sq.block_size) {
-			read_sq.rear_size = 0;
-			read_sq.front++;
-			if (read_sq.front >= read_sq.max_active)
-				read_sq.front = 0;
-		}
-	}
-	return uRead;
-}
-#endif
-
-static int sq_open(struct inode *inode, struct file *file)
-{
-	int rc = 0;
-
-	MOD_INC_USE_COUNT;
-	if (file->f_mode & FMODE_WRITE) {
-		if (sq.busy) {
-			rc = -EBUSY;
-			if (NON_BLOCKING(file->f_flags))
-				goto err_out;
-			rc = -EINTR;
-			while (sq.busy) {
-				SLEEP(sq.open_queue, ONE_SECOND);
-				if (SIGNAL_RECEIVED)
-					goto err_out;
-			}
-		}
-		sq.busy = 1; /* Let's play spot-the-race-condition */
-
-		if (sq_allocate_buffers()) goto err_out_nobusy;
-
-		sq_setup(numBufs, bufSize<<10,sound_buffers);
-		sq.open_mode = file->f_mode;
-	}
-
-
-#ifdef CONFIG_PPC
-	if (file->f_mode & FMODE_READ) {
-		if (read_sq.busy) {
-			rc = -EBUSY;
-			if (NON_BLOCKING(file->f_flags))
-				goto err_out;
-			rc = -EINTR;
-			while (read_sq.busy) {
-				SLEEP(read_sq.open_queue, ONE_SECOND);
-				if (SIGNAL_RECEIVED)
-					goto err_out;
-			}
-			rc = 0;
-		}
-		read_sq.busy = 1;
-		if (sq_allocate_read_buffers()) goto err_out_nobusy;
-
-		read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers);
-		read_sq.open_mode = file->f_mode;
-	}                                                                      
-#endif
-
-#ifdef CONFIG_ATARI
-	sq.ignore_int = 1;
-#endif /* CONFIG_ATARI */
-	sound.minDev = MINOR(inode->i_rdev) & 0x0f;
-	sound.soft = sound.dsp;
-	sound.hard = sound.dsp;
-	sound_init();
-	if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
-		sound_set_speed(8000);
-		sound_set_stereo(0);
-		sound_set_format(AFMT_MU_LAW);
-	}
-
-#if 0
-	if (file->f_mode == FMODE_READ) {
-		/* Start dma'ing straight away */
-		PMacRecord();
-	}
-#endif
-
-	return 0;
-
-err_out_nobusy:
-	if (file->f_mode & FMODE_WRITE) {
-		sq.busy = 0;
-		WAKE_UP(sq.open_queue);
-	}
-#ifdef CONFIG_PPC
-	if (file->f_mode & FMODE_READ) {
-		read_sq.busy = 0;
-		WAKE_UP(read_sq.open_queue);
-	}
-#endif
-err_out:
-	MOD_DEC_USE_COUNT;
-	return rc;
-}
-
-
-static void sq_reset(void)
-{
-	sound_silence();
-	sq.active = 0;
-	sq.count = 0;
-	sq.front = (sq.rear+1) % sq.max_count;
-}
-
-
-static int sq_fsync(struct file *filp, struct dentry *dentry)
-{
-	int rc = 0;
-
-	sq.syncing = 1;
-	sq_play();	/* there may be an incomplete frame waiting */
-
-	while (sq.active) {
-		SLEEP(sq.sync_queue, ONE_SECOND);
-		if (SIGNAL_RECEIVED) {
-			/* While waiting for audio output to drain, an
-			 * interrupt occurred.  Stop audio output immediately
-			 * and clear the queue. */
-			sq_reset();
-			rc = -EINTR;
-			break;
-		}
-	}
-
-	sq.syncing = 0;
-	return rc;
-}
-
-static int sq_release(struct inode *inode, struct file *file)
-{
-	int rc = 0;
-
-	if (sq.busy)
-		rc = sq_fsync(file, file->f_dentry);
-	sound.soft = sound.dsp;
-	sound.hard = sound.dsp;
-	sound_silence();
-
-#ifdef CONFIG_PPC
-	sq_release_read_buffers();
-#endif
-	sq_release_buffers();
-	MOD_DEC_USE_COUNT;
-
-	/* There is probably a DOS atack here. They change the mode flag. */
-	/* XXX add check here */
-#ifdef CONFIG_PPC
-	if (file->f_mode & FMODE_READ) {
-		read_sq.busy = 0;
-		WAKE_UP(read_sq.open_queue);
-	}
-#endif
-
-	if (file->f_mode & FMODE_WRITE) {
-		sq.busy = 0;
-		WAKE_UP(sq.open_queue);
-	}
-
-	/* Wake up a process waiting for the queue being released.
-	 * Note: There may be several processes waiting for a call
-	 * to open() returning. */
-
-	return rc;
-}
-
-
-static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		    u_long arg)
-{
-	u_long fmt;
-	int data;
-	int size, nbufs;
-	audio_buf_info info;
-
-	switch (cmd) {
-	case SNDCTL_DSP_RESET:
-		sq_reset();
-		return 0;
-	case SNDCTL_DSP_POST:
-	case SNDCTL_DSP_SYNC:
-		return sq_fsync(file, file->f_dentry);
-
-		/* ++TeSche: before changing any of these it's
-		 * probably wise to wait until sound playing has
-		 * settled down. */
-	case SNDCTL_DSP_SPEED:
-		sq_fsync(file, file->f_dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_speed(data));
-	case SNDCTL_DSP_STEREO:
-		sq_fsync(file, file->f_dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_stereo(data));
-	case SOUND_PCM_WRITE_CHANNELS:
-		sq_fsync(file, file->f_dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
-	case SNDCTL_DSP_SETFMT:
-		sq_fsync(file, file->f_dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_format(data));
-	case SNDCTL_DSP_GETFMTS:
-		fmt = 0;
-		if (sound.trans) {
-			if (sound.trans->ct_ulaw)
-				fmt |= AFMT_MU_LAW;
-			if (sound.trans->ct_alaw)
-				fmt |= AFMT_A_LAW;
-			if (sound.trans->ct_s8)
-				fmt |= AFMT_S8;
-			if (sound.trans->ct_u8)
-				fmt |= AFMT_U8;
-			if (sound.trans->ct_s16be)
-				fmt |= AFMT_S16_BE;
-			if (sound.trans->ct_u16be)
-				fmt |= AFMT_U16_BE;
-			if (sound.trans->ct_s16le)
-				fmt |= AFMT_S16_LE;
-			if (sound.trans->ct_u16le)
-				fmt |= AFMT_U16_LE;
-		}
-		return IOCTL_OUT(arg, fmt);
-	case SNDCTL_DSP_GETBLKSIZE:
-		size = sq.block_size
-			* sound.soft.size * (sound.soft.stereo + 1)
-			/ (sound.hard.size * (sound.hard.stereo + 1));
-		return IOCTL_OUT(arg, size);
-	case SNDCTL_DSP_SUBDIVIDE:
-		break;
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (sq.count || sq.active || sq.syncing)
-			return -EINVAL;
-		IOCTL_IN(arg, size);
-		nbufs = size >> 16;
-		if (nbufs < 2 || nbufs > numBufs)
-			nbufs = numBufs;
-		size &= 0xffff;
-		if (size >= 8 && size <= 29) {
-			size = 1 << size;
-			size *= sound.hard.size * (sound.hard.stereo + 1);
-			size /= sound.soft.size * (sound.soft.stereo + 1);
-			if (size > (bufSize << 10))
-				size = bufSize << 10;
-		} else
-			size = bufSize << 10;
-		sq_setup(numBufs, size, sound_buffers);
-		sq.max_active = nbufs;
-		return 0;
-	case SNDCTL_DSP_GETOSPACE:
-		info.fragments = sq.max_active - sq.count;
-		info.fragstotal = sq.max_active;
-		info.fragsize = sq.block_size;
-		info.bytes = info.fragments * info.fragsize;
-		if (copy_to_user((void *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-
-	default:
-		return mixer_ioctl(inode, file, cmd, arg);
-	}
-	return -EINVAL;
-}
-
-
-
-static struct file_operations sq_fops =
-{
-	llseek:		sound_lseek,
-	write:		sq_write,
-	ioctl:		sq_ioctl,
-	open:		sq_open,
-	release:	sq_release,
-#ifdef CONFIG_PPC
-	read:		sq_read,			/* sq_read */
-#endif
-};
-
-
-static void __init sq_init(void)
-{
-#ifndef MODULE
-	int sq_unit;
-#endif
-	sq_unit = register_sound_dsp(&sq_fops, -1);
-	if (sq_unit < 0)
-		return;
-
-	init_waitqueue_head(&sq.action_queue);
-	init_waitqueue_head(&sq.open_queue);
-	init_waitqueue_head(&sq.sync_queue);
-
-#ifdef CONFIG_PPC
-	init_waitqueue_head(&read_sq.action_queue);
-	init_waitqueue_head(&read_sq.open_queue);
-	init_waitqueue_head(&read_sq.sync_queue);
-#endif
-
-	sq.busy = 0;
-#ifdef CONFIG_PPC
-	read_sq.busy = 0;
-#endif
-
-	/* whatever you like as startup mode for /dev/dsp,
-	 * (/dev/audio hasn't got a startup mode). note that
-	 * once changed a new open() will *not* restore these!
-	 */
-	sound.dsp.format = AFMT_U8;
-	sound.dsp.stereo = 0;
-	sound.dsp.size = 8;
-
-	/* set minimum rate possible without expanding */
-	switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
-	case DMASND_TT:
-		sound.dsp.speed = 6258;
-		break;
-	case DMASND_FALCON:
-		sound.dsp.speed = 8195;
-		break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-	case DMASND_AMIGA:
-		sound.dsp.speed = 8000;
-		break;
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
-	case DMASND_AWACS:
-		sound.dsp.speed = 8000;
-		break;
-#endif /* CONFIG_PPC */
-	}
-
-	/* before the first open to /dev/dsp this wouldn't be set */
-	sound.soft = sound.dsp;
-	sound.hard = sound.dsp;
-
-	sound_silence();
-}
-
-/*
- * /dev/sndstat
- */
-
-
-/* state.buf should not overflow! */
-
-static int state_open(struct inode *inode, struct file *file)
-{
-	char *buffer = state.buf, *mach = "";
-#ifdef CONFIG_PPC
-	char awacs_buf[64];
-#endif
-	int len = 0;
-
-	if (state.busy)
-		return -EBUSY;
-
-	MOD_INC_USE_COUNT;
-	state.ptr = 0;
-	state.busy = 1;
-
-	switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
-	case DMASND_TT:
-	case DMASND_FALCON:
-		mach = "Atari ";
-		break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-	case DMASND_AMIGA:
-		mach = "Amiga ";
-		break;
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
-	case DMASND_AWACS:
-		sprintf(awacs_buf, "PowerMac (AWACS rev %d) ", awacs_revision);
-		mach = awacs_buf;
-		break;
-#endif /* CONFIG_PPC */
-	}
-	len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
-
-	len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
-	switch (sound.soft.format) {
-	case AFMT_MU_LAW:
-		len += sprintf(buffer+len, " (mu-law)");
-		break;
-	case AFMT_A_LAW:
-		len += sprintf(buffer+len, " (A-law)");
-		break;
-	case AFMT_U8:
-		len += sprintf(buffer+len, " (unsigned 8 bit)");
-		break;
-	case AFMT_S8:
-		len += sprintf(buffer+len, " (signed 8 bit)");
-		break;
-	case AFMT_S16_BE:
-		len += sprintf(buffer+len, " (signed 16 bit big)");
-		break;
-	case AFMT_U16_BE:
-		len += sprintf(buffer+len, " (unsigned 16 bit big)");
-		break;
-	case AFMT_S16_LE:
-		len += sprintf(buffer+len, " (signed 16 bit little)");
-		break;
-	case AFMT_U16_LE:
-		len += sprintf(buffer+len, " (unsigned 16 bit little)");
-		break;
-	}
-	len += sprintf(buffer+len, "\n");
-	len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
-		       sound.soft.speed, sound.hard.speed);
-	len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
-		       sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
-	switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
-	case DMASND_TT:
-		len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
-			       sound.volume_left);
-		len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
-			       sound.volume_right);
-		len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
-			       sound.bass);
-		len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
-			       sound.treble);
-		break;
-	case DMASND_FALCON:
-		len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
-			       sound.volume_left);
-		len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
-			       sound.volume_right);
-		break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-	case DMASND_AMIGA:
-		len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
-			       sound.volume_left);
-		len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
-			       sound.volume_right);
-		break;
-#endif /* CONFIG_AMIGA */
-	}
-	len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
-		       " sq.max_active = %d\n",
-		       sq.block_size, sq.max_count, sq.max_active);
-	len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
-		       sq.rear_size);
-	len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
-		       sq.active, sq.syncing);
-	state.len = len;
-	return 0;
-}
-
-
-static int state_release(struct inode *inode, struct file *file)
-{
-	state.busy = 0;
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-
-static ssize_t state_read(struct file *file, char *buf, size_t count,
-			  loff_t *ppos)
-{
-	int n = state.len - state.ptr;
-	if (n > count)
-		n = count;
-	if (n <= 0)
-		return 0;
-	if (copy_to_user(buf, &state.buf[state.ptr], n))
-		return -EFAULT;
-	state.ptr += n;
-	return n;
-}
-
-
-static struct file_operations state_fops =
-{
-	llseek:		sound_lseek,
-	read:		state_read,
-	open:		state_open,
-	release:	state_release,
-};
-
-
-static void __init state_init(void)
-{
-#ifndef MODULE
-	int state_unit;
-#endif
-	state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
-	if (state_unit < 0)
-		return;
-	state.busy = 0;
-}
-
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig)
-{
-	return -ESPIPE;
-}
-
-
-/*** Config & Setup **********************************************************/
-
-
-void __init dmasound_init(void)
-{
-	int has_sound = 0;
-#ifdef CONFIG_PPC
-	struct device_node *np;
-#endif
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	switch (m68k_machtype) {
-#ifdef CONFIG_ATARI
-	case MACH_ATARI:
-		if (ATARIHW_PRESENT(PCM_8BIT)) {
-			if (ATARIHW_PRESENT(CODEC))
-				sound.mach = machFalcon;
-			else if (ATARIHW_PRESENT(MICROWIRE))
-				sound.mach = machTT;
-			else
-				break;
-			if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
-				has_sound = 1;
-			else
-				printk("DMA sound driver: Timer A interrupt already in use\n");
-		}
-		break;
-
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-	case MACH_AMIGA:
-		if (AMIGAHW_PRESENT(AMI_AUDIO)) {
-			sound.mach = machAmiga;
-			has_sound = 1;
-		}
-		break;
-#endif /* CONFIG_AMIGA */
-	}
-#endif /* __mc68000__||CONFIG_APUS */
-
-#ifdef CONFIG_PPC
-	awacs_subframe = 0;
-	awacs_revision = 0;
-	np = find_devices("awacs");
-	if (np == 0) {
-		/*
-		 * powermac G3 models have a node called "davbus"
-		 * with a child called "sound".
-		 */
-		struct device_node *sound;
-		np = find_devices("davbus");
-		sound = find_devices("sound");
-		if (sound != 0 && sound->parent == np) {
-			unsigned int *prop, l, i;
-			prop = (unsigned int *)
-				get_property(sound, "sub-frame", 0);
-			if (prop != 0 && *prop >= 0 && *prop < 16)
-				awacs_subframe = *prop;
-			if (device_is_compatible(sound, "burgundy"))
-				awacs_revision = AWACS_BURGUNDY;
-
-			/* look for a property saying what sample rates
-			   are available */
-			for (i = 0; i < 8; ++i)
-				awacs_freqs_ok[i] = 0;
-			prop = (unsigned int *) get_property
-				(sound, "sample-rates", &l);
-			if (prop == 0)
-				prop = (unsigned int *) get_property
-					(sound, "output-frame-rates", &l);
-			if (prop != 0) {
-				for (l /= sizeof(int); l > 0; --l) {
-					/* sometimes the rate is in the
-					   high-order 16 bits (?) */
-					unsigned int r = *prop++;
-					if (r >= 0x10000)
-						r >>= 16;
-					for (i = 0; i < 8; ++i) {
-						if (r == awacs_freqs[i]) {
-							awacs_freqs_ok[i] = 1;
-							break;
-						}
-					}
-				}
-			} else {
-				/* assume just 44.1k is OK */
-				awacs_freqs_ok[0] = 1;
-			}
-		}
-	}
-	if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
-		int vol;
-		sound.mach = machPMac;
-		has_sound = 1;
-
-		awacs = (volatile struct awacs_regs *)
-			ioremap(np->addrs[0].address, 0x80);
-		awacs_txdma = (volatile struct dbdma_regs *)
-			ioremap(np->addrs[1].address, 0x100);
-		awacs_rxdma = (volatile struct dbdma_regs *)
-			ioremap(np->addrs[2].address, 0x100);
-
-		awacs_irq = np->intrs[0].line;
-		awacs_tx_irq = np->intrs[1].line;
-		awacs_rx_irq = np->intrs[2].line;
-
-		awacs_tx_cmd_space = kmalloc((numBufs + 4) * sizeof(struct dbdma_cmd),
-					     GFP_KERNEL);
-		if (awacs_tx_cmd_space == NULL) {
-			printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
-			return;
-		}
-		awacs_node = np;
-#ifdef CONFIG_PMAC_PBOOK
-		if (machine_is_compatible("PowerBook1,1")
-		    || machine_is_compatible("AAPL,PowerBook1998")) {
-			feature_set(np, FEATURE_Sound_CLK_enable);
-			feature_set(np, FEATURE_Sound_power);
-			/* Shorter delay will not work */
-			mdelay(1000);
-		}
-#endif
-		awacs_tx_cmds = (volatile struct dbdma_cmd *)
-			DBDMA_ALIGN(awacs_tx_cmd_space);
-
-
-		awacs_rx_cmd_space = kmalloc((numReadBufs + 4) * sizeof(struct dbdma_cmd),
-					     GFP_KERNEL);
-		if (awacs_rx_cmd_space == NULL) {
-		  printk("DMA sound driver: No memory for input");
-		}
-		awacs_rx_cmds = (volatile struct dbdma_cmd *)
-		  DBDMA_ALIGN(awacs_rx_cmd_space);
-
-
-
-		awacs_reg[0] = MASK_MUX_CD;
-		awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
-		/* get default volume from nvram */
-		vol = (~nvram_read_byte(0x1308) & 7) << 1;
-		awacs_reg[2] = vol + (vol << 6);
-		awacs_reg[4] = vol + (vol << 6);
-		out_le32(&awacs->control, 0x11);
-		awacs_write(awacs_reg[0] + MASK_ADDR0);
-		awacs_write(awacs_reg[1] + MASK_ADDR1);
-		awacs_write(awacs_reg[2] + MASK_ADDR2);
-		awacs_write(awacs_reg[4] + MASK_ADDR4);
-
-		/* Initialize recent versions of the awacs */
-		if (awacs_revision == 0) {
-			awacs_revision =
-				(in_le32(&awacs->codec_stat) >> 12) & 0xf;
-			if (awacs_revision == 3) {
-				mdelay(100);
-				awacs_write(0x6000);
-				mdelay(2);
-				awacs_write(awacs_reg[1] + MASK_ADDR1);
-				awacs_enable_amp(100 * 0x101);
-			}
-		}
-		if (awacs_revision >= AWACS_BURGUNDY)
-			awacs_burgundy_init();
-
-		/* Initialize beep stuff */
-		beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1);
-		orig_mksound = kd_mksound;
-		kd_mksound = awacs_mksound;
-		beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
-		if (beep_buf == NULL)
-			printk(KERN_WARNING "dmasound: no memory for "
-			       "beep buffer\n");
-#ifdef CONFIG_PMAC_PBOOK
-		pmu_register_sleep_notifier(&awacs_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-
-		/* Powerbooks have odd ways of enabling inputs such as
-		   an expansion-bay CD or sound from an internal modem
-		   or a PC-card modem. */
-		if (machine_is_compatible("AAPL,3400/2400")
-			|| machine_is_compatible("AAPL,3500")) {
-			is_pbook_3400 = 1;
-			/*
-			 * Enable CD and PC-card sound inputs.
-			 * This is done by reading from address
-			 * f301a000, + 0x10 to enable the expansion-bay
-			 * CD sound input, + 0x80 to enable the PC-card
-			 * sound input.  The 0x100 enables the SCSI bus
-			 * terminator power.
-			 */
-			latch_base = (unsigned char *) ioremap
-				(0xf301a000, 0x1000);
-			in_8(latch_base + 0x190);
-		} else if (machine_is_compatible("PowerBook1,1")
-			   || machine_is_compatible("AAPL,PowerBook1998")) {
-			struct device_node* mio;
-			macio_base = 0;
-			is_pbook_G3 = 1;
-			for (mio = np->parent; mio; mio = mio->parent) {
-				if (strcmp(mio->name, "mac-io") == 0
-				    && mio->n_addrs > 0) {
-					macio_base = (unsigned char *) ioremap
-						(mio->addrs[0].address, 0x40);
-					break;
-				}
-			}
-			/* enable CD sound input */
-			if (macio_base)
-				out_8(macio_base + 0x37, 3);
-		}
-	}
-#endif /* CONFIG_PPC */
-
-	if (!has_sound)
-		return;
-
-	/* Set up sound queue, /dev/audio and /dev/dsp. */
-
-	/* Set default settings. */
-	sq_init();
-
-	/* Set up /dev/sndstat. */
-	state_init();
-
-	/* Set up /dev/mixer. */
-	mixer_init();
-
-	if (!sound.mach.irqinit()) {
-		printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
-		return;
-	}
-#ifdef MODULE
-	irq_installed = 1;
-#endif
-
-	printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
-	       numBufs, bufSize);
-
-	return;
-}
-
-
-static int __init dmasound_setup(char *str)
-{
-	int ints[6];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-
-	/* check the bootstrap parameter for "dmasound=" */
-
-	switch (ints[0]) {
-	case 3:
-		if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
-			printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
-		else
-			catchRadius = ints[3];
-		/* fall through */
-	case 2:
-		if (ints[1] < MIN_BUFFERS)
-			printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
-		else
-			numBufs = ints[1];
-		if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
-			printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
-		else
-			bufSize = ints[2];
-		break;
-	case 0:
-		break;
-	default:
-		printk("dmasound_setup: illegal number of arguments\n");
-		return 0;
-	}
-	
-	return 1;
-}
-
-__setup("dmasound=", dmasound_setup);
-
-
-#ifdef MODULE
-
-int init_module(void)
-{
-	dmasound_init();
-	return 0;
-}
-
-
-void cleanup_module(void)
-{
-	if (irq_installed) {
-		sound_silence();
-		sound.mach.irqcleanup();
-	}
-
-#ifdef CONFIG_PPC
-	sq_release_read_buffers();
-#endif
-	sq_release_buffers();
-
-	if (mixer_unit >= 0)
-		unregister_sound_mixer(mixer_unit);
-	if (state_unit >= 0)
-		unregister_sound_special(state_unit);
-	if (sq_unit >= 0)
-		unregister_sound_dsp(sq_unit);
-}
-
-#endif /* MODULE */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/dmasound.h linux/drivers/sound/dmasound.h
--- v2.3.99-pre3/linux/drivers/sound/dmasound.h	Tue Sep 30 08:46:59 1997
+++ linux/drivers/sound/dmasound.h	Wed Dec 31 16:00:00 1969
@@ -1,36 +0,0 @@
-
-/* linux/drivers/sound/dmasound.h */
-
-/*
- * Minor numbers for the sound driver.
- *
- * Unfortunately Creative called the codec chip of SB as a DSP. For this
- * reason the /dev/dsp is reserved for digitized audio use. There is a
- * device for true DSP processors but it will be called something else.
- * In v3.0 it's /dev/sndproc but this could be a temporary solution.
- */
-
-#define SND_NDEVS	256	/* Number of supported devices */
-#define SND_DEV_CTL	0	/* Control port /dev/mixer */
-#define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM
-				   synthesizer and MIDI output) */
-#define SND_DEV_MIDIN	2	/* Raw midi access */
-#define SND_DEV_DSP	3	/* Digitized voice /dev/dsp */
-#define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
-#define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS	6	/* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
-#define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
-#define SND_DEV_PSS	SND_DEV_SNDPROC
-
-#define DSP_DEFAULT_SPEED	8000
-
-#define ON		1
-#define OFF		0
-
-#define MAX_AUDIO_DEV	5
-#define MAX_MIXER_DEV	2
-#define MAX_SYNTH_DEV	3
-#define MAX_MIDI_DEV	6
-#define MAX_TIMER_DEV	3
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v2.3.99-pre3/linux/drivers/sound/mad16.c	Fri Mar 10 16:40:44 2000
+++ linux/drivers/sound/mad16.c	Mon Mar 27 11:02:54 2000
@@ -791,7 +791,7 @@
 
 		mad_write(MC3_PORT, tmp | 0x04);
 		hw_config->driver_use_1 = SB_MIDI_ONLY;
-		return sb_dsp_detect(hw_config, 0, 0);
+		return sb_dsp_detect(hw_config, 0, 0, NULL);
 #else
 		/* assuming all later Mozart cards are identified as
 		 * either 82C928 or Mozart. If so, following code attempts
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/sb.h linux/drivers/sound/sb.h
--- v2.3.99-pre3/linux/drivers/sound/sb.h	Mon Mar 27 08:08:28 2000
+++ linux/drivers/sound/sb.h	Mon Mar 27 11:02:54 2000
@@ -70,6 +70,13 @@
 typedef struct mixer_def mixer_tab[32][2];
 typedef struct mixer_def mixer_ent;
 
+struct sb_module_options
+{
+	int  esstype;	/* ESS chip type */
+	int  acer;	/* Do acer notebook init? */
+	int  sm_games;	/* Logitech soundman games? */
+};
+
 typedef struct sb_devc {
 	   int dev;
 
@@ -128,7 +135,10 @@
 	   int input_opened;
 	   int midi_broken;
 	   void (*midi_input_intr) (int dev, unsigned char data);
-	   void *midi_irq_cookie;	/* IRQ cookie for the midi */
+	   void *midi_irq_cookie;		/* IRQ cookie for the midi */
+
+	   struct sb_module_options sbmo;	/* Module options */
+
 	} sb_devc;
 	
 /*
@@ -147,7 +157,7 @@
 int sb_dsp_reset (sb_devc *devc);
 void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value);
 unsigned int sb_getmixer (sb_devc *devc, unsigned int port);
-int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio);
+int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo);
 int sb_dsp_init (struct address_info *hw_config);
 void sb_dsp_unload(struct address_info *hw_config, int sbmpu);
 int sb_mixer_init(sb_devc *devc);
@@ -163,7 +173,6 @@
 int sb_audio_open(int dev, int mode);
 void sb_audio_close(int dev);
 
-extern int acer;
 extern sb_devc *last_sb;
 
 /*	From sb_common.c */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.3.99-pre3/linux/drivers/sound/sb_card.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/sound/sb_card.c	Mon Mar 27 11:02:55 2000
@@ -32,6 +32,10 @@
  * 13-03-2000 Added some more cards, thanks to Torsten Werner.
  *  Removed joystick and wavetable code, there are better places for them.
  *  Code cleanup plus some fixes. 
+ *  Alessandro Zummo <azummo@ita.flashnet.it>
+ * 
+ * 26-03-2000 Fixed acer, esstype and sm_games module options.
+ *  Alessandro Zummo <azummo@ita.flashnet.it>
  *
  */
 
@@ -51,6 +55,22 @@
 
 extern void *smw_free;
 
+/*
+ *    Note DMA2 of -1 has the right meaning in the SB16 driver as well
+ *    as here. It will cause either an error if it is needed or a fallback
+ *    to the 8bit channel.
+ */
+
+static int __initdata mpu_io	= 0;
+static int __initdata io	= -1;
+static int __initdata irq	= -1;
+static int __initdata dma	= -1;
+static int __initdata dma16	= -1;   /* Set this for modules that need it */
+static int __initdata type	= 0;    /* Can set this to a specific card type */
+static int __initdata esstype   = 0;	/* ESS chip type */
+static int __initdata acer 	= 0;	/* Do acer notebook init? */
+static int __initdata sm_games 	= 0;	/* Logitech soundman games? */
+
 static void __init attach_sb_card(struct address_info *hw_config)
 {
 	if(!sb_dsp_init(hw_config))
@@ -60,6 +80,8 @@
 
 static int __init probe_sb(struct address_info *hw_config)
 {
+	struct sb_module_options sbmo;
+
 	if (hw_config->io_base == -1 || hw_config->dma == -1 || hw_config->irq == -1)
 	{
 		printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n");
@@ -127,14 +149,21 @@
 	}
 #endif
 
-	/* This is useless since is done by sb_dsp_detect - azummo */
+	/* This is useless since it is done by sb_dsp_detect - azummo */
 	
 	if (check_region(hw_config->io_base, 16))
 	{
 		printk(KERN_ERR "sb_card: I/O port 0x%x is already in use\n\n", hw_config->io_base);
 		return 0;
 	}
-	return sb_dsp_detect(hw_config, 0, 0);
+
+	/* Setup extra module options */
+
+	sbmo.acer 	= acer;
+	sbmo.sm_games	= sm_games;
+	sbmo.esstype	= esstype;
+
+	return sb_dsp_detect(hw_config, 0, 0, &sbmo);
 }
 
 static void __exit unload_sb(struct address_info *hw_config)
@@ -143,25 +172,11 @@
 		sb_dsp_unload(hw_config, sbmpu);
 }
 
-extern int esstype;	/* ESS chip type */
-
 static struct address_info cfg;
 static struct address_info cfg_mpu;
 
 struct pci_dev 	*sb_dev 	= NULL, 
 		*mpu_dev	= NULL;
-/*
- *    Note DMA2 of -1 has the right meaning in the SB16 driver as well
- *    as here. It will cause either an error if it is needed or a fallback
- *    to the 8bit channel.
- */
-
-static int __initdata mpu_io	= 0;
-static int __initdata io	= -1;
-static int __initdata irq	= -1;
-static int __initdata dma	= -1;
-static int __initdata dma16	= -1;   /* Set this for modules that need it */
-static int __initdata type	= 0;    /* Can set this to a specific card type */
 
 
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.3.99-pre3/linux/drivers/sound/sb_common.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/sound/sb_common.c	Mon Mar 27 11:02:55 2000
@@ -53,14 +53,6 @@
 	0, 1, 0, 2, 0, 3, 0, 4
 };
 
-/* Do acer notebook init? */
-int acer = 0;
-
-/* soundman games? */
-int sm_games = 0;
-
-extern int esstype;
-
 void *smw_free = NULL;
 
 /*
@@ -503,12 +495,16 @@
 #endif
 }
 
-int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio)
+int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo)
 {
 	sb_devc sb_info;
 	sb_devc *devc = &sb_info;
 
 	memset((char *) &sb_info, 0, sizeof(sb_info));	/* Zero everything */
+
+	/* Copy module options in place */
+	if(sbmo) memcpy(&devc->sbmo, sbmo, sizeof(struct sb_module_options));
+
 	sb_info.my_mididev = -1;
 	sb_info.my_mixerdev = -1;
 	sb_info.dev = -1;
@@ -553,7 +549,7 @@
 		printk("Yamaha PCI mode.\n");
 	}
 	
-	if (acer)
+	if (devc->sbmo.acer)
 	{
 		cli();
 		inb(devc->base + 0x09);
@@ -1294,10 +1290,6 @@
 #endif
 	unload_uart401(hw_config);
 }
-
-MODULE_PARM(acer, "i");
-MODULE_PARM(sm_games, "i");
-MODULE_PARM(esstype, "i");
 
 EXPORT_SYMBOL(sb_dsp_init);
 EXPORT_SYMBOL(sb_dsp_detect);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/sb_ess.c linux/drivers/sound/sb_ess.c
--- v2.3.99-pre3/linux/drivers/sound/sb_ess.c	Tue Dec 14 01:27:24 1999
+++ linux/drivers/sound/sb_ess.c	Mon Mar 27 11:02:55 2000
@@ -196,8 +196,6 @@
 #define ESSTYPE_LIKE20	-1		/* Mimic 2.0 behaviour					*/
 #define ESSTYPE_DETECT	0		/* Mimic 2.0 behaviour					*/
 
-int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */
-
 #define SUBMDL_ES1788	0x10	/* Subtype ES1788 for specific handling */
 #define SUBMDL_ES1868	0x11	/* Subtype ES1868 for specific handling */
 #define SUBMDL_ES1869	0x12	/* Subtype ES1869 for specific handling */
@@ -1066,7 +1064,7 @@
 		char *chip = NULL;
 		int submodel = -1;
 
-		switch (esstype) {
+		switch (devc->sbmo.esstype) {
 		case ESSTYPE_DETECT:
 		case ESSTYPE_LIKE20:
 			break;
@@ -1098,12 +1096,12 @@
 			submodel = SUBMDL_ES1888;
 			break;
 		default:
-			printk (KERN_ERR "Invalid esstype=%d specified\n", esstype);
+			printk (KERN_ERR "Invalid esstype=%d specified\n", devc->sbmo.esstype);
 			return 0;
 		};
 		if (submodel != -1) {
 			devc->submodel = submodel;
-			sprintf (modelname, "ES%d", esstype);
+			sprintf (modelname, "ES%d", devc->sbmo.esstype);
 			chip = modelname;
 		};
 		if (chip == NULL && (ess_minor & 0x0f) < 8) {
@@ -1116,7 +1114,7 @@
 		 * If Nothing detected yet, and we want 2.0 behaviour...
 		 * Then let's assume it's ES1688.
 		 */
-		if (chip == NULL && esstype == ESSTYPE_LIKE20) {
+		if (chip == NULL && devc->sbmo.esstype == ESSTYPE_LIKE20) {
 			chip = "ES1688";
 		};
 
@@ -1185,11 +1183,11 @@
 
 	    printk ( KERN_INFO "ESS chip %s %s%s\n"
                , chip
-               , ( esstype == ESSTYPE_DETECT || esstype == ESSTYPE_LIKE20
+               , ( devc->sbmo.esstype == ESSTYPE_DETECT || devc->sbmo.esstype == ESSTYPE_LIKE20
                  ? "detected"
                  : "specified"
                  )
-               , ( esstype == ESSTYPE_LIKE20
+               , ( devc->sbmo.esstype == ESSTYPE_LIKE20
                  ? " (kernel 2.0 compatible)"
                  : ""
                  )
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v2.3.99-pre3/linux/drivers/sound/sb_mixer.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/sound/sb_mixer.c	Mon Mar 27 11:02:55 2000
@@ -642,11 +642,10 @@
 {
 	char name[32];
 	int i;
-	extern int sm_games;
 
 	sprintf(name, "SB_%d", devc->sbmixnum);
 
-	if (sm_games)
+	if (devc->sbmo.sm_games)
 		devc->levels = load_mixer_volumes(name, smg_default_levels, 1);
 	else
 		devc->levels = load_mixer_volumes(name, sb_default_levels, 1);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h
--- v2.3.99-pre3/linux/drivers/sound/sound_calls.h	Tue Mar  7 14:32:26 2000
+++ linux/drivers/sound/sound_calls.h	Sun Apr  2 15:45:06 2000
@@ -89,10 +89,3 @@
 
 /*      From midi_synth.c       */
 void do_midi_msg (int synthno, unsigned char *msg, int mlen);
-
-#ifdef FIXED_LOWLEVEL_SOUND
-/*	From aedsp16.c */
-int InitAEDSP16_SBPRO(struct address_info *hw_config);
-int InitAEDSP16_MSS(struct address_info *hw_config);
-int InitAEDSP16_MPU401(struct address_info *hw_config);
-#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
--- v2.3.99-pre3/linux/drivers/sound/sound_core.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/sound/sound_core.c	Sun Apr  2 15:38:54 2000
@@ -218,7 +218,7 @@
 static struct sound_unit *chains[16];
 
 /**
- *	register_sound_special
+ *	register_sound_special - register a special sound node
  *	@fops: File operations for the driver
  *	@unit: Unit number to allocate
  *
@@ -288,7 +288,7 @@
 EXPORT_SYMBOL(register_sound_special);
 
 /**
- *	register_sound_mixer
+ *	register_sound_mixer - register a mixer device
  *	@fops: File operations for the driver
  *	@dev: Unit number to allocate
  *
@@ -306,7 +306,7 @@
 EXPORT_SYMBOL(register_sound_mixer);
 
 /**
- *	register_sound_midi
+ *	register_sound_midi - register a midi device
  *	@fops: File operations for the driver
  *	@dev: Unit number to allocate
  *
@@ -329,7 +329,7 @@
  */
  
 /**
- *	register_sound_dsp
+ *	register_sound_dsp - register a DSP device
  *	@fops: File operations for the driver
  *	@dev: Unit number to allocate
  *
@@ -350,7 +350,7 @@
 EXPORT_SYMBOL(register_sound_dsp);
 
 /**
- *	register_sound_synth
+ *	register_sound_synth - register a synth device
  *	@fops: File operations for the driver
  *	@dev: Unit number to allocate
  *
@@ -369,7 +369,7 @@
 EXPORT_SYMBOL(register_sound_synth);
 
 /**
- *	unregister_sound_special
+ *	unregister_sound_special - unregister a special sound device
  *	@unit: Unit number to allocate
  *
  *	Release a sound device that was allocated with register_sound_special.
@@ -385,7 +385,7 @@
 EXPORT_SYMBOL(unregister_sound_special);
 
 /**
- *	unregister_sound_mixer
+ *	unregister_sound_mixer - unregister a mixer
  *	@unit: Unit number to allocate
  *
  *	Release a sound device that was allocated with register_sound_mixer.
@@ -400,7 +400,7 @@
 EXPORT_SYMBOL(unregister_sound_mixer);
 
 /**
- *	unregister_sound_midi
+ *	unregister_sound_midi - unregister a midi device
  *	@unit: Unit number to allocate
  *
  *	Release a sound device that was allocated with register_sound_midi.
@@ -415,7 +415,7 @@
 EXPORT_SYMBOL(unregister_sound_midi);
 
 /**
- *	unregister_sound_dsp
+ *	unregister_sound_dsp - unregister a DSP device
  *	@unit: Unit number to allocate
  *
  *	Release a sound device that was allocated with register_sound_dsp.
@@ -433,7 +433,7 @@
 EXPORT_SYMBOL(unregister_sound_dsp);
 
 /**
- *	unregister_sound_synth
+ *	unregister_sound_synth - unregister a synth device
  *	@unit: Unit number to allocate
  *
  *	Release a sound device that was allocated with register_sound_synth.
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.3.99-pre3/linux/drivers/sound/soundcard.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/sound/soundcard.c	Sun Apr  2 15:46:00 2000
@@ -46,14 +46,6 @@
 #include "soundmodule.h"
 
 
-#if defined(CONFIG_LOWLEVEL_SOUND) && !defined MODULE
-extern void sound_preinit_lowlevel_drivers(void);
-extern void sound_init_lowlevel_drivers(void);
-#endif
-
-/* From obsolete legacy.h */
-#define SELECTED_SOUND_OPTIONS 0x0
-
 struct notifier_block *sound_locker=(struct notifier_block *)0;
 static int lock_depth = 0;
 
@@ -65,7 +57,6 @@
 #endif
 
 static int      chrdev_registered = 0;
-static int      is_unloading = 0;
 
 /*
  * Table for permanently allocated memory (used when unloading the module)
@@ -80,7 +71,6 @@
 int             sound_dmap_flag = 0;
 #endif
 
-static int      soundcard_configured = 0;
 static char     dma_alloc_map[MAX_DMA_CHANNELS] = {0};
 
 #define DMA_MAP_UNAVAIL		0
@@ -101,17 +91,14 @@
 {
 	int             i, n;
 
-	for (i = 0; i < num_mixer_volumes; i++)
-	{
-		if (strcmp(name, mixer_vols[i].name) == 0)
-		{
+	for (i = 0; i < num_mixer_volumes; i++) {
+		if (strcmp(name, mixer_vols[i].name) == 0) {
 			if (present)
 				mixer_vols[i].num = i;
 			return mixer_vols[i].levels;
 		}
 	}
-	if (num_mixer_volumes >= MAX_MIXER_DEV)
-	{
+	if (num_mixer_volumes >= MAX_MIXER_DEV) {
 		printk(KERN_ERR "Sound: Too many mixers (%s)\n", name);
 		return levels;
 	}
@@ -229,26 +216,15 @@
 
 static int sound_open(struct inode *inode, struct file *file)
 {
-	int dev, retval;
+	int dev = MINOR(inode->i_rdev);
+	int retval;
 
-	if (is_unloading) {
-		/* printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/
-		return -EBUSY;
-	}
-	dev = MINOR(inode->i_rdev);
-	if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) {
-		/* printk("SoundCard Error: The sound system has not been configured\n");*/
-		return -ENXIO;
-	}
 	DEB(printk("sound_open(dev=%d)\n", dev));
 	if ((dev >= SND_NDEVS) || (dev < 0)) {
 		/* printk(KERN_ERR "Invalid minor device %d\n", dev);*/
 		return -ENXIO;
 	}
 	switch (dev & 0x0f) {
-	case SND_DEV_STATUS:
-		break;
-
 	case SND_DEV_CTL:
 		dev >>= 4;
 		if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {
@@ -296,7 +272,6 @@
 
 	DEB(printk("sound_release(dev=%d)\n", dev));
 	switch (dev & 0x0f) {
-	case SND_DEV_STATUS:
 	case SND_DEV_CTL:
 		break;
 		
@@ -470,45 +445,38 @@
 	dev_class = dev & 0x0f;
 	dev >>= 4;
 
-	if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO)
-	{
-/*		printk("Sound: mmap() not supported for other than audio devices\n");*/
+	if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) {
+		printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
 		return -EINVAL;
 	}
 	if (vma->vm_flags & VM_WRITE)	/* Map write and read/write to the output buf */
 		dmap = audio_devs[dev]->dmap_out;
 	else if (vma->vm_flags & VM_READ)
 		dmap = audio_devs[dev]->dmap_in;
-	else
-	{
-/*		printk("Sound: Undefined mmap() access\n");*/
+	else {
+		printk(KERN_ERR "Sound: Undefined mmap() access\n");
 		return -EINVAL;
 	}
 
-	if (dmap == NULL)
-	{
-/*		printk("Sound: mmap() error. dmap == NULL\n");*/
+	if (dmap == NULL) {
+		printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
 		return -EIO;
 	}
-	if (dmap->raw_buf == NULL)
-	{
-/*		printk("Sound: mmap() called when raw_buf == NULL\n");*/
+	if (dmap->raw_buf == NULL) {
+		printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
 		return -EIO;
 	}
-	if (dmap->mapping_flags)
-	{
-/*		printk("Sound: mmap() called twice for the same DMA buffer\n");*/
+	if (dmap->mapping_flags) {
+		printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
 		return -EIO;
 	}
-	if (vma->vm_pgoff != 0)
-	{
-/*		printk("Sound: mmap() offset must be 0.\n");*/
+	if (vma->vm_pgoff != 0) {
+		printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
 		return -EINVAL;
 	}
 	size = vma->vm_end - vma->vm_start;
 
-	if (size != dmap->bytes_in_use)
-	{
+	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),
@@ -546,19 +514,14 @@
 static int create_special_devices(void)
 {
 	int seq1,seq2;
-	int sndstat=register_sound_special(&oss_sound_fops, 6);
-	if(sndstat==-1)
-		goto bad1;
 	seq1=register_sound_special(&oss_sound_fops, 1);
 	if(seq1==-1)
-		goto bad2;
+		goto bad;
 	seq2=register_sound_special(&oss_sound_fops, 8);
 	if(seq2!=-1)
 		return 0;
 	unregister_sound_special(1);
-bad2:
-	unregister_sound_special(6);		
-bad1:	
+bad:
 	return -1;
 }
 
@@ -594,30 +557,27 @@
 /* Register/unregister audio entries */
 static void soundcard_register_devfs (int do_register)
 {
-    char name_buf[32];
-    int i, j, num;
-
-    for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++)
-    {
-	num = (dev_list[i].num == NULL) ? 0 : *dev_list[i].num;
-	for (j = 0; j < num || j == 0; j++)
-	{
-	    soundcard_make_name (name_buf, dev_list[i].name, j);
-	    if (do_register)
-		devfs_register (NULL, name_buf, 0, DEVFS_FL_NONE,
-				SOUND_MAJOR, dev_list[i].minor+ (j* 0x10),
-				S_IFCHR | dev_list[i].mode, 0, 0,
-				&oss_sound_fops, NULL);
-	    else
-	    {
-		devfs_handle_t de;
+	char name_buf[32];
+	int i, j, num;
 
-		de = devfs_find_handle (NULL, name_buf, 0, 0, 0,
+	for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) {
+		num = (dev_list[i].num == NULL) ? 0 : *dev_list[i].num;
+		for (j = 0; j < num || j == 0; j++) {
+			soundcard_make_name (name_buf, dev_list[i].name, j);
+			if (do_register)
+				devfs_register (NULL, name_buf, 0, DEVFS_FL_NONE,
+					SOUND_MAJOR, dev_list[i].minor+ (j* 0x10),
+					S_IFCHR | dev_list[i].mode, 0, 0,
+					&oss_sound_fops, NULL);
+			else {
+				devfs_handle_t de;
+				
+				de = devfs_find_handle (NULL, name_buf, 0, 0, 0,
 					DEVFS_SPECIAL_CHR, 0);
-		devfs_unregister (de);
-	    }
+				devfs_unregister (de);
+			}
+		}
 	}
-    }
 }
 
 #ifdef MODULE
@@ -638,10 +598,6 @@
 	chrdev_registered = 1;
 #endif
 
-	soundcard_configured = 1;
-
-	audio_init_devices();
-
 	soundcard_register_devfs(1); /* register after we know # of devices */
 }
 
@@ -650,14 +606,9 @@
 static void destroy_special_devices(void)
 {
 	unregister_sound_special(6);
-	unregister_sound_special(1);
 	unregister_sound_special(8);
 }
 
-static int      sound[20] = {
-	0
-};
-
 static int dmabuf = 0;
 static int dmabug = 0;
 
@@ -668,12 +619,12 @@
 {
 	int             err;
 
+#ifdef CONFIG_PCI
 	if(dmabug)
 		isa_dma_bridge_buggy = dmabug;
-
+#endif
 	err = create_special_devices();
-	if (err)
-	{
+	if (err) {
 		printk(KERN_ERR "sound: driver already loaded/included in kernel\n");
 		return err;
 	}
@@ -695,10 +646,8 @@
 	int i;
 
 	if (MOD_IN_USE)
-	{
 		return;
-	}
-        remove_proc_entry("sound", NULL);
+
 	soundcard_register_devfs (0);
 	if (chrdev_registered)
 		destroy_special_devices();
@@ -708,17 +657,13 @@
 	sequencer_unload();
 
 	for (i = 0; i < MAX_DMA_CHANNELS; i++)
-	{
-		if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
-		{
+		if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) {
 			printk(KERN_ERR "Sound: Hmm, DMA%d was left allocated - fixed\n", i);
 			sound_free_dma(i);
 		}
-	}
+
 	for (i = 0; i < sound_nblocks; i++)
-	{
 		vfree(sound_mem_blocks[i]);
-	}
 
 }
 #endif
@@ -739,16 +684,14 @@
 {
 	unsigned long   flags;
 
-	if (!valid_dma(chn))
-	{
+	if (!valid_dma(chn)) {
 		printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn);
 		return 1;
 	}
 	save_flags(flags);
 	cli();
 
-	if (dma_alloc_map[chn] != DMA_MAP_FREE)
-	{
+	if (dma_alloc_map[chn] != DMA_MAP_FREE) {
 		printk("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]);
 		restore_flags(flags);
 		return 1;
@@ -760,8 +703,7 @@
 
 void sound_free_dma(int chn)
 {
-	if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL)
-	{
+	if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL) {
 		/* printk( "sound_free_dma: Bad access to DMA channel %d\n",  chn); */
 		return;
 	}
@@ -776,8 +718,7 @@
 	save_flags(flags);
 	cli();
 
-	if (dma_alloc_map[chn] != DMA_MAP_BUSY)
-	{
+	if (dma_alloc_map[chn] != DMA_MAP_BUSY) {
 		printk(KERN_ERR "sound_close_dma: Bad access to DMA channel %d\n", chn);
 		restore_flags(flags);
 		return;
@@ -799,8 +740,7 @@
 {
 	extern unsigned long seq_time;
 
-	if (count < 0)
-	{
+	if (count < 0) {
 		seq_timer.expires = (-count) + jiffies;
 		add_timer(&seq_timer);
 		return;
@@ -879,8 +819,7 @@
 	 *	Normalise the lock count by calling the entry directly. We
 	 *	have to call the module as it owns its own use counter
 	 */
-	while(ct<lock_depth)
-	{
+	while(ct<lock_depth) {
 		bl->notifier_call(bl, 1, 0);
 		ct++;
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v2.3.99-pre3/linux/drivers/sound/trix.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/sound/trix.c	Mon Mar 27 11:02:55 2000
@@ -318,7 +318,7 @@
 	sb_initialized = 1;
 
 	hw_config->name = "AudioTrix SB";
-	return sb_dsp_detect(hw_config, 0, 0);
+	return sb_dsp_detect(hw_config, 0, 0, NULL);
 }
 
 static void __init attach_trix_sb(struct address_info *hw_config)
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- v2.3.99-pre3/linux/drivers/sound/via82cxxx_audio.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/sound/via82cxxx_audio.c	Mon Mar 27 11:02:55 2000
@@ -486,7 +486,7 @@
 		return 0;
 	}
 	DPRINTK("EXIT after sb_dsp_detect\n");
-	return sb_dsp_detect(hw_config, 0, 0);
+	return sb_dsp_detect(hw_config, 0, 0, NULL);
 }
 
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/telephony/phonedev.c linux/drivers/telephony/phonedev.c
--- v2.3.99-pre3/linux/drivers/telephony/phonedev.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/telephony/phonedev.c	Sun Apr  2 15:38:54 2000
@@ -28,6 +28,7 @@
 #include <asm/system.h>
 
 #include <linux/kmod.h>
+#include <linux/sem.h>
 
 
 #define PHONE_NUM_DEVICES	256
@@ -37,6 +38,7 @@
  */
 
 static struct phone_device *phone_device[PHONE_NUM_DEVICES];
+static DECLARE_MUTEX(phone_lock);
 
 /*
  *    Open a phone device.
@@ -45,29 +47,37 @@
 static int phone_open(struct inode *inode, struct file *file)
 {
 	unsigned int minor = MINOR(inode->i_rdev);
-	int err;
+	int err = 0;
 	struct phone_device *p;
 
 	if (minor >= PHONE_NUM_DEVICES)
 		return -ENODEV;
 
+	down(&phone_lock);
 	p = phone_device[minor];
 	if (p == NULL) {
 		char modname[32];
 
+		up(&phone_lock);
 		sprintf(modname, "char-major-%d-%d", PHONE_MAJOR, minor);
 		request_module(modname);
+		down(&phone_lock);
 		p = phone_device[minor];
 		if (p == NULL)
-			return -ENODEV;
+		{
+			err=-ENODEV;
+			goto end;
+		}
 	}
 	if (p->open) {
 		err = p->open(p, file);	/* Tell the device it is open */
 		if (err)
-			return err;
+			goto end;
 	}
 	file->f_op = p->f_op;
-	return 0;
+end:
+	up(&phone_lock);
+	return err;
 }
 
 /*
@@ -87,14 +97,18 @@
 		base = unit;
 		end = unit + 1;  /* enter the loop at least one time */
 	}
+	
+	down(&phone_lock);
 	for (i = base; i < end; i++) {
 		if (phone_device[i] == NULL) {
 			phone_device[i] = p;
 			p->minor = i;
 			MOD_INC_USE_COUNT;
+			up(&phone_lock);
 			return 0;
 		}
 	}
+	up(&phone_lock);
 	return -ENFILE;
 }
 
@@ -104,9 +118,11 @@
 
 void phone_unregister_device(struct phone_device *pfd)
 {
+	down(&phone_lock);
 	if (phone_device[pfd->minor] != pfd)
 		panic("phone: bad unregister");
 	phone_device[pfd->minor] = NULL;
+	up(&phone_lock);
 	MOD_DEC_USE_COUNT;
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.99-pre3/linux/drivers/usb/Config.in	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/Config.in	Mon Apr 10 22:53:15 2000
@@ -6,6 +6,10 @@
 
 tristate 'Support for USB' CONFIG_USB
 if [ ! "$CONFIG_USB" = "n" ]; then
+   bool '  USB verbose debug messages' CONFIG_USB_DEBUG
+
+comment 'Miscellaneous USB options'
+   bool '  Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
 
 comment 'USB Controllers'
    if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
@@ -13,19 +17,13 @@
    fi
    if [ "$CONFIG_USB_UHCI" != "y" ]; then
       dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
-      if [ "$CONFIG_USB_UHCI_ALT" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-         bool '    UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
-      fi
    fi
    dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
 
-comment 'Miscellaneous USB options'
-   bool '  Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
-
 comment 'USB Devices'
    dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
    dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
-   dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB
+   dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
    dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
    dep_tristate '  USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
    if [ "$CONFIG_USB_SERIAL" != "n" ]; then
@@ -38,9 +36,8 @@
       fi
       bool '    USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
    fi
-   dep_tristate '  USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
-   dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB
-   dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB
+   dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+   dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	   dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB
@@ -52,12 +49,12 @@
    dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
    dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      dep_tristate '  PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB
-      dep_tristate '  USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB
+      dep_tristate '  PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET
+      dep_tristate '  USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET
       dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB
-      dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB
+      dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV
    fi
-   
+
 comment 'USB HID'
    dep_tristate '  USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB
    if [ "$CONFIG_USB_HID" != "y" ]; then
@@ -69,12 +66,8 @@
    dep_tristate '  Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB
    dep_tristate '  Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB
    if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
-      bool '    Mix all mice into one device' CONFIG_INPUT_MOUSEDEV_MIX
-      bool '    Support for digitizers' CONFIG_INPUT_MOUSEDEV_DIGITIZER
-      if [ "$CONFIG_INPUT_MOUSEDEV_DIGITIZER" != "n" ]; then
-         int '     Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
-         int '      Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
-      fi
+      int '   Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
+      int '   Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
    fi
    dep_tristate '  Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB
    dep_tristate '  Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.99-pre3/linux/drivers/usb/Makefile	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/Makefile	Mon Mar 27 14:25:28 2000
@@ -42,7 +42,7 @@
 
 ifeq ($(CONFIG_USB_SERIAL),y)
 	SUB_DIRS += serial
-	obj-y += serial/serial.o
+	obj-y += serial/usb-serial.o
 else
 	ifeq ($(CONFIG_USB_SERIAL),m)
 		MOD_IN_SUB_DIRS += serial
@@ -71,7 +71,6 @@
 obj-$(CONFIG_USB_ACM)		+= acm.o
 obj-$(CONFIG_USB_PRINTER)	+= printer.o
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
-obj-$(CONFIG_USB_CPIA)		+= cpia.o
 obj-$(CONFIG_USB_IBMCAM)	+= ibmcam.o
 obj-$(CONFIG_USB_DC2XX)		+= dc2xx.o
 obj-$(CONFIG_USB_MDC800)   += mdc800.o
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.99-pre3/linux/drivers/usb/acm.c	Fri Mar 10 16:40:44 2000
+++ linux/drivers/usb/acm.c	Wed Apr  5 16:58:38 2000
@@ -52,6 +52,10 @@
 #define DEBUG
 #include <linux/usb.h>
 
+void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
+			unsigned minor);
+void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
+
 /*
  * CMSPAR, some architectures can't have space and mark parity.
  */
@@ -143,6 +147,7 @@
 };
 
 static struct usb_driver acm_driver;
+static struct tty_driver acm_tty_driver;
 static struct acm *acm_table[ACM_TTY_MINORS] = { NULL, /* .... */ };
 
 #define ACM_READY(acm)	(acm && acm->dev && acm->used)
@@ -306,20 +311,19 @@
 
 	if (!acm || !acm->used) return;
 
-	MOD_DEC_USE_COUNT;
-
-	if (--acm->used) return;
-	
-	if (acm->dev) {
-		acm_set_control(acm, acm->ctrlout = 0);
-		usb_unlink_urb(&acm->ctrlurb);
-		usb_unlink_urb(&acm->writeurb);
-		usb_unlink_urb(&acm->readurb);
-		return;
+	if (!--acm->used) {
+		if (acm->dev) {
+			acm_set_control(acm, acm->ctrlout = 0);
+			usb_unlink_urb(&acm->ctrlurb);
+			usb_unlink_urb(&acm->writeurb);
+			usb_unlink_urb(&acm->readurb);
+		} else {
+			tty_unregister_devfs(&acm_tty_driver, acm->minor);
+			acm_table[acm->minor] = NULL;
+			kfree(acm);
+		}
 	}
-
-	acm_table[acm->minor] = NULL;
-	kfree(acm);
+	MOD_DEC_USE_COUNT;
 }
 
 static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
@@ -572,6 +576,7 @@
 		usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
 		usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
 
+		tty_register_devfs(&acm_tty_driver, 0, minor);
 		return acm_table[minor] = acm;
 	}
 
@@ -599,6 +604,7 @@
 	usb_driver_release_interface(&acm_driver, acm->iface + 1);
 
 	if (!acm->used) {
+		tty_unregister_devfs(&acm_tty_driver, acm->minor);
 		acm_table[acm->minor] = NULL;
 		kfree(acm);
 		return;
@@ -630,14 +636,14 @@
 
 static struct tty_driver acm_tty_driver = {
 	magic:			TTY_DRIVER_MAGIC,
-	driver_name:		"usb",
-	name:			"ttyACM",
+	driver_name:		"acm",
+	name:			"usb/acm/%d",
 	major:			ACM_TTY_MAJOR,
 	minor_start:		0,
 	num:			ACM_TTY_MINORS,
 	type:			TTY_DRIVER_TYPE_SERIAL,
 	subtype:		SERIAL_TYPE_NORMAL,
-	flags:			TTY_DRIVER_REAL_RAW,
+	flags:			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
 
 	refcount:		&acm_tty_refcount,
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.3.99-pre3/linux/drivers/usb/audio.c	Fri Mar 10 16:40:44 2000
+++ linux/drivers/usb/audio.c	Mon Mar 27 10:23:21 2000
@@ -1395,25 +1395,30 @@
 
 /* --------------------------------------------------------------------- */
 
-static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt)
+static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int rate)
 {
 	unsigned int i;
 
-	/* first find an exact match */
-	for (i = 0; i < nr; i++)
-		if (afp[i].format == fmt)
+	/* first find an exact match, taking both format and sample rate into account,
+	   but ignore stereo bit */
+	for (i = 0; i < nr; i++) {
+		if (afp[i].format == (fmt & ~AFMT_STEREO) && rate >= afp[i].sratelo && rate <= afp[i].sratehi)
 			return i;
+	}
+		
 	/* second find a match with the same stereo/mono and 8bit/16bit property */
 	for (i = 0; i < nr; i++)
 		if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) &&
-		    !AFMT_IS16BIT(afp[i].format) == !AFMT_IS16BIT(fmt))
+		    !AFMT_IS16BIT(afp[i].format) == !AFMT_IS16BIT(fmt) && 
+		    rate >= afp[i].sratelo && rate <= afp[i].sratehi)
 			return i;
 	/* third find a match with the same number of channels */
 	for (i = 0; i < nr; i++)
-		if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt))
+		if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) && 
+		    rate >= afp[i].sratelo && rate <= afp[i].sratehi)
 			return i;
-	/* return anything */
-	return 0;
+	/* return failure */
+	return -1;
 }
 
 static int set_format_in(struct usb_audiodev *as)
@@ -1432,7 +1437,13 @@
 	if (u->interface < 0 || u->interface >= config->bNumInterfaces)
 		return 0;
 	iface = &config->interface[u->interface];
-	fmtnr = find_format(as->fmtin, as->numfmtin, d->format);
+
+	fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate);
+	if (fmtnr < 0) {
+		printk(KERN_ERR "usbaudio: set_format_in(): failed to find desired format/speed combination.\n");
+		return -1;
+	}
+
 	fmt = as->fmtin + fmtnr;
 	alts = &iface->altsetting[fmt->altsetting];
 	u->format = fmt->format;
@@ -1513,7 +1524,13 @@
 	if (u->interface < 0 || u->interface >= config->bNumInterfaces)
 		return 0;
 	iface = &config->interface[u->interface];
-	fmtnr = find_format(as->fmtout, as->numfmtout, d->format);
+
+	fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate);
+	if (fmtnr < 0) {
+		printk(KERN_ERR "usbaudio: set_format_out(): failed to find desired format/speed combination.\n");
+		return -1;
+	}
+
 	fmt = as->fmtout + fmtnr;
 	u->format = fmt->format;
 	alts = &iface->altsetting[fmt->altsetting];
@@ -3330,7 +3347,7 @@
 	struct usb_interface *iface;
 	unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
 	unsigned char *p1;
-	unsigned int i, j, numifin = 0, numifout = 0;
+	unsigned int i, j, k, numifin = 0, numifout = 0;
 	
 	if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL)))
 		return NULL;
@@ -3377,12 +3394,25 @@
 			       dev->devnum, ctrlif, j);
 			continue;
 		}
-		if (iface->num_altsetting < 2 ||
-		    iface->altsetting[0].bNumEndpoints > 0) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u altsetting 0 not zero bandwidth\n",
-			       dev->devnum, ctrlif);
+		if (iface->num_altsetting == 0) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has no working interface.\n", dev->devnum, ctrlif);
+			continue;
+		}
+		if (iface->num_altsetting == 1) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif);
 			continue;
 		}
+		if (iface->altsetting[0].bNumEndpoints > 0) {
+			/* Check all endpoints; should they all have a bandwidth of 0 ? */
+			for (k = 0; k < iface->altsetting[0].bNumEndpoints; k++) {
+				if (iface->altsetting[0].endpoint[k].wMaxPacketSize > 0) {
+					printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k);
+					break;
+				}
+			}
+			if (k < iface->altsetting[0].bNumEndpoints)
+				continue;
+		}
 		if (iface->altsetting[1].bNumEndpoints < 1) {
 			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n",
 			       dev->devnum, ctrlif, j);
@@ -3418,7 +3448,7 @@
 		p1 = find_csinterface_descriptor(buffer, buflen, p1, OUTPUT_TERMINAL, ctrlif, -1);
 	}
 
- ret:
+ret:
 	if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) {
 		kfree(s);
 		return NULL;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/audio.h linux/drivers/usb/audio.h
--- v2.3.99-pre3/linux/drivers/usb/audio.h	Sat Oct  9 11:47:50 1999
+++ linux/drivers/usb/audio.h	Mon Mar 27 10:23:21 2000
@@ -30,7 +30,7 @@
 #define MAX_FREQ			16
 #define MAX_IFACE			8
 #define MAX_FORMAT			8
-#define MAX_ALT				8
+#define MAX_ALT				32 	/* Sorry, we need quite a few for the Philips webcams */
 
 struct usb_audio_terminal
 {	
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.99-pre3/linux/drivers/usb/cpia.c	Fri Mar 10 16:40:44 2000
+++ linux/drivers/usb/cpia.c	Wed Dec 31 16:00:00 1969
@@ -1,1425 +0,0 @@
-/*
- * USB CPiA Video Camera driver
- *
- * Supports CPiA based Video Cameras. Many manufacturers use this chipset.
- *
- * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.com
- * (C) Copyright 1999 Randy Dunlap
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/videodev.h>
-#include <linux/vmalloc.h>
-#include <linux/wrapper.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-
-#include <asm/io.h>
-
-#include "cpia.h"
-
-static int debug = 0;
-MODULE_PARM(debug, "i");
-
-/* Video Size 384 x 288 x 3 bytes for RGB */
-/* 384 because xawtv tries to grab 384 even though we tell it 352 is our max */
-#define MAX_FRAME_SIZE (384 * 288 * 3)
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
-
-static struct usb_driver cpia_driver;
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-	unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-
-	if (!pgd_none(*pgd)) {
-		pmd = pmd_offset(pgd, adr);
-		if (!pmd_none(*pmd)) {
-			ptep = pte_offset(pmd, adr);
-			pte = *ptep;
-			if (pte_present(pte))
-				ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1));
-		}
-	}
-	MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
-	unsigned long kva, ret;
-
-	kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-	ret = virt_to_bus((void *)kva);
-	MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
-	unsigned long va, kva, ret;
-
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = virt_to_bus((void *)kva);
-	MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
-	unsigned long va, kva, ret;
-
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = __pa(kva);
-	MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-static void *rvmalloc(unsigned long size)
-{
-	void *mem;
-	unsigned long adr, page;
-
-	/* Round it off to PAGE_SIZE */
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
-
-	mem = vmalloc(size);
-	if (!mem)
-		return NULL;
-
-	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-	adr = (unsigned long) mem;
-	while (size > 0) {
-		page = kvirt_to_pa(adr);
-		mem_map_reserve(MAP_NR(__va(page)));
-		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
-	}
-
-	return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
-	unsigned long adr, page;
-
-	if (!mem)
-		return;
-
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
-
-	adr=(unsigned long) mem;
-	while (size > 0) {
-		page = kvirt_to_pa(adr);
-		mem_map_unreserve(MAP_NR(__va(page)));
-		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
-	}
-	vfree(mem);
-}
-
-static int usb_cpia_get_version(struct usb_device *dev, void *buf)
-{
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		USB_REQ_CPIA_GET_VERSION,
-		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		0, 0, buf, 4, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
-{
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		USB_REQ_CPIA_GET_PNP_ID,
-		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		0, 0, buf, 6, HZ);
-}
-#endif
-
-#ifdef NOTUSED
-static int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
-{
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		USB_REQ_CPIA_GET_CAMERA_STATUS,
-		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		0, 0, buf, 8, HZ);
-}
-#endif
-
-static int usb_cpia_goto_hi_power(struct usb_device *dev)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_GOTO_HI_POWER, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
-{
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		USB_REQ_CPIA_GET_VP_VERSION,
-		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		0, 0, buf, 4, HZ);
-}
-
-static int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_SET_SENSOR_FPS,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		(sensorbaserate << 8) + sensorclkdivisor, 0, NULL, 0, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_GRAB_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		streamstartline << 8, 0, NULL, 0, HZ);
-}
-#endif
-
-static int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_UPLOAD_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		forceupload, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_SET_GRAB_MODE,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE, continuousgrab,
-		0, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_SET_FORMAT,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		(subsample << 8) + size, order, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_roi(struct usb_device *dev, int colstart, int colend, int rowstart, int rowend)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_SET_ROI,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		(colend << 8) + colstart, (rowend << 8) + rowstart,
-		NULL, 0, HZ);
-}
-
-static int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_SET_COMPRESSION,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		(decimation << 8) + compmode, 0, NULL, 0, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_set_compression_target(struct usb_device *dev, int target, int targetfr, int targetq)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_SET_COMPRESSION_TARGET,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		(targetfr << 8) + target, targetq, NULL, 0, HZ);
-}
-#endif
-
-#ifdef NOTUSED
-static int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_INIT_STREAM_CAP,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		(streamstartline << 8) + skipframes, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_finistreamcap(struct usb_device *dev)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_FINI_STREAM_CAP,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_startstreamcap(struct usb_device *dev)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_START_STREAM_CAP,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_endstreamcap(struct usb_device *dev)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CPIA_END_STREAM_CAP,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-#endif
-
-/* How much data is left in the scratch buf? */
-#define scratch_left(x)	(cpia->scratchlen - (int)((char *)x - (char *)cpia->scratch))
-
-static void cpia_parse_data(struct usb_cpia *cpia)
-{
-	struct cpia_frame *frame, *pframe;
-	unsigned char *data = cpia->scratch;
-	unsigned long left;
-	long copylen = 0;
-
-	/* Grab the current frame and the previous frame */
-	frame = &cpia->frame[cpia->curframe];
-	pframe = &cpia->frame[(cpia->curframe - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES];
-
-	while (1) {
-		if (!scratch_left(data))
-			goto out;
-
-		switch (frame->scanstate) {
-		case STATE_SCANNING:
-		{
-			struct cpia_frame_header *header;
-
-			/* We need at least 2 bytes for the magic value */
-			if (scratch_left(data) < 2)
-				goto out;
-
-			header = (struct cpia_frame_header *)data;
-
-			if (be16_to_cpup(&header->magic) == CPIA_MAGIC) {
-				frame->scanstate = STATE_HEADER;
-				break;
-			}
-
-			/* Woops, lost the header, find the end of the frame */
-			if (scratch_left(data) < 4)
-				goto out;
-
-			/* See if we found the end of the frame */
-			while (scratch_left(data) >= 4) {
-				if (*((__u32 *)data) == 0xFFFFFFFF) {
-					data += 4;
-					if (debug >= 1)
-						printk(KERN_INFO "cpia: EOF while scanning for magic\n");
-					goto error;
-				}
-				data++;
-			}
-			break;
-		}
-		case STATE_HEADER:
-			/* We need at least 64 bytes for the header */
-			if (scratch_left(data) <
-			    sizeof(struct cpia_frame_header))
-				goto out;
-
-			memcpy(&frame->header, data,
-				sizeof(struct cpia_frame_header));
-
-			/* Skip over the header */
-			data += sizeof(struct cpia_frame_header);
-
-			frame->hdrwidth = (frame->header.col_end -
-				frame->header.col_start) * 8;
-			frame->hdrheight = (frame->header.row_end -
-				frame->header.row_start) * 4;
-			if (debug >= 2) {
-				printk(KERN_DEBUG "cpia: frame size %dx%d\n",
-					frame->hdrwidth, frame->hdrheight);
-				printk(KERN_DEBUG "cpia: frame %scompressed\n",
-					frame->header.comp_enable ? "" : "not ");
-			}
-
-			frame->scanstate = STATE_LINES;
-			frame->curline = 0;
-			break;
-
-		case STATE_LINES:
-		{
-			unsigned char *f, *end;
-			unsigned int len;
-			int i;
-			int y, u, y1, v, r, g, b;
-
-			/* We want at least 2 bytes for the length */
-			if (scratch_left(data) < 2)
-				goto out;
-
-			/* Grab the length */
-			len = data[0] + (data[1] << 8);
-
-			/* Check to make sure it's nothing outrageous */
-			if (len > (frame->hdrwidth * 2) + 1) {
-				if (debug >= 1)
-					printk(KERN_DEBUG "cpia: bad length, resynching (expected %d, got %d)\n", (frame->hdrwidth * 2) + 1, len);
-				goto error;
-			}
-
-			/* Make sure there's enough data for the entire line */
-			if (scratch_left(data + 2) < len)
-				goto out;
-
-			/* Skip over the length */
-			data += 2;
-
-			/* Is the end of the line there */
-			if (data[len - 1] != 0xFD) {
-				if (debug >= 1)
-					printk(KERN_DEBUG "cpia: lost synch\n");
-				goto error;
-			}
-
-			/* Start at the beginning */
-			end = data + len - 1;
-
-			f = frame->data + (frame->width * 3 * frame->curline);
-
-			if (frame->header.comp_enable) {
-				unsigned char *fp;
-
-				/* We use the previous frame as a reference */
-				fp = pframe->data +
-					(frame->width * 3 * frame->curline);
-
-				while (data < end) {
-					if (*data & 1) {
-						/* Compress RLE data */
-						i = *data >> 1;
-						memcpy(f, fp, i * 3);
-						copylen += (i * 3);
-						f += (i * 3);
-						fp += (i * 3);
-						data++;
-					} else {
-						/* Raw data */
-
-#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
-
-y =  *data++ - 16;
-u =  *data++ - 128;
-y1 = *data++ - 16;
-v =  *data++ - 128;
-r = 104635 * v;
-g = -25690 * u + -53294 * v;
-b = 132278 * u;
-y  *= 76310;
-y1 *= 76310;
-*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
-*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
-						fp += 6;
-						copylen += 6;
-					}
-				}
-			} else {
-				/* Raw data */
-				while (data < end) {
-y =  *data++ - 16;
-u =  *data++ - 128;
-y1 = *data++ - 16;
-v =  *data++ - 128;
-r = 104635 * v;
-g = -25690 * u + -53294 * v;
-b = 132278 * u;
-y  *= 76310;
-y1 *= 76310;
-*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
-*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
-copylen += 6;
-				}
-			}
-
-			/* Skip the last byte */
-			data++;
-
-			if (++frame->curline >= frame->hdrheight)
-				goto nextframe;
-
-			break;
-		} /* end case STATE_LINES */
-		} /* end switch (scanstate) */
-	} /* end while (1) */
-
-nextframe:
-	if (debug >= 1)
-		printk(KERN_DEBUG "cpia: marking as success\n");
-
-	if (scratch_left(data) >= 4 && *((__u32 *)data) == 0xFFFFFFFF)
-		data += 4;
-
-	frame->grabstate = FRAME_DONE;
-
-	goto wakeup;
-
-error:
-	if (debug >= 1)
-		printk(KERN_DEBUG "cpia: marking as error\n");
-
-	frame->grabstate = FRAME_ERROR;
-
-	/* Get a fresh frame since this frame may have been important */
-	cpia->compress = 0;
-
-	copylen = 0;
-
-wakeup:
-	cpia->curframe = -1;
-
-	/* This will cause the process to request another frame. */
-	if (waitqueue_active(&frame->wq))
-		wake_up_interruptible(&frame->wq);
-
-out:
-	/* Grab the remaining */
-	left = scratch_left(data);
-	memmove(cpia->scratch, data, left);
-	cpia->scratchlen = left;
-
-	/* Update the frame's uncompressed length. */
-	frame->scanlength += copylen;
-}
-
-/*
- * Make all of the blocks of data contiguous
- */
-static int cpia_compress_isochronous(struct usb_cpia *cpia, urb_t *urb)
-{
-	unsigned char *cdata, *data;
-	int i, totlen = 0;
-
-	data = cpia->scratch + cpia->scratchlen;
-	for (i = 0; i < urb->number_of_packets; i++) {
-		int n = urb->iso_frame_desc[i].actual_length;
-		int st = urb->iso_frame_desc[i].status;
-		
-		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
-		if (st && debug >= 1)
-			printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n",
-				i, n, st);
-
-		if ((cpia->scratchlen + n) > SCRATCH_BUF_SIZE) {
-			printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n",cpia->scratchlen, n );
-			return totlen;
-		}
-
-		if (n) {
-			memmove(data, cdata, n);
-			data += n;
-			totlen += n;
-			cpia->scratchlen += n;
-		}
-	}
-
-	return totlen;
-}
-
-static void cpia_isoc_irq(struct urb *urb)
-{
-	int len;
-	struct usb_cpia *cpia = urb->context;
-	struct cpia_sbuf *sbuf;
-	int i;
-
-	if (!cpia->dev)
-		return;
-
-	if (!cpia->streaming) {
-		if (debug >= 1)
-			printk(KERN_DEBUG "cpia: oops, not streaming, but interrupt\n");
-		return;
-	}
-	
-	sbuf = &cpia->sbuf[cpia->cursbuf];
-
-	/* Copy the data received into our scratch buffer */
-	len = cpia_compress_isochronous(cpia, urb);
-
-	/* If we don't have a frame we're current working on, complain */
-	if (cpia->scratchlen) {
-		if (cpia->curframe < 0) {
-			if (debug >= 1)
-				printk(KERN_DEBUG "cpia: received data, but no frame available\n");
-		} else
-			cpia_parse_data(cpia);
-	}
-
-	for (i = 0; i < FRAMES_PER_DESC; i++) {
-		sbuf->urb->iso_frame_desc[i].status = 0;
-		sbuf->urb->iso_frame_desc[i].actual_length = 0;
-	}
-
-	/* Move to the next sbuf */
-	cpia->cursbuf = (cpia->cursbuf + 1) % CPIA_NUMSBUF;
-
-	return;
-}
-
-static int cpia_init_isoc(struct usb_cpia *cpia)
-{
-	urb_t *urb;
-	int fx, err;
-
-	cpia->compress = 0;
-	cpia->curframe = -1;
-	cpia->cursbuf = 0;
-	cpia->scratchlen = 0;
-
-	/* Alternate interface 3 is is the biggest frame size */
-	if (usb_set_interface(cpia->dev, cpia->iface, 3) < 0) {
-		printk(KERN_ERR "usb_set_interface error\n");
-		return -EBUSY;
-	}
-
-	/* We double buffer the Iso lists */
-	urb = usb_alloc_urb(FRAMES_PER_DESC);
-	
-	if (!urb) {
-		printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
-			0);
-		return -ENOMEM;
-	}
-	cpia->sbuf[0].urb = urb;
-	urb->dev = cpia->dev;
-	urb->context = cpia;
-	urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
-	urb->transfer_flags = USB_ISO_ASAP;
-	urb->transfer_buffer = cpia->sbuf[0].data;
- 	urb->complete = cpia_isoc_irq;
- 	urb->number_of_packets = FRAMES_PER_DESC;
- 	urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- 	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- 		urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
-		urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
-	}
-	urb = usb_alloc_urb(FRAMES_PER_DESC);
-	if (!urb) {
-		printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
-			0);
-		return -ENOMEM;
-	}
-	cpia->sbuf[1].urb = urb;
-	urb->dev = cpia->dev;
-	urb->context = cpia;
-	urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
-	urb->transfer_flags = USB_ISO_ASAP;
-	urb->transfer_buffer = cpia->sbuf[1].data;
- 	urb->complete = cpia_isoc_irq;
- 	urb->number_of_packets = FRAMES_PER_DESC;
- 	urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- 	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- 		urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
-		urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
-	}
-
-	cpia->sbuf[1].urb->next = cpia->sbuf[0].urb;
-	cpia->sbuf[0].urb->next = cpia->sbuf[1].urb;
-	
-	err = usb_submit_urb(cpia->sbuf[0].urb);
-	if (err)
-		printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(0) ret %d\n",
-			err);
-	err = usb_submit_urb(cpia->sbuf[1].urb);
-	if (err)
-		printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(1) ret %d\n",
-			err);
-
-	cpia->streaming = 1;
-
-	return 0;
-}
-
-static void cpia_stop_isoc(struct usb_cpia *cpia)
-{
-	if (!cpia->streaming || !cpia->dev)
-		return;
-
-	/* Turn off continuous grab */
-	if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) {
-		printk(KERN_ERR "cpia_set_grab_mode error\n");
-		return /* -EBUSY */;
-	}
-
-	/* Set packet size to 0 */
-	if (usb_set_interface(cpia->dev, cpia->iface, 0) < 0) {
-		printk(KERN_ERR "usb_set_interface error\n");
-		return /* -EINVAL */;
-	}
-
-	cpia->streaming = 0;
-
-	/* Unschedule all of the iso td's */
-	if (cpia->sbuf[1].urb) {
-		cpia->sbuf[1].urb->next = NULL;
-		usb_unlink_urb(cpia->sbuf[1].urb);
-		usb_free_urb(cpia->sbuf[1].urb);
-		cpia->sbuf[1].urb = NULL;
-	}
-	if (cpia->sbuf[0].urb) {
-		cpia->sbuf[0].urb->next = NULL;
-		usb_unlink_urb(cpia->sbuf[0].urb);
-		usb_free_urb(cpia->sbuf[0].urb);
-		cpia->sbuf[0].urb = NULL;
-	}
-}
-
-static int cpia_new_frame(struct usb_cpia *cpia, int framenum)
-{
-	struct cpia_frame *frame;
-	int width, height;
-
-	if (!cpia->dev)
-		return -1;
-
-	/* If we're not grabbing a frame right now and the other frame is */
-	/*  ready to be grabbed into, then use it instead */
-	if (cpia->curframe == -1) {
-		if (cpia->frame[(framenum - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES].grabstate == FRAME_READY)
-			framenum = (framenum - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES;
-	} else
-		return 0;
-
-	frame = &cpia->frame[framenum];
-	width = frame->width;
-	height = frame->height;
-
-	frame->grabstate = FRAME_GRABBING;
-	frame->scanstate = STATE_SCANNING;
-	frame->scanlength = 0;		/* accumulated in cpia_parse_data() */
-
-	cpia->curframe = framenum;
-
-	/* Make sure it's not too big */
-	if (width > 352)
-		width = 352;
-	width = (width / 8) * 8;	/* Multiple of 8 */
-
-	if (height > 288)
-		height = 288;
-	height = (height / 4) * 4;	/* Multiple of 4 */
-
-	/* Set the ROI they want */
-	if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0)
-		return -EBUSY;
-
-	if (usb_cpia_set_compression(cpia->dev, cpia->compress ?
-			COMP_AUTO : COMP_DISABLED, DONT_DECIMATE) < 0) {
-		printk(KERN_ERR "cpia_set_compression error\n");
-		return -EBUSY;
-	}
-
-	/* We want a fresh frame every 30 we get */
-	cpia->compress = (cpia->compress + 1) % 30;
-
-	/* Grab the frame */
-	if (usb_cpia_upload_frame(cpia->dev, WAIT_FOR_NEXT_FRAME) < 0) {
-		printk(KERN_ERR "cpia_upload_frame error\n");
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-/* Video 4 Linux API */
-static int cpia_open(struct video_device *dev, int flags)
-{
-	int err = -EBUSY;
-	struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
-	down(&cpia->lock);
-	if (cpia->user)
-		goto out_unlock;
-
-	cpia->frame[0].grabstate = FRAME_UNUSED;
-	cpia->frame[1].grabstate = FRAME_UNUSED;
-
-	err = -ENOMEM;
-
-	/* Allocate memory for the frame buffers */
-	cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
-	if (!cpia->fbuf)
-		goto open_err_ret;
-
-	cpia->frame[0].data = cpia->fbuf;
-	cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE;
-
-	cpia->sbuf[0].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
-	if (!cpia->sbuf[0].data)
-		goto open_err_on0;
-
-	cpia->sbuf[1].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
-	if (!cpia->sbuf[1].data)
-		goto open_err_on1;
-
-	/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
-	 * (using read() instead). */
-	cpia->frame[0].width = 352;
-	cpia->frame[0].height = 288;
-	cpia->frame[0].bytes_read = 0;
-	cpia->frame[1].width = 352;
-	cpia->frame[1].height = 288;
-	cpia->frame[1].bytes_read = 0;
-
-	err = cpia_init_isoc(cpia);
-	if (err)
-		goto open_err_on2;
-
-	cpia->user++;
-	up(&cpia->lock);
-
-	MOD_INC_USE_COUNT;
-
-	return 0;
-
-open_err_on2:
-	kfree (cpia->sbuf[1].data);
-open_err_on1:
-	kfree (cpia->sbuf[0].data);
-open_err_on0:
-	rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
-open_err_ret:
-	return err;
-
-out_unlock:
-	up(&cpia->lock);
-	return err;
-}
-
-static void cpia_close(struct video_device *dev)
-{
-	struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
-	down(&cpia->lock);	
-	cpia->user--;
-
-	MOD_DEC_USE_COUNT;
-
-	cpia_stop_isoc(cpia);
-
-	rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
-
-	kfree(cpia->sbuf[1].data);
-	kfree(cpia->sbuf[0].data);
-
-	up(&cpia->lock);
-
-	if (!cpia->dev) {
-		video_unregister_device(&cpia->vdev);
-		kfree(cpia);
-	}
-}
-
-static int cpia_init_done(struct video_device *dev)
-{
-	return 0;
-}
-
-static long cpia_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
-{
-	return -EINVAL;
-}
-
-static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
-	struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
-	if (!cpia->dev)
-		return -EIO;
-
-	switch (cmd) {
-		case VIDIOCGCAP:
-		{
-			struct video_capability b;
-
-			strcpy(b.name, "CPiA USB Camera");
-			b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-			b.channels = 1;
-			b.audios = 0;
-			b.maxwidth = 352;	/* CIF */
-			b.maxheight = 288;	/*  "  */
-			b.minwidth = 8;
-			b.minheight = 4;
-
-			if (copy_to_user(arg, &b, sizeof(b)))
-				return -EFAULT;
-
-			return 0;
-		}
-		case VIDIOCGCHAN:
-		{
-			struct video_channel v;
-
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			if (v.channel != 0)
-				return -EINVAL;
-
-			v.flags = 0;
-			v.tuners = 0;
-			v.type = VIDEO_TYPE_CAMERA;
-			strcpy(v.name, "Camera");
-
-			if (copy_to_user(arg, &v, sizeof(v)))
-				return -EFAULT;
-
-			return 0;
-		}
-		case VIDIOCSCHAN:
-		{
-			int v;
-
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-
-			if (v != 0)
-				return -EINVAL;
-
-			return 0;
-		}
-		case VIDIOCGPICT:
-		{
-			struct video_picture p;
-
-			p.colour = 0x8000;	/* Damn British people :) */
-			p.hue = 0x8000;
-			p.brightness = 180 << 8;	/* XXX */
-			p.contrast = 192 << 8;		/* XXX */
-			p.whiteness = 105 << 8;		/* XXX */
-			p.depth = 24;
-			p.palette = VIDEO_PALETTE_RGB24;
-
-			if (copy_to_user(arg, &p, sizeof(p)))
-				return -EFAULT;
-
-			return 0;
-		}
-		case VIDIOCSPICT:
-		{
-			struct video_picture p;
-
-			if (copy_from_user(&p, arg, sizeof(p)))
-				return -EFAULT;
-
-			return 0;
-		}
-		case VIDIOCSWIN:
-		{
-			struct video_window vw;
-
-			if (copy_from_user(&vw, arg, sizeof(vw)))
-				return -EFAULT;
-			if (vw.flags)
-				return -EINVAL;
-			if (vw.clipcount)
-				return -EINVAL;
-			if (vw.height != 288)
-				return -EINVAL;
-			if (vw.width != 352)
-				return -EINVAL;
-
-			cpia->compress = 0;
-
-			return 0;
-		}
-		case VIDIOCGWIN:
-		{
-			struct video_window vw;
-
-			vw.x = 0;
-			vw.y = 0;
-			vw.width = 352;
-			vw.height = 288;
-			vw.chromakey = 0;
-			vw.flags = 30;		/* 30 fps */
-
-			if (copy_to_user(arg, &vw, sizeof(vw)))
-				return -EFAULT;
-
-			return 0;
-		}
-		case VIDIOCGMBUF:
-		{
-			struct video_mbuf vm;
-
-			memset(&vm, 0, sizeof(vm));
-			vm.size = MAX_FRAME_SIZE * 2;
-			vm.frames = 2;
-			vm.offsets[0] = 0;
-			vm.offsets[1] = MAX_FRAME_SIZE;
-
-			if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-				return -EFAULT;
-
-			return 0;
-		}
-		case VIDIOCMCAPTURE:
-		{
-			struct video_mmap vm;
-
-			if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
-				return -EFAULT;
-
-			if (debug >= 1)
-				printk(KERN_DEBUG "frame: %d, size: %dx%d, format: %d\n",
-					vm.frame, vm.width, vm.height, vm.format);
-
-			if (vm.format != VIDEO_PALETTE_RGB24)
-				return -EINVAL;
-
-			if ((vm.frame != 0) && (vm.frame != 1))
-				return -EINVAL;
-
-			if (cpia->frame[vm.frame].grabstate == FRAME_GRABBING)
-				return -EBUSY;
-
-			/* Don't compress if the size changed */
-			if ((cpia->frame[vm.frame].width != vm.width) ||
-			    (cpia->frame[vm.frame].height != vm.height))
-				cpia->compress = 0;
-
-			cpia->frame[vm.frame].width = vm.width;
-			cpia->frame[vm.frame].height = vm.height;
-
-			/* Mark it as ready */
-			cpia->frame[vm.frame].grabstate = FRAME_READY;
-
-			return cpia_new_frame(cpia, vm.frame);
-		}
-		case VIDIOCSYNC:
-		{
-			int frame;
-
-			if (copy_from_user((void *)&frame, arg, sizeof(int)))
-				return -EFAULT;
-
-			if (debug >= 1)
-				printk(KERN_DEBUG "cpia: syncing to frame %d\n", frame);
-
-			switch (cpia->frame[frame].grabstate) {
-			case FRAME_UNUSED:
-				return -EINVAL;
-			case FRAME_READY:
-			case FRAME_GRABBING:
-			case FRAME_ERROR:
-redo:
-				if (!cpia->dev)
-					return -EIO;
-
-				do {
-					interruptible_sleep_on(&cpia->frame[frame].wq);
-					if (signal_pending(current))
-						return -EINTR;
-				} while (cpia->frame[frame].grabstate == FRAME_GRABBING);
-
-				if (cpia->frame[frame].grabstate == FRAME_ERROR) {
-					int ret;
-
-					if ((ret = cpia_new_frame(cpia, frame)) < 0)
-						return ret;
-					goto redo;
-				}
-			case FRAME_DONE:
-				cpia->frame[frame].grabstate = FRAME_UNUSED;
-				break;
-			}
-
-			cpia->frame[frame].grabstate = FRAME_UNUSED;
-
-			return 0;
-		}
-		case VIDIOCGFBUF:
-		{
-			struct video_buffer vb;
-
-			memset(&vb, 0, sizeof(vb));
-			vb.base = NULL;	/* frame buffer not supported, not used */
-
-			if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
-				return -EFAULT;
-
- 			return 0;
- 		}
-		case VIDIOCKEY:
-			return 0;
-		case VIDIOCCAPTURE:
-			return -EINVAL;
-		case VIDIOCSFBUF:
-			return -EINVAL;
-		case VIDIOCGTUNER:
-		case VIDIOCSTUNER:
-			return -EINVAL;
-		case VIDIOCGFREQ:
-		case VIDIOCSFREQ:
-			return -EINVAL;
-		case VIDIOCGAUDIO:
-		case VIDIOCSAUDIO:
-			return -EINVAL;
-		default:
-			return -ENOIOCTLCMD;
-	}
-	return 0;
-}
-
-static long cpia_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
-{
-	struct usb_cpia *cpia = (struct usb_cpia *)dev;
-	int frmx = -1;
-	volatile struct cpia_frame *frame;
-
-	if (debug >= 1)
-		printk(KERN_DEBUG "cpia_read: %ld bytes, noblock=%d\n", count, noblock);
-
-	if (!dev || !buf)
-		return -EFAULT;
-
-	if (!cpia->dev)
-		return -EIO;
-
-	/* See if a frame is completed, then use it. */
-	if (cpia->frame[0].grabstate >= FRAME_DONE)	/* _DONE or _ERROR */
-		frmx = 0;
-	else if (cpia->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
-		frmx = 1;
-
-	if (noblock && (frmx == -1))
-		return -EAGAIN;
-
-	/* If no FRAME_DONE, look for a FRAME_GRABBING state. */
-	/* See if a frame is in process (grabbing), then use it. */
-	if (frmx == -1) {
-		if (cpia->frame[0].grabstate == FRAME_GRABBING)
-			frmx = 0;
-		else if (cpia->frame[1].grabstate == FRAME_GRABBING)
-			frmx = 1;
-	}
-
-	/* If no frame is active, start one. */
-	if (frmx == -1)
-		cpia_new_frame(cpia, frmx = 0);
-
-	frame = &cpia->frame[frmx];
-
-restart:
-	if (!cpia->dev)
-		return -EIO;
-
-	while (frame->grabstate == FRAME_GRABBING) {
-		interruptible_sleep_on(&frame->wq);
-		if (signal_pending(current))
-			return -EINTR;
-	}
-
-	if (frame->grabstate == FRAME_ERROR) {
-		frame->bytes_read = 0;
-printk("cpia_read: errored frame %d\n", cpia->curframe);
-		if (cpia_new_frame(cpia, frmx))
-			printk(KERN_ERR "cpia_read: cpia_new_frame error\n");
-		goto restart;
-	}
-
-	if (debug >= 1)
-		printk(KERN_DEBUG "cpia_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n",
-			frmx, frame->bytes_read, frame->scanlength);
-
-	/* copy bytes to user space; we allow for partials reads */
-	if ((count + frame->bytes_read) > frame->scanlength)
-		count = frame->scanlength - frame->bytes_read;
-
-	if (copy_to_user(buf, frame->data + frame->bytes_read, count))
-		return -EFAULT;
-
-	frame->bytes_read += count;
-	if (debug >= 1)
-		printk(KERN_DEBUG "cpia_read: {copy} count used=%ld, new bytes_read=%ld\n",
-			count, frame->bytes_read);
-
-	if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
-		frame->bytes_read = 0;
-
-		/* Mark it as available to be used again. */
-		cpia->frame[frmx].grabstate = FRAME_UNUSED;
-		if (cpia_new_frame(cpia, frmx ? 0 : 1))
-			printk(KERN_ERR "cpia_read: cpia_new_frame returned error\n");
-	}
-
-	return count;
-}
-
-static int cpia_mmap(struct video_device *dev, const char *adr, unsigned long size)
-{
-	struct usb_cpia *cpia = (struct usb_cpia *)dev;
-	unsigned long start = (unsigned long)adr;
-	unsigned long page, pos;
-
-	if (!cpia->dev)
-		return -EIO;
-
-	if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
-		return -EINVAL;
-
-	pos = (unsigned long)cpia->fbuf;
-	while (size > 0) {
-		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
-			return -EAGAIN;
-
-		start += PAGE_SIZE;
-		pos += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
-	}
-
-	return 0;
-}
-
-static struct video_device cpia_template = {
-	"CPiA USB Camera",
-	VID_TYPE_CAPTURE,
-	VID_HARDWARE_CPIA,
-	cpia_open,
-	cpia_close,
-	cpia_read,
-	cpia_write,
-	NULL,
-	cpia_ioctl,
-	cpia_mmap,
-	cpia_init_done,
-	NULL,
-	0,
-	0
-};
-
-static int usb_cpia_configure(struct usb_cpia *cpia)
-{
-	struct usb_device *dev = cpia->dev;
-	unsigned char version[4];
-
-	/* Set altsetting 0 */
-	if (usb_set_interface(dev, cpia->iface, 0) < 0) {
-		printk(KERN_ERR "usb_set_interface error\n");
-		return -EBUSY;
-	}
-
-	if (usb_cpia_get_version(dev, version) < 0) {
-		printk(KERN_ERR "cpia_get_version error\n");
-		return -EBUSY;
-	}
-
-	if (debug >= 1)
-		printk(KERN_DEBUG "cpia: Firmware v%d.%d, VC Hardware v%d.%d\n",
-			version[0], version[1], version[2], version[3]);
-
-	memcpy(&cpia->vdev, &cpia_template, sizeof(cpia_template));
-
-	init_waitqueue_head(&cpia->frame[0].wq);
-	init_waitqueue_head(&cpia->frame[1].wq);
-
-	if (video_register_device(&cpia->vdev, VFL_TYPE_GRABBER) == -1) {
-		printk(KERN_ERR "video_register_device failed\n");
-		return -EBUSY;
-	}
-
-	if (usb_cpia_goto_hi_power(dev) < 0) {
-		printk(KERN_ERR "cpia_goto_hi_power error\n");
-		goto error;
-	}
-
-	if (usb_cpia_get_vp_version(dev, version) < 0) {
-		printk(KERN_ERR "cpia_get_vp_version error\n");
-		goto error;
-	}
-
-	if (debug >= 1) {
-		printk(KERN_DEBUG "cpia: VP v%d rev %d\n", version[0], version[1]);
-		printk(KERN_DEBUG "cpia: Camera Head ID %04X\n", (version[3] << 8) + version[2]);
-	}
-
-	/* Turn on continuous grab */
-	if (usb_cpia_set_grab_mode(dev, 1) < 0) {
-		printk(KERN_ERR "cpia_set_grab_mode error\n");
-		goto error;
-	}
-
-	/* Set up the sensor to be 30fps */
-	if (usb_cpia_set_sensor_fps(dev, 1, 0) < 0) {
-		printk(KERN_ERR "cpia_set_sensor_fps error\n");
-		goto error;
-	}
-
-	/* Set video into CIF mode, and order into YUYV mode */
-	if (usb_cpia_set_format(dev, FORMAT_CIF, FORMAT_422,
-			FORMAT_YUYV) < 0) {
-		printk(KERN_ERR "cpia_set_format error\n");
-		goto error;
-	}
-
-	/* Turn off compression */
-	if (usb_cpia_set_compression(dev, COMP_DISABLED, DONT_DECIMATE) < 0) {
-		printk(KERN_ERR "cpia_set_compression error\n");
-		goto error;
-	}
-
-	cpia->compress = 0;
-
-	return 0;
-
-error:
-	video_unregister_device(&cpia->vdev);
-	usb_driver_release_interface(&cpia_driver,
-		&dev->actconfig->interface[0]);
-
-	kfree(cpia);
-
-	return -EBUSY;
-}
-
-static void * cpia_probe(struct usb_device *dev, unsigned int ifnum)
-{
-	struct usb_interface_descriptor *interface;
-	struct usb_cpia *cpia;
-
-	/* We don't handle multi-config cameras */
-	if (dev->descriptor.bNumConfigurations != 1)
-		return NULL;
-
-	interface = &dev->actconfig->interface[ifnum].altsetting[0];
-
-	/* Is it a CPiA? */
-	if (dev->descriptor.idVendor != 0x0553)
-		return NULL;
-	if (dev->descriptor.idProduct != 0x0002)
-		return NULL;
-
-	/* Checking vendor/product should be enough, but what the hell */
-	if (interface->bInterfaceClass != 0xFF)
-		return NULL;
-	if (interface->bInterfaceSubClass != 0x00)
-		return NULL;
-
-	/* We found a CPiA */
-	printk(KERN_INFO "USB CPiA camera found\n");
-
-	if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) {
-		printk(KERN_ERR "couldn't kmalloc cpia struct\n");
-		return NULL;
-	}
-
-	memset(cpia, 0, sizeof(*cpia));
-
-	cpia->dev = dev;
-	cpia->iface = interface->bInterfaceNumber;
-
-	if (!usb_cpia_configure(cpia)) {
-		cpia->user=0; 
-		init_MUTEX(&cpia->lock);	/* to 1 == available */
-
-		return cpia;
-	} else
-		return NULL;
-}
-
-static void cpia_disconnect(struct usb_device *dev, void *ptr)
-{
-	struct usb_cpia *cpia = (struct usb_cpia *) ptr;
-
-	/* We don't want people trying to open up the device */
-	if (!cpia->user)
-		video_unregister_device(&cpia->vdev);
-
-	usb_driver_release_interface(&cpia_driver,
-		&cpia->dev->actconfig->interface[0]);
-
-	cpia->dev = NULL;
-	cpia->frame[0].grabstate = FRAME_ERROR;
-	cpia->frame[1].grabstate = FRAME_ERROR;
-	cpia->curframe = -1;
-
-	/* This will cause the process to request another frame. */
-	if (waitqueue_active(&cpia->frame[0].wq))
-		wake_up_interruptible(&cpia->frame[0].wq);
-
-	if (waitqueue_active(&cpia->frame[1].wq))
-		wake_up_interruptible(&cpia->frame[1].wq);
-
-	cpia->streaming = 0;
-
-	/* Unschedule all of the iso td's */
-	if (cpia->sbuf[1].urb) {
-		cpia->sbuf[1].urb->next = NULL;
-		usb_unlink_urb(cpia->sbuf[1].urb);
-		usb_free_urb(cpia->sbuf[1].urb);
-		cpia->sbuf[1].urb = NULL;
-	}
-	if (cpia->sbuf[0].urb) {
-		cpia->sbuf[0].urb->next = NULL;
-		usb_unlink_urb(cpia->sbuf[0].urb);
-		usb_free_urb(cpia->sbuf[0].urb);
-		cpia->sbuf[0].urb = NULL;
-	}
-
-	/* Free the memory */
-	if (!cpia->user)
-		kfree(cpia);
-}
-
-static struct usb_driver cpia_driver = {
-	"cpia",
-	cpia_probe,
-	cpia_disconnect,
-	{ NULL, NULL }
-};
-
-int usb_cpia_init(void)
-{
-	return usb_register(&cpia_driver);
-}
-
-void usb_cpia_cleanup(void)
-{
-	usb_deregister(&cpia_driver);
-}
-
-#ifdef MODULE
-int init_module(void)
-{
-	return usb_cpia_init();
-}
-
-void cleanup_module(void)
-{
-	usb_cpia_cleanup();
-}
-#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/cpia.h linux/drivers/usb/cpia.h
--- v2.3.99-pre3/linux/drivers/usb/cpia.h	Mon Dec 20 18:48:22 1999
+++ linux/drivers/usb/cpia.h	Wed Dec 31 16:00:00 1969
@@ -1,205 +0,0 @@
-#ifndef __LINUX_CPIA_H
-#define __LINUX_CPIA_H
-
-#include <linux/list.h>
-
-#define USB_REQ_CPIA_GET_VERSION		0x01
-#define USB_REQ_CPIA_GET_PNP_ID			0x02
-#define USB_REQ_CPIA_GET_CAMERA_STATUS		0x03
-#define USB_REQ_CPIA_GOTO_HI_POWER		0x04
-#define USB_REQ_CPIA_GOTO_LO_POWER		0x05
-/* No 0x06 */
-#define USB_REQ_CPIA_GOTO_SUSPEND		0x07
-#define USB_REQ_CPIA_GOTO_PASS_THROUGH		0x08
-/* No 0x09 */
-#define USB_REQ_CPIA_MODIFY_CAMERA_STATUS	0x0A
-
-#define USB_REQ_CPIA_READ_VC_REGS		0x21
-#define USB_REQ_CPIA_WRITE_BC_REG		0x22
-#define USB_REQ_CPIA_READ_MC_PORTS		0x23
-#define USB_REQ_CPIA_WRITE_MC_PORT		0x24
-#define USB_REQ_CPIA_SET_BAUD_RATE		0x25
-#define USB_REQ_CPIA_SET_ECP_TIMING		0x26
-#define USB_REQ_CPIA_READ_IDATA			0x27
-#define USB_REQ_CPIA_WRITE_IDATA		0x28
-#define USB_REQ_CPIA_GENERIC_CALL		0x29
-#define USB_REQ_CPIA_I2CSTART			0x2A
-#define USB_REQ_CPIA_I2CSTOP			0x2B
-#define USB_REQ_CPIA_I2CWRITE			0x2C
-#define USB_REQ_CPIA_I2CREAD			0x2D
-
-#define USB_REQ_CPIA_GET_VP_VERSION		0xA1
-#define USB_REQ_CPIA_SET_COLOUR_PARAMS		0xA3
-#define USB_REQ_CPIA_SET_EXPOSURE		0xA4
-/* No 0xA5 */
-#define USB_REQ_CPIA_SET_COLOUR_BALANCE		0xA6
-#define USB_REQ_CPIA_SET_SENSOR_FPS		0xA7
-#define USB_REQ_CPIA_SET_VP_DEFAULTS		0xA8
-#define USB_REQ_CPIA_SET_APCOR			0xA9
-#define USB_REQ_CPIA_SET_FLICKER_CTRL		0xAA
-#define USB_REQ_CPIA_SET_VL_OFFSET		0xAB
-
-#define USB_REQ_CPIA_GET_COLOUR_PARAMETERS	0xB0
-#define USB_REQ_CPIA_GET_COLOUR_BALANCE		0xB1
-#define USB_REQ_CPIA_GET_EXPOSURE		0xB2
-#define USB_REQ_CPIA_SET_SENSOR_MATRIX		0xB3
-
-#define USB_REQ_CPIA_COLOUR_BARS		0xBD
-#define USB_REQ_CPIA_READ_VP_REGS		0xBE
-#define USB_REQ_CPIA_WRITE_VP_REGS		0xBF
-
-#define USB_REQ_CPIA_GRAB_FRAME			0xC1
-#define USB_REQ_CPIA_UPLOAD_FRAME		0xC2
-#define  WAIT_FOR_NEXT_FRAME			0
-#define  FORCE_FRAME_UPLOAD			1
-#define USB_REQ_CPIA_SET_GRAB_MODE		0xC3
-#define USB_REQ_CPIA_INIT_STREAM_CAP		0xC4
-#define USB_REQ_CPIA_FINI_STREAM_CAP		0xC5
-#define USB_REQ_CPIA_START_STREAM_CAP		0xC6
-#define USB_REQ_CPIA_END_STREAM_CAP		0xC7
-#define USB_REQ_CPIA_SET_FORMAT			0xC8
-#define  FORMAT_QCIF	0
-#define  FORMAT_CIF	1
-#define  FORMAT_YUYV	0
-#define  FORMAT_UYVY	1
-#define  FORMAT_420	0
-#define  FORMAT_422	1
-#define USB_REQ_CPIA_SET_ROI			0xC9
-#define USB_REQ_CPIA_SET_COMPRESSION		0xCA
-#define  COMP_DISABLED	0
-#define  COMP_AUTO	1
-#define  COMP_MANUAL	2
-#define  DONT_DECIMATE	0
-#define  DECIMATE	1
-#define USB_REQ_CPIA_SET_COMPRESSION_TARGET	0xCB
-#define  TARGET_QUALITY		0
-#define  TARGET_FRAMERATE	1
-#define USB_REQ_CPIA_SET_YUV_THRESH		0xCC
-#define USB_REQ_CPIA_SET_COMPRESSION_PARAMS	0xCD
-#define USB_REQ_CPIA_DISCARD_FRAME		0xCE
-
-#define USB_REQ_CPIA_OUTPUT_RS232		0xE1
-#define USB_REQ_CPIA_ABORT_PROCESS		0xE4
-#define USB_REQ_CPIA_SET_DRAM_PAGE		0xE5
-#define USB_REQ_CPIA_START_DRAM_UPLOAD		0xE6
-#define USB_REQ_CPIA_START_DUMMY_STREAM		0xE8
-#define USB_REQ_CPIA_ABORT_STREAM		0xE9
-#define USB_REQ_CPIA_DOWNLOAD_DRAM		0xEA
-/* #define USB_REQ_CPIA_NULL_CMD		0x?? */
-
-#define STREAM_BUF_SIZE		(PAGE_SIZE * 4)
-/* #define STREAM_BUF_SIZE	(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC) */
-
-#define SCRATCH_BUF_SIZE	(STREAM_BUF_SIZE * 2)
-
-#define FRAMES_PER_DESC		10
-#define FRAME_SIZE_PER_DESC	960	/* Shouldn't be hardcoded */
-
-enum {
-	STATE_SCANNING,		/* Scanning for start */
-	STATE_HEADER,		/* Parsing header */
-	STATE_LINES,		/* Parsing lines */
-};
-
-#define CPIA_MAGIC	0x1968
-struct cpia_frame_header {
-	__u16 magic;		/* 0 - 1 */
-	__u16 timestamp;	/* 2 - 3 */
-	__u16 unused;		/* 4 - 5 */
-	__u16 timestamp1;	/* 6 - 7 */
-	__u8  unused1[8];	/* 8 - 15 */
-	__u8  video_size;	/* 16 0 = QCIF, 1 = CIF */
-	__u8  sub_sample;	/* 17 0 = 4:2:0, 1 = 4:2:2 */
-	__u8  yuv_order;	/* 18 0 = YUYV, 1 = UYVY */
-	__u8  unused2[5];	/* 19 - 23 */
-	__u8  col_start;	/* 24 */
-	__u8  col_end;		/* 25 */
-	__u8  row_start;	/* 26 */
-	__u8  row_end;		/* 27 */
-	__u8  comp_enable;	/* 28 0 = non compressed, 1 = compressed */
-	__u8  decimation;	/* 29 0 = no decimation, 1 = decimation */
-	__u8  y_thresh;		/* 30 */
-	__u8  uv_thresh;	/* 31 */
-	__u8  system_state;	/* 32 */
-	__u8  grab_state;	/* 33 */
-	__u8  stream_state;	/* 34 */
-	__u8  fatal_error;	/* 35 */
-	__u8  cmd_error;	/* 36 */
-	__u8  debug_flags;	/* 37 */
-	__u8  camera_state_7;	/* 38 */
-	__u8  camera_state_8;	/* 39 */
-	__u8  cr_achieved;	/* 40 */
-	__u8  fr_achieved;	/* 41 */
-	__u8  unused3[22];	/* 42 - 63 */
-};
-
-struct usb_device;
-
-struct cpia_sbuf {
-	char *data;
-	urb_t *urb;
-};
-
-enum {
-	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
-	FRAME_READY,		/* Ready to start grabbing */
-	FRAME_GRABBING,		/* In the process of being grabbed into */
-	FRAME_DONE,		/* Finished grabbing, but not been synced yet */
-	FRAME_ERROR,		/* Something bad happened while processing */
-};
-
-struct cpia_frame {
-	char *data;		/* Frame buffer */
-
-	struct cpia_frame_header header;	/* Header from stream */
-
-	int width;		/* Width application is expecting */
-	int height;		/* Height */
-
-	int hdrwidth;		/* Width the frame actually is */
-	int hdrheight;		/* Height */
-
-	volatile int grabstate;	/* State of grabbing */
-	int scanstate;		/* State of scanning */
-
-	int curline;		/* Line of frame we're working on */
-
-	long scanlength;	/* uncompressed, raw data length of frame */
-	long bytes_read;	/* amount of scanlength that has been read from *data */
-
-	wait_queue_head_t wq;	/* Processes waiting */
-};
-
-#define CPIA_NUMFRAMES	2
-#define CPIA_NUMSBUF	2
-
-struct usb_cpia {
-	struct video_device vdev;
-
-	/* Device structure */
-	struct usb_device *dev;
-
-	unsigned char iface;
-
-	struct semaphore lock;
-	int user;		/* user count for exclusive use */
-
-	int streaming;		/* Are we streaming Isochronous? */
-	int grabbing;		/* Are we grabbing? */
-
-	int compress;		/* Should the next frame be compressed? */
-
-	char *fbuf;		/* Videodev buffer area */
-
-	int curframe;
-	struct cpia_frame frame[CPIA_NUMFRAMES];	/* Double buffering */
-
-	int cursbuf;		/* Current receiving sbuf */
-	struct cpia_sbuf sbuf[CPIA_NUMSBUF];		/* Double buffering */
-
-	/* Scratch space from the Isochronous pipe */
-	unsigned char scratch[SCRATCH_BUF_SIZE];
-	int scratchlen;
-};
-
-#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/devices.c linux/drivers/usb/devices.c
--- v2.3.99-pre3/linux/drivers/usb/devices.c	Fri Mar 10 16:40:44 2000
+++ linux/drivers/usb/devices.c	Mon Apr 10 22:55:08 2000
@@ -54,9 +54,8 @@
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
 #include <asm/uaccess.h>
-
-#include "usbdevice_fs.h"
 
 #define MAX_TOPO_LEVEL		6
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/devio.c linux/drivers/usb/devio.c
--- v2.3.99-pre3/linux/drivers/usb/devio.c	Fri Mar 10 16:40:44 2000
+++ linux/drivers/usb/devio.c	Mon Apr 10 22:55:08 2000
@@ -41,9 +41,9 @@
 #include <linux/signal.h>
 #include <linux/poll.h>
 #include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
 #include <asm/uaccess.h>
 
-#include "usbdevice_fs.h"
 
 struct async {
         struct list_head asynclist;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/drivers.c linux/drivers/usb/drivers.c
--- v2.3.99-pre3/linux/drivers/usb/drivers.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/usb/drivers.c	Mon Apr 10 22:55:08 2000
@@ -37,10 +37,8 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
 #include <asm/uaccess.h>
-
-#include "usbdevice_fs.h"
-
 
 /*****************************************************************/
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/evdev.c linux/drivers/usb/evdev.c
--- v2.3.99-pre3/linux/drivers/usb/evdev.c	Sat Feb 26 22:31:50 2000
+++ linux/drivers/usb/evdev.c	Mon Apr 10 22:53:15 2000
@@ -29,9 +29,9 @@
  */
 
 #define EVDEV_MINOR_BASE	64
+#define EVDEV_MINORS		32
 #define EVDEV_BUFFER_SIZE	64
 
-#include <linux/miscdevice.h>
 #include <linux/poll.h>
 #include <linux/malloc.h>
 #include <linux/module.h>
@@ -39,11 +39,12 @@
 #include <linux/input.h>
 
 struct evdev {
-	char name[32];
 	int used;
+	int open;
+	int minor;
 	struct input_handle handle;
-	struct miscdevice misc;
 	wait_queue_head_t wait;
+	devfs_handle_t devfs;
 	struct evdev_list *list;
 };
 
@@ -56,8 +57,7 @@
 	struct evdev_list *next;
 };
 
-static unsigned long evdev_miscbits = 0;
-static struct evdev *evdev_base[BITS_PER_LONG];
+static struct evdev *evdev_table[EVDEV_MINORS] = { NULL, /* ... */ };
 
 static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
@@ -99,10 +99,13 @@
 	while (*listptr && (*listptr != list))
 		listptr = &((*listptr)->next);
 	*listptr = (*listptr)->next;
+
+	if (!--list->evdev->open)
+		input_close_device(&list->evdev->handle);	
 	
 	if (!--list->evdev->used) {
-		clear_bit(list->evdev->misc.minor - EVDEV_MINOR_BASE, &evdev_miscbits);
-		misc_deregister(&list->evdev->misc);
+		input_unregister_minor(list->evdev->devfs);
+		evdev_table[list->evdev->minor] = NULL;
 		kfree(list->evdev);
 	}
 
@@ -117,23 +120,28 @@
 	struct evdev_list *list;
 	int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;
 
-	if (i > BITS_PER_LONG || !test_bit(i, &evdev_miscbits))
+	if (i > EVDEV_MINORS || !evdev_table[i])
 		return -ENODEV;
 
-	if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
-		return -ENOMEM;
+	MOD_INC_USE_COUNT;
 
+	if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
 	memset(list, 0, sizeof(struct evdev_list));
 
-	list->evdev = evdev_base[i];
-	list->next = evdev_base[i]->list;
-	evdev_base[i]->list = list;
+	list->evdev = evdev_table[i];
+	list->next = evdev_table[i]->list;
+	evdev_table[i]->list = list;
 
 	file->private_data = list;
 
 	list->evdev->used++;
 
-	MOD_INC_USE_COUNT;
+	if (!list->evdev->open++)
+		input_open_device(&list->evdev->handle);	
+
 	return 0;
 }
 
@@ -193,34 +201,81 @@
 	return 0;
 }
 
+static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct evdev_list *list = file->private_data;
+	struct evdev *evdev = list->evdev;
+	struct input_dev *dev = evdev->handle.dev;
+
+	switch (cmd) {
+
+		case EVIOCGVERSION:
+			return put_user(EV_VERSION, (__u32 *) arg);
+		case EVIOCGID:
+			return copy_to_user(&dev->id, (void *) arg,
+						sizeof(struct input_id)) ? -EFAULT : 0;
+		default:
+
+			if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
+				return -EINVAL;
+
+			if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+
+				long *bits = NULL;
+				int len = 0;
+
+				switch (_IOC_NR(cmd) & EV_MAX) {
+					case      0: bits = dev->evbit;  len = EV_MAX;  break;
+					case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+					case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+					case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+					case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+					case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+					default: return -EINVAL;
+				}
+				len = NBITS(len) * sizeof(long);
+				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+				return copy_to_user((void *) arg, bits, len) ? -EFAULT : len;
+			}
+
+			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+				int len = strlen(dev->name) + 1;
+				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+				return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len;
+			}
+	}
+	return -EINVAL;
+}
+
 static struct file_operations evdev_fops = {
 	read:		evdev_read,
 	write:		evdev_write,
 	poll:		evdev_poll,
 	open:		evdev_open,
 	release:	evdev_release,
+	ioctl:		evdev_ioctl,
 	fasync:		evdev_fasync,
 };
 
-static int evdev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev)
 {
 	struct evdev *evdev;
+	int minor;
 
-	if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
-		return -1;
+	for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
+	if (evdev_table[minor]) {
+		printk(KERN_ERR "evdev: no more free evdev devices\n");
+		return NULL;
+	}
 
+	if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
+		return NULL;
 	memset(evdev, 0, sizeof(struct evdev));
 
 	init_waitqueue_head(&evdev->wait);
 
-	evdev->misc.minor = ffz(evdev_miscbits);
-	set_bit(evdev->misc.minor, &evdev_miscbits);
-	evdev_base[evdev->misc.minor] = evdev;
-
-	sprintf(evdev->name, "evdev%d", evdev->misc.minor);
-	evdev->misc.name = evdev->name;
-	evdev->misc.minor += EVDEV_MINOR_BASE;
-	evdev->misc.fops = &evdev_fops;
+	evdev->minor = minor;
+	evdev_table[minor] = evdev;
 
 	evdev->handle.dev = dev;
 	evdev->handle.handler = handler;
@@ -228,24 +283,23 @@
 
 	evdev->used = 1;
 
-	misc_register(&evdev->misc);
-	input_open_device(&evdev->handle);
+	evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
 
-	printk("%s: Event device for input%d on misc%d - /dev/input%d\n",
-		evdev->name, dev->number, evdev->misc.minor, evdev->misc.minor - EVDEV_MINOR_BASE);
+	printk("event%d: Event device for input%d\n", minor, dev->number);
 
-	return 0;
+	return &evdev->handle;
 }
 
 static void evdev_disconnect(struct input_handle *handle)
 {
 	struct evdev *evdev = handle->private;
 
-	input_close_device(handle);
+	if (evdev->open)
+		input_close_device(handle);
 
 	if (!--evdev->used) {
-		clear_bit(evdev->misc.minor - EVDEV_MINOR_BASE, &evdev_miscbits);
-		misc_deregister(&evdev->misc);
+		input_unregister_minor(evdev->devfs);
+		evdev_table[evdev->minor] = NULL;
 		kfree(evdev);
 	}
 }
@@ -254,6 +308,8 @@
 	event:		evdev_event,
 	connect:	evdev_connect,
 	disconnect:	evdev_disconnect,
+	fops:		&evdev_fops,
+	minor:		EVDEV_MINOR_BASE,
 };
 
 static int __init evdev_init(void)
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/hid.c linux/drivers/usb/hid.c
--- v2.3.99-pre3/linux/drivers/usb/hid.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/hid.c	Wed Apr  5 17:02:15 2000
@@ -1288,7 +1288,7 @@
 					hid_configure_usage(hid, report->field[i], report->field[i]->usage + j);
 
 			if (k == HID_INPUT_REPORT)  {
-				usb_set_idle(hid->dev, hid->ifnum, report->id, 0);
+				usb_set_idle(hid->dev, hid->ifnum, 0, report->id);
 				hid_read_report(hid, report);
 			}
 		}
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.3.99-pre3/linux/drivers/usb/hub.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/usb/hub.c	Tue Apr 11 09:57:43 2000
@@ -6,12 +6,17 @@
  * (C) Copyright 1999 Gregory P. Smith
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/list.h>
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
-#define DEBUG
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
 #include <linux/usb.h>
 
 #include <asm/uaccess.h>
@@ -609,5 +614,28 @@
 	usb_deregister(&hub_driver);
 } /* usb_hub_cleanup() */
 
+int usb_reset_device(struct usb_device *dev)
+{
+	struct usb_device *parent = dev->parent;
+	int i;
+
+	if (!parent) {
+		err("attempting to reset root hub!");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < parent->maxchild; i++) {
+		if (parent->children[i] == dev) {
+			usb_set_port_feature(parent, i + 1,
+				USB_PORT_FEAT_RESET);
 
+			usb_disconnect(&dev);
+			usb_hub_port_connect_change(parent, i);
+
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/ibmcam.c linux/drivers/usb/ibmcam.c
--- v2.3.99-pre3/linux/drivers/usb/ibmcam.c	Fri Mar 10 16:40:44 2000
+++ linux/drivers/usb/ibmcam.c	Sun Apr  2 15:19:56 2000
@@ -58,6 +58,8 @@
 #define FLAGS_DISPLAY_HINTS		(1 << 2)
 #define FLAGS_OVERLAY_STATS		(1 << 3)
 #define FLAGS_FORCE_TESTPATTERN		(1 << 4)
+#define FLAGS_SEPARATE_FRAMES		(1 << 5)
+#define FLAGS_CLEAN_FRAMES		(1 << 6)
 
 static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
 
@@ -2238,6 +2240,12 @@
 	}
 }
 
+/*
+ * ibmcam_new_frame()
+ *
+ * History:
+ * 29-Mar-00 Added copying of previous frame into the current one.
+ */
 static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum)
 {
 	struct ibmcam_frame *frame;
@@ -2258,10 +2266,33 @@
 	frame->scanstate = STATE_SCANNING;
 	frame->scanlength = 0;		/* Accumulated in ibmcam_parse_data() */
 	ibmcam->curframe = framenum;
-#if 0
-	/* This provides a "clean" frame but slows things down */
-	memset(frame->data, 0, MAX_FRAME_SIZE);
-#endif
+
+	/*
+	 * Normally we would want to copy previous frame into the current one
+	 * before we even start filling it with data; this allows us to stop
+	 * filling at any moment; top portion of the frame will be new and
+	 * bottom portion will stay as it was in previous frame. If we don't
+	 * do that then missing chunks of video stream will result in flickering
+	 * portions of old data whatever it was before.
+	 *
+	 * If we choose not to copy previous frame (to, for example, save few
+	 * bus cycles - the frame can be pretty large!) then we have an option
+	 * to clear the frame before using. If we experience losses in this
+	 * mode then missing picture will be black (no flickering).
+	 *
+	 * Finally, if user chooses not to clean the current frame before
+	 * filling it with data then the old data will be visible if we fail
+	 * to refill entire frame with new data.
+	 */
+	if (!(flags & FLAGS_SEPARATE_FRAMES)) {
+		/* This copies previous frame into this one to mask losses */
+		memmove(frame->data, ibmcam->frame[1-framenum].data,  MAX_FRAME_SIZE);
+	} else {
+		if (flags & FLAGS_CLEAN_FRAMES) {
+			/* This provides a "clean" frame but slows things down */
+			memset(frame->data, 0, MAX_FRAME_SIZE);
+		}
+	}
 	switch (videosize) {
 	case VIDEOSIZE_128x96:
 		frame->frmwidth = 128;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/inode.c linux/drivers/usb/inode.c
--- v2.3.99-pre3/linux/drivers/usb/inode.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/usb/inode.c	Mon Apr 10 22:55:08 2000
@@ -38,9 +38,8 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
 #include <asm/uaccess.h>
-
-#include "usbdevice_fs.h"
 
 /* --------------------------------------------------------------------- */
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/input.c linux/drivers/usb/input.c
--- v2.3.99-pre3/linux/drivers/usb/input.c	Sat Feb 26 22:31:50 2000
+++ linux/drivers/usb/input.c	Mon Apr 10 22:53:15 2000
@@ -35,20 +35,25 @@
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 
-#ifndef MODULE
 EXPORT_SYMBOL(input_register_device);
 EXPORT_SYMBOL(input_unregister_device);
 EXPORT_SYMBOL(input_register_handler);
 EXPORT_SYMBOL(input_unregister_handler);
+EXPORT_SYMBOL(input_register_minor);
+EXPORT_SYMBOL(input_unregister_minor);
 EXPORT_SYMBOL(input_open_device);
 EXPORT_SYMBOL(input_close_device);
 EXPORT_SYMBOL(input_event);
-#endif
+
+#define INPUT_MAJOR	13
+#define INPUT_DEVICES	256
 
 static struct input_dev *input_dev = NULL;
 static struct input_handler *input_handler = NULL;
-
+static struct input_handler *input_table[8] = { NULL, /* ... */ };
+static devfs_handle_t input_devfs_handle = NULL;
 static int input_number = 0;
+static long input_devices[NBITS(INPUT_DEVICES)] = { 0, /* ... */ };
 
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
@@ -142,7 +147,8 @@
  */
 
 	while (handle) {
-		handle->handler->event(handle, type, code, value);
+		if (handle->open)
+			handle->handler->event(handle, type, code, value);
 		handle = handle->dnext;
 	}
 }
@@ -154,9 +160,48 @@
 	mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]);
 }
 
+int input_open_device(struct input_handle *handle)
+{
+	handle->open++;
+	if (handle->dev->open)
+		return handle->dev->open(handle->dev);
+	return 0;
+}
+
+void input_close_device(struct input_handle *handle)
+{
+	if (handle->dev->close)
+		handle->dev->close(handle->dev);
+	handle->open--;
+}
+
+static void input_link_handle(struct input_handle *handle)
+{
+	handle->dnext = handle->dev->handle;
+	handle->hnext = handle->handler->handle;
+	handle->dev->handle = handle;
+	handle->handler->handle = handle;
+}
+
+static void input_unlink_handle(struct input_handle *handle)
+{
+	struct input_handle **handleptr;
+
+	handleptr = &handle->dev->handle;
+	while (*handleptr && (*handleptr != handle))
+		handleptr = &((*handleptr)->dnext);
+	*handleptr = (*handleptr)->dnext;
+
+	handleptr = &handle->handler->handle;
+	while (*handleptr && (*handleptr != handle))
+		handleptr = &((*handleptr)->hnext);
+	*handleptr = (*handleptr)->hnext;
+}
+
 void input_register_device(struct input_dev *dev)
 {
 	struct input_handler *handler = input_handler;
+	struct input_handle *handle;
 
 /*
  * Initialize repeat timer to default values.
@@ -172,17 +217,25 @@
  * Add the device.
  */
 
-	MOD_INC_USE_COUNT;
-	dev->number = input_number++;
+	if (input_number >= INPUT_DEVICES) {
+		printk(KERN_WARNING "input: ran out of input device numbers!\n");
+		dev->number = input_number;
+	} else {
+		dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
+		set_bit(dev->number, input_devices);
+	}
+		
 	dev->next = input_dev;	
 	input_dev = dev;
+	input_number++;
 
 /*
  * Notify handlers.
  */
 
 	while (handler) {
-		handler->connect(handler, dev);
+		if ((handle = handler->connect(handler, dev)))
+			input_link_handle(handle);
 		handler = handler->next;
 	}
 }
@@ -203,6 +256,7 @@
  */
 
 	while (handle) {
+		input_unlink_handle(handle);
 		handle->handler->disconnect(handle);
 		handle = handle->dnext;
 	}
@@ -216,12 +270,22 @@
 	*devptr = (*devptr)->next;
 
 	input_number--;
-	MOD_DEC_USE_COUNT;
+
+	if (dev->number < INPUT_DEVICES)
+		clear_bit(dev->number, input_devices);
 }
 
 void input_register_handler(struct input_handler *handler)
 {
 	struct input_dev *dev = input_dev;
+	struct input_handle *handle;
+
+/*
+ * Add minors if needed.
+ */
+
+	if (handler->fops != NULL)
+		input_table[handler->minor >> 5] = handler;
 
 /*
  * Add the handler.
@@ -235,7 +299,8 @@
  */
 
 	while (dev) {
-		handler->connect(handler, dev);
+		if ((handle = handler->connect(handler, dev)))
+			input_link_handle(handle);
 		dev = dev->next;
 	}
 }
@@ -250,6 +315,7 @@
  */
 
 	while (handle) {
+		input_unlink_handle(handle);
 		handler->disconnect(handle);
 		handle = handle->hnext;
 	}
@@ -263,42 +329,59 @@
 
 	*handlerptr = (*handlerptr)->next;
 
+/*
+ * Remove minors.
+ */
+
+	if (handler->fops != NULL)
+		input_table[handler->minor >> 5] = NULL;
 }
 
-void input_open_device(struct input_handle *handle)
+static int input_open_file(struct inode *inode, struct file *file)
 {
-	handle->dnext = handle->dev->handle;
-	handle->hnext = handle->handler->handle;
-	handle->dev->handle = handle;
-	handle->handler->handle = handle;
+	struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5];
 
-	if (handle->dev->open)
-		handle->dev->open(handle->dev);
-}
+	if (!handler || !handler->fops || !handler->fops->open)
+		return -ENODEV;
 
-void input_close_device(struct input_handle *handle)
-{
-	struct input_handle **handleptr;
+	file->f_op = handler->fops;
 
-	if (handle->dev->close)
-		handle->dev->close(handle->dev);
-/*
- * Remove from device list of handles.
- */
+	return handler->fops->open(inode, file);
+}
 
-	handleptr = &handle->dev->handle;
+static struct file_operations input_fops = {
+	open: input_open_file,
+};
 
-	while (*handleptr && (*handleptr != handle))
-		handleptr = &((*handleptr)->dnext);
-	*handleptr = (*handleptr)->dnext;
+devfs_handle_t input_register_minor(char *name, int minor, int minor_base)
+{
+	char devfs_name[16];
+	sprintf(devfs_name, name, minor);
+	return devfs_register(input_devfs_handle, devfs_name, 0, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
+		S_IFCHR | S_IRUGO | S_IWUSR, 0, 0, &input_fops, NULL);
+}
 
-/*
- * Remove from handler list of handles.
- */
+void input_unregister_minor(devfs_handle_t handle)
+{
+	devfs_unregister(handle);
+}
 
-	handleptr = &handle->handler->handle;
+static int __init input_init(void)
+{
+	if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) {
+		printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
+		return -EBUSY;
+	}
+	input_devfs_handle = devfs_mk_dir(NULL, "input", 5, NULL);
+	return 0;
+}
 
-	while (*handleptr && (*handleptr != handle))
-		handleptr = &((*handleptr)->hnext);
-	*handleptr = (*handleptr)->hnext;
+static void __exit input_exit(void)
+{
+	devfs_unregister(input_devfs_handle);
+        if (devfs_unregister_chrdev(INPUT_MAJOR, "input"))
+                printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR);
 }
+
+module_init(input_init);
+module_exit(input_exit);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/joydev.c linux/drivers/usb/joydev.c
--- v2.3.99-pre3/linux/drivers/usb/joydev.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/usb/joydev.c	Mon Apr 10 22:53:15 2000
@@ -45,15 +45,18 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 
-#define JOYDEV_MAJOR            15
+#define JOYDEV_MINOR_BASE	0
+#define JOYDEV_MINORS		32
 #define JOYDEV_BUFFER_SIZE	64
 
 struct joydev {
-	char name[32];
 	int used;
-	struct input_handle handle;
+	int open;
 	int minor;
+	char name[32];
+	struct input_handle handle;
 	wait_queue_head_t wait;
+	devfs_handle_t devfs;
 	struct joydev *next;
 	struct joydev_list *list;
 	struct js_corr corr[ABS_MAX];
@@ -76,11 +79,10 @@
 	struct joydev_list *next;
 };
 
-static unsigned long joydev_minors = 0;
-static struct joydev *joydev_base[BITS_PER_LONG];
+static struct joydev *joydev_table[JOYDEV_MINORS];
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_SUPPORTED_DEVICE("js");
+MODULE_SUPPORTED_DEVICE("input/js");
 
 static int joydev_correct(int value, struct js_corr *corr)
 {
@@ -164,9 +166,13 @@
 	while (*listptr && (*listptr != list))
 		listptr = &((*listptr)->next);
 	*listptr = (*listptr)->next;
+
+	if (!--list->joydev->open)
+		input_close_device(&list->joydev->handle);
 	
 	if (!--list->joydev->used) {
-		clear_bit(list->joydev->minor, &joydev_minors);
+		input_unregister_minor(list->joydev->devfs);
+		joydev_table[list->joydev->minor] = NULL;
 		kfree(list->joydev);
 	}
 
@@ -179,28 +185,30 @@
 static int joydev_open(struct inode *inode, struct file *file)
 {
 	struct joydev_list *list;
-	int i = MINOR(inode->i_rdev);
+	int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
 
-	if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
-		return -EINVAL;
-
-	if (i > BITS_PER_LONG || !test_bit(i, &joydev_minors))
+	if (i > JOYDEV_MINORS || !joydev_table[i])
 		return -ENODEV;
 
-	if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
-		return -ENOMEM;
+	MOD_INC_USE_COUNT;
 
+	if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
 	memset(list, 0, sizeof(struct joydev_list));
 
-	list->joydev = joydev_base[i];
-	list->next = joydev_base[i]->list;
-	joydev_base[i]->list = list;	
+	list->joydev = joydev_table[i];
+	list->next = joydev_table[i]->list;
+	joydev_table[i]->list = list;	
 
 	file->private_data = list;
 
 	list->joydev->used++;
 
-	MOD_INC_USE_COUNT;
+	if (!list->joydev->open++)
+		input_open_device(&list->joydev->handle);
+
 	return 0;
 }
 
@@ -370,30 +378,33 @@
 	fasync:		joydev_fasync,
 };
 
-static int joydev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev)
 {
 	struct joydev *joydev;
-	int i, j;
+	int i, j, minor;
 
 	if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) &&
 	      test_bit(ABS_X, dev->absbit) && test_bit(ABS_Y, dev->absbit) &&
 	     (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit)
-		|| test_bit(BTN_1, dev->keybit)))) return -1;
+		|| test_bit(BTN_1, dev->keybit)))) return NULL; 
 
-	if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
-		return -1;
+	for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
+	if (joydev_table[minor]) {
+		printk(KERN_ERR "joydev: no more free joydev devices\n");
+		return NULL;
+	}
 
+	if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
+		return NULL;
 	memset(joydev, 0, sizeof(struct joydev));
 
 	init_waitqueue_head(&joydev->wait);
 
-	if (joydev_minors == -1) {
-		printk("Can't register new joystick - 32 devices already taken.\n");
-		return -1;
-	}
-
 	sprintf(joydev->name, "joydev%d", joydev->minor);
 
+	joydev->minor = minor;
+	joydev_table[minor] = joydev;
+
 	joydev->handle.dev = dev;
 	joydev->handle.handler = handler;
 	joydev->handle.private = joydev;
@@ -421,10 +432,6 @@
 			joydev->nkey++;
 		}
 
-	joydev->minor = ffz(joydev_minors);
-	set_bit(joydev->minor, &joydev_minors);
-	joydev_base[joydev->minor] = joydev;
-
 	for (i = 0; i < joydev->nabs; i++) {
 		j = joydev->abspam[i];
 		if (dev->absmax[j] == dev->absmin[j]) {
@@ -439,21 +446,23 @@
 		joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
 	}
 
-	input_open_device(&joydev->handle);	
+	joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
 
-	printk("%s: Joystick device for input%d on /dev/js%d\n", joydev->name, dev->number, joydev->minor);
+	printk("js%d: Joystick device for input%d\n", minor, dev->number);
 
-	return 0;
+	return &joydev->handle;
 }
 
 static void joydev_disconnect(struct input_handle *handle)
 {
 	struct joydev *joydev = handle->private;
 
-	input_close_device(handle);
+	if (joydev->open)
+		input_close_device(handle);	
 
 	if (!--joydev->used) {
-		clear_bit(joydev->minor, &joydev_minors);
+		input_unregister_minor(joydev->devfs);
+		joydev_table[joydev->minor] = NULL;
 		kfree(joydev);
 	}
 }
@@ -462,14 +471,12 @@
 	event:		joydev_event,
 	connect:	joydev_connect,
 	disconnect:	joydev_disconnect,
+	fops:		&joydev_fops,
+	minor:		JOYDEV_MINOR_BASE,
 };
 
 static int __init joydev_init(void)
 {
-	if (register_chrdev(JOYDEV_MAJOR, "js", &joydev_fops)) {
-		printk(KERN_ERR "joydev: unable to get major %d for joystick\n", JOYDEV_MAJOR);
-		return -EBUSY;
-	}
 	input_register_handler(&joydev_handler);
 	return 0;
 }
@@ -477,8 +484,6 @@
 static void __exit joydev_exit(void)
 {
 	input_unregister_handler(&joydev_handler);
-	if (unregister_chrdev(JOYSTICK_MAJOR, "js"))
-		printk(KERN_ERR "js: can't unregister device\n");
 }
 
 module_init(joydev_init);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c
--- v2.3.99-pre3/linux/drivers/usb/keybdev.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/keybdev.c	Mon Apr 10 22:53:15 2000
@@ -36,17 +36,63 @@
 #include <linux/module.h>
 #include <linux/kbd_kern.h>
 
-#if defined(CONFIG_X86) || defined(CONFIG_IA64)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS)
 
-static unsigned char keybdev_x86_e0s[] = 
-	{ 0x1c, 0x1d, 0x35, 0x2a, 0x38, 0x39, 0x47, 0x48,
-	  0x49, 0x4b, 0x4d, 0x4f, 0x50, 0x51, 0x52, 0x53,
-	  0x26, 0x25, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x00,
-	  0x23, 0x24, 0x25, 0x26, 0x27 };
+static int x86_sysrq_alt = 0;
 
-#elif CONFIG_ADB_KEYBOARD
+static unsigned short x86_keycodes[256] =
+	{ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+	 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+	 80, 81, 82, 83, 89, 85, 86, 87, 88,115,119,120,121,375,123, 90,
+	284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339,
+	367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349,
+	360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
+	103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361,
+	291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114,
+	118,117,125,374,379,259,260,261,262,263,264,265,266,267,268,269,
+	271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307,
+	308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
+	332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
 
-static unsigned char keybdev_mac_codes[256] =
+static int emulate_raw(unsigned int keycode, int down)
+{
+	if (keycode > 255 || !x86_keycodes[keycode])
+		return -1; 
+
+	if (keycode == KEY_PAUSE) {
+		handle_scancode(0xe1, 1);
+		handle_scancode(0x1d, down);
+		handle_scancode(0x45, down);
+		return 0;
+	} 
+
+	if (keycode == KEY_SYSRQ && x86_sysrq_alt) {
+		handle_scancode(0x54, down);
+		return 0;
+	}
+
+	if (x86_keycodes[keycode] & 0x100)
+		handle_scancode(0xe0, 1);
+
+	handle_scancode(x86_keycodes[keycode] & 0x7f, down);
+
+	if (keycode == KEY_SYSRQ) {
+		handle_scancode(0xe0, 1);
+		handle_scancode(0x37, down);
+	}
+
+	if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
+		x86_sysrq_alt = down;
+
+	return 0;
+}
+
+#elif defined(CONFIG_ADB_KEYBOARD)
+
+static unsigned char mac_keycodes[128] =
 	{ 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
 	 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128,  1,
 	  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
@@ -56,10 +102,19 @@
 	 76,125, 75,105,124,  0,115, 62,116, 59, 60,119, 61,121,114,117,
 	  0,  0,  0,  0,127, 81,  0,113,  0,  0,  0,  0,  0, 55, 55 };
 
+static int emulate_raw(unsigned int code, unsigned char upflag)
+{
+	if (keycode > 127 || !mac_keycodes[keycode])
+		return -1;
+
+	handle_scancode(mac_keycodes[keycode] & 0x7f, down);
+
+	return 0;
+}
+
 #endif
 
 static struct input_handler keybdev_handler;
-static int keybdev_alt = 0;
 
 void keybdev_ledfunc(unsigned int led)
 {
@@ -76,70 +131,30 @@
 
 void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down)
 {
-	if (type != EV_KEY || code > 255) return;
+	if (type != EV_KEY) return;
 
-#if defined(CONFIG_X86) || defined(CONFIG_IA64)
-
-	if (code >= 189) {
-  		printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code);
-		return; 
-	} else if (code >= 162) {
-		handle_scancode(0xe0, 1);
-		handle_scancode(code - 161, down);
-	} else if (code >= 125) {
-		handle_scancode(0xe0, 1);
-		handle_scancode(code - 34, down);
-	} else if (code == 119) {
-		handle_scancode(0xe1, 1);
-		handle_scancode(0x1d, down);
-		handle_scancode(0x45, down);
-	} else if (code >= 96) {
-		if (code == 99 && keybdev_alt) {
-			 handle_scancode(84, down);
-		} else {
-			handle_scancode(0xe0, 1);
-			handle_scancode(keybdev_x86_e0s[code - 96], down);
-			if (code == 99) {
-				handle_scancode(0xe0, 1);
-				handle_scancode(0x37, down);
-			}
-		}
-	} else if (code == 84) {
-		handle_scancode(43, down);
-	} else handle_scancode(code, down);
-
-	if (code == 56 || code == 100) keybdev_alt = down;
-
-#elif CONFIG_ADB_KEYBOARD
-
-	if (code < 128 && keybdev_mac_codes[code]) 
-		handle_scancode(keybdev_mac_codes[code] & 0x7f, down);
-	else
-		printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code);
-
-#else
-#error "Cannot generate rawmode keyboard for your architecture yet."
-#endif
+	if (emulate_raw(code, down))
+		printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code);
 
 	tasklet_schedule(&keyboard_tasklet);
 }
 
-static int keybdev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev)
 {
 	struct input_handle *handle;
 	int i;
 
 	if (!test_bit(EV_KEY, dev->evbit))
-		return -1;
+		return NULL;
 
 	for (i = KEY_RESERVED; i < BTN_MISC; i++)
 		if (test_bit(i, dev->keybit)) break;
 
 	if (i == BTN_MISC)
- 		return -1;
+ 		return NULL;
 
 	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
-		return -1;
+		return NULL;
 	memset(handle, 0, sizeof(struct input_handle));
 
 	handle->dev = dev;
@@ -149,15 +164,13 @@
 
 	printk("keybdev.c: Adding keyboard: input%d\n", dev->number);
 
-	return 0;
+	return handle;
 }
 
 static void keybdev_disconnect(struct input_handle *handle)
 {
 	printk("keybdev.c: Removing keyboard: input%d\n", handle->dev->number);
-
 	input_close_device(handle);
-
 	kfree(handle);
 }
 	
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c
--- v2.3.99-pre3/linux/drivers/usb/mdc800.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/mdc800.c	Wed Apr  5 16:58:48 2000
@@ -26,11 +26,19 @@
  * To use the Camera you must support the USB Protocoll of the camera
  * to the Kernel Node.
  * The Driver uses a misc device Node. Create it with :
- * mknod /dev/mustek c 10 171
+ * mknod /dev/mustek c 180 32
  *
  * The driver supports only one camera.
  *
  * version 0.7.1
+ * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload
+ * problems when compiled as Module.
+ * (04/04/2000)
+ *
+ * The mdc800 driver gets assigned the USB Minor 32-47. The Registration
+ * was updated to use these values.
+ * (26/03/2000)
+ *
  * The Init und Exit Module Function are updated.
  * (01/03/2000)
  *
@@ -57,7 +65,6 @@
 #include <linux/signal.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
-#include <linux/miscdevice.h>
 #include <linux/random.h>
 #include <linux/poll.h>
 #include <linux/init.h>
@@ -67,22 +74,22 @@
 #include <linux/usb.h>
 
 #define VERSION 		"0.7.1"
-#define RELEASE_DATE "(01/03/2000)"
+#define RELEASE_DATE "(26/03/2000)"
 
 /* Vendor and Product Information */
 #define MDC800_VENDOR_ID 	0x055f
 #define MDC800_PRODUCT_ID	0xa800
 
 /* Timeouts (msec) */
-#define TO_READ_FROM_IRQ 			4000
+#define TO_READ_FROM_IRQ 		4000
 #define TO_GET_READY				2000
-#define TO_DOWNLOAD_GET_READY			1500
-#define TO_DOWNLOAD_GET_BUSY			1500
-#define TO_WRITE_GET_READY			3000
-#define TO_DEFAULT_COMMAND			5000
+#define TO_DOWNLOAD_GET_READY	1500
+#define TO_DOWNLOAD_GET_BUSY	1500
+#define TO_WRITE_GET_READY		3000
+#define TO_DEFAULT_COMMAND		5000
 
-/* Minor Number of the device (create with mknod /dev/mustek c 10 171) */
-#define MDC800_DEVICE_MINOR 171
+/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
+#define MDC800_DEVICE_MINOR_BASE 32
 
 
 /**************************************************************************
@@ -514,11 +521,20 @@
 static int mdc800_device_open (struct inode* inode, struct file *file)
 {
 	int retval=0;
+	
+	MOD_INC_USE_COUNT;
+	
 	if (mdc800->state == NOT_CONNECTED)
+	{
+		MOD_DEC_USE_COUNT;
 		return -EBUSY;
+	}
 
 	if (mdc800->open)
+	{
+		MOD_DEC_USE_COUNT;
 		return -EBUSY;
+	}
 
 	mdc800->rw_lock=0;
 	mdc800->in_count=0;
@@ -535,10 +551,10 @@
 	if (usb_submit_urb (mdc800->irq_urb))
 	{
 		err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
-	MOD_INC_USE_COUNT;
 	mdc800->open=1;
 
 	dbg ("Mustek MDC800 device opened.");
@@ -792,21 +808,6 @@
 	Init and Cleanup this driver (Structs and types)
 ****************************************************************************/
 
-
-/*
- * USB Driver Struct for this device
- */
-static struct usb_driver mdc800_usb_driver =
-{
-	"mdc800",
-	mdc800_usb_probe,
-	mdc800_usb_disconnect,
-	{ 0,0 },
-	0,
-	0
-};
-
-
 /* File Operations of this drivers */
 static struct file_operations mdc800_device_ops =
 {
@@ -828,17 +829,22 @@
 };
 
 
+
 /*
- * The Misc Device Configuration Struct
+ * USB Driver Struct for this device
  */
-static struct miscdevice mdc800_device =
+static struct usb_driver mdc800_usb_driver =
 {
-	MDC800_DEVICE_MINOR,
-	"USB Mustek MDC800 Camera",
-	&mdc800_device_ops
+	"mdc800",
+	mdc800_usb_probe,
+	mdc800_usb_disconnect,
+	{ 0,0 },
+	&mdc800_device_ops,
+	MDC800_DEVICE_MINOR_BASE
 };
 
 
+
 /************************************************************************
 	Init and Cleanup this driver (Main Functions)
 *************************************************************************/
@@ -872,8 +878,6 @@
 	/* Register the driver */
 	if (usb_register (&mdc800_usb_driver) < 0)
 		goto cleanup_on_fail;
-	if (misc_register (&mdc800_device) < 0)
-		goto cleanup_on_misc_register_fail;
 
 	info ("Mustek Digital Camera Driver " VERSION " (MDC800)");
 	info (RELEASE_DATE " Henning Zabel <henning@uni-paderborn.de>");
@@ -882,9 +886,6 @@
 
 	/* Clean driver up, when something fails */
 
-cleanup_on_misc_register_fail:
-	usb_deregister (&mdc800_usb_driver);
-
 cleanup_on_fail:
 
 	if (mdc800 != 0)
@@ -909,7 +910,6 @@
 void __exit usb_mdc800_cleanup (void)
 {
 	usb_deregister (&mdc800_usb_driver);
-	misc_deregister (&mdc800_device);
 
 	usb_free_urb (mdc800->irq_urb);
 	usb_free_urb (mdc800->download_urb);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/mousedev.c linux/drivers/usb/mousedev.c
--- v2.3.99-pre3/linux/drivers/usb/mousedev.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/mousedev.c	Mon Apr 10 22:53:15 2000
@@ -29,8 +29,9 @@
  */
 
 #define MOUSEDEV_MINOR_BASE 	32
+#define MOUSEDEV_MINORS		32
+#define MOUSEDEV_MIX		31
 
-#include <linux/miscdevice.h>
 #include <linux/malloc.h>
 #include <linux/poll.h>
 #include <linux/module.h>
@@ -46,12 +47,13 @@
 #endif
 
 struct mousedev {
-	char name[32];
 	int used;
-	struct input_handle handle;
-	struct miscdevice misc;
+	int open;
+	int minor;
 	wait_queue_head_t wait;
 	struct mousedev_list *list;
+	struct input_handle handle;
+	devfs_handle_t devfs;
 };
 
 struct mousedev_list {
@@ -71,77 +73,80 @@
 static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 };
 static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
 
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
-static struct mousedev mousedev_single;
-#else
-static unsigned long mousedev_miscbits = 0;
-static struct mousedev *mousedev_base[BITS_PER_LONG];
-#endif
+static struct input_handler mousedev_handler;
+
+static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
+static struct mousedev mousedev_mix;
 
 static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
-	struct mousedev *mousedev = handle->private;
-	struct mousedev_list *list = mousedev->list;
+	struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
+	struct mousedev **mousedev = mousedevs;
+	struct mousedev_list *list;
 	int index, size;
 
-	while (list) {
-		switch (type) {
-			case EV_ABS:
-				switch (code) {
-					case ABS_X:	
-						size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
-						list->dx += (value * CONFIG_MOUSEDEV_SCREEN_X - list->oldx) / size;
-						list->oldx += list->dx * size;
-						break;
-					case ABS_Y:
-						size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
-						list->dy -= (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size;
-						list->oldy -= list->dy * size;
-						break;
-				}
-				break;
-			case EV_REL:
-				switch (code) {
-					case REL_X:	list->dx += value; break;
-					case REL_Y:	list->dy -= value; break;
-					case REL_WHEEL:	if (list->mode) list->dz -= value; break;
-				}
-				break;
+	while (*mousedev) {
+		list = (*mousedev)->list;
+		while (list) {
+			switch (type) {
+				case EV_ABS:
+					switch (code) {
+						case ABS_X:	
+							size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
+							list->dx += (value * CONFIG_MOUSEDEV_SCREEN_X - list->oldx) / size;
+							list->oldx += list->dx * size;
+							break;
+						case ABS_Y:
+							size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
+							list->dy -= (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size;
+							list->oldy -= list->dy * size;
+							break;
+					}
+					break;
+				case EV_REL:
+					switch (code) {
+						case REL_X:	list->dx += value; break;
+						case REL_Y:	list->dy -= value; break;
+						case REL_WHEEL:	if (list->mode) list->dz -= value; break;
+					}
+					break;
+
+				case EV_KEY:
+					switch (code) {
+						case BTN_0:
+						case BTN_TOUCH:
+						case BTN_LEFT:   index = 0; break;
+						case BTN_4:
+						case BTN_EXTRA:  if (list->mode > 1) { index = 4; break; }
+						case BTN_STYLUS:
+						case BTN_1:
+						case BTN_RIGHT:  index = 1; break;
+						case BTN_3:
+						case BTN_SIDE:   if (list->mode > 1) { index = 3; break; }
+						case BTN_2:
+						case BTN_STYLUS2:
+						case BTN_MIDDLE: index = 2; break;	
+						default: return;
+					}
+					switch (value) {
+						case 0: clear_bit(index, &list->buttons); break;
+						case 1: set_bit(index, &list->buttons); break;
+						case 2: return;
+					}
+					break;
+			}
+					
+			list->ready = 1;
 
-			case EV_KEY:
-				switch (code) {
-					case BTN_0:
-					case BTN_TOUCH:
-					case BTN_LEFT:   index = 0; break;
-					case BTN_4:
-					case BTN_EXTRA:  if (list->mode > 1) { index = 4; break; }
-					case BTN_STYLUS:
-					case BTN_1:
-					case BTN_RIGHT:  index = 1; break;
-					case BTN_3:
-					case BTN_SIDE:   if (list->mode > 1) { index = 3; break; }
-					case BTN_2:
-					case BTN_STYLUS2:
-					case BTN_MIDDLE: index = 2; break;	
-					default: return;
-				}
-				switch (value) {
-					case 0: clear_bit(index, &list->buttons); break;
-					case 1: set_bit(index, &list->buttons); break;
-					case 2: return;
-				}
-				break;
-		}
-				
-		list->ready = 1;
+			if (list->fasync)
+				kill_fasync(list->fasync, SIGIO, POLL_IN);
 
-		if (list->fasync)
-			kill_fasync(list->fasync, SIGIO, POLL_IN);
+			list = list->next;
+		}
 
-		list = list->next;
+		wake_up_interruptible(&((*mousedev)->wait));
+		mousedev++;
 	}
-
-	wake_up_interruptible(&mousedev->wait);
 }
 
 static int mousedev_fasync(int fd, struct file *file, int on)
@@ -162,14 +167,27 @@
 	while (*listptr && (*listptr != list))
 		listptr = &((*listptr)->next);
 	*listptr = (*listptr)->next;
+
+	if (!--list->mousedev->open) {
+		if (list->mousedev->minor == MOUSEDEV_MIX) {
+			struct input_handle *handle = mousedev_handler.handle;
+			while (handle) {
+				struct mousedev *mousedev = handle->private;
+				if (!mousedev->open)
+					input_close_device(handle);
+				handle = handle->hnext;
+			}
+		} else {
+			if (!mousedev_mix.open)	
+				input_close_device(&list->mousedev->handle);
+		}
+	}
 	
-#ifndef CONFIG_INPUT_MOUSEDEV_MIX
 	if (!--list->mousedev->used) {
-		clear_bit(list->mousedev->misc.minor - MOUSEDEV_MINOR_BASE, &mousedev_miscbits);
-		misc_deregister(&list->mousedev->misc);
+		input_unregister_minor(list->mousedev->devfs);
+		mousedev_table[list->mousedev->minor] = NULL;
 		kfree(list->mousedev);
 	}
-#endif
 
 	kfree(list);
 
@@ -180,33 +198,41 @@
 static int mousedev_open(struct inode * inode, struct file * file)
 {
 	struct mousedev_list *list;
-
-#ifndef CONFIG_INPUT_MOUSEDEV_MIX
 	int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
-	if (i > BITS_PER_LONG || !test_bit(i, &mousedev_miscbits))
+
+	if (i > MOUSEDEV_MINORS || !mousedev_table[i])
 		return -ENODEV;
-#endif
 
-	if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
-		return -ENOMEM;
+	MOD_INC_USE_COUNT;
 
+	if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
 	memset(list, 0, sizeof(struct mousedev_list));
 
+	list->mousedev = mousedev_table[i];
+	list->next = mousedev_table[i]->list;
+	mousedev_table[i]->list = list;
+	file->private_data = list;
 
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
-	list->mousedev = &mousedev_single;
-	list->next = mousedev_single.list;
-	mousedev_single.list = list;
-#else
-	list->mousedev = mousedev_base[i];
-	list->next = mousedev_base[i]->list;
-	mousedev_base[i]->list = list;
 	list->mousedev->used++;
-#endif
 
-	file->private_data = list;
+	if (!list->mousedev->open++) {
+		if (list->mousedev->minor == MOUSEDEV_MIX) {
+			struct input_handle *handle = mousedev_handler.handle;
+			while (handle) {
+				struct mousedev *mousedev = handle->private;
+				if (!mousedev->open)
+					input_open_device(handle);
+				handle = handle->hnext;
+			}
+		} else {
+			if (!mousedev_mix.open)	
+				input_open_device(&list->mousedev->handle);
+		}
+	}
 
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -357,119 +383,93 @@
 	fasync:		mousedev_fasync,
 };
 
-static int mousedev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev)
 {
+	struct mousedev *mousedev;
+	int minor = 0;
 
 	if (!test_bit(EV_KEY, dev->evbit) ||
 	   (!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit)))
-		return -1;
+		return NULL;
 
 	if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) &&
 	    (!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit)))
-		return -1;
-	
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
-	{
-		struct input_handle *handle;
+		return NULL;
 
-		if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
-			return -1;
-
-		memset(handle, 0, sizeof(struct input_handle));
-
-		handle->dev = dev;
-		handle->handler = handler;
-		handle->private = &mousedev_single;
-
-		input_open_device(handle);
-
-		printk("mousedev.c: Adding mouse: input%d\n", dev->number);
+	for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
+	if (mousedev_table[minor]) {
+		printk(KERN_ERR "mousedev: no more free mousedev devices\n");
+		return NULL;
 	}
-#else
-	{
-		struct mousedev *mousedev;
-
-		if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
-			return -1;
-
-		memset(mousedev, 0, sizeof(struct mousedev));
-
-		mousedev->misc.minor = ffz(mousedev_miscbits);
-		set_bit(mousedev->misc.minor, &mousedev_miscbits);
-		mousedev_base[mousedev->misc.minor] = mousedev;
 
-		sprintf(mousedev->name, "mousedev%d", mousedev->misc.minor);
-		mousedev->misc.name = mousedev->name;
-		mousedev->misc.minor += MOUSEDEV_MINOR_BASE;
-		mousedev->misc.fops = &mousedev_fops;
+	if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
+		return NULL;
+	memset(mousedev, 0, sizeof(struct mousedev));
+	init_waitqueue_head(&mousedev->wait);
+
+	mousedev->used = 1;
+	mousedev->minor = minor;
+	mousedev_table[minor] = mousedev;
+
+	mousedev->handle.dev = dev;
+	mousedev->handle.handler = handler;
+	mousedev->handle.private = mousedev;
 
-		mousedev->handle.dev = dev;
-		mousedev->handle.handler = handler;
-		mousedev->handle.private = mousedev;
+	mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE);
 
-		init_waitqueue_head(&mousedev->wait);
-
-		mousedev->used = 1;
-
-		misc_register(&mousedev->misc);
+	if (mousedev_mix.open) {
 		input_open_device(&mousedev->handle);
-
-		printk("%s: PS/2 mouse device for input%d on misc%d\n",
-			mousedev->name, dev->number, mousedev->misc.minor);
+		mousedev_mix.open++;
 	}
-#endif
 
-	return 0;
+	printk("mouse%d: PS/2 mouse device for input%d\n", minor, dev->number);
+
+	return &mousedev->handle;
 }
 
 static void mousedev_disconnect(struct input_handle *handle)
 {
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
-	printk("mousedev.c: Removing mouse: input%d\n", handle->dev->number);
-	input_close_device(handle);
-	kfree(handle);
-#else
 	struct mousedev *mousedev = handle->private;
-	input_close_device(handle);
+
+	if (mousedev->open || mousedev_mix.open) {
+		input_close_device(handle);
+		mousedev_mix.open--;
+	}
+
 	if (!--mousedev->used) {
-		clear_bit(mousedev->misc.minor - MOUSEDEV_MINOR_BASE, &mousedev_miscbits);
-		misc_deregister(&mousedev->misc);
+		input_unregister_minor(mousedev->devfs);
+		mousedev_table[mousedev->minor] = NULL;
 		kfree(mousedev);
 	}
-#endif
 }
 	
 static struct input_handler mousedev_handler = {
 	event:		mousedev_event,
 	connect:	mousedev_connect,
 	disconnect:	mousedev_disconnect,
+	fops:		&mousedev_fops,
+	minor:		MOUSEDEV_MINOR_BASE,
 };
 
 static int __init mousedev_init(void)
 {
 	input_register_handler(&mousedev_handler);
 
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
-	memset(&mousedev_single, 0, sizeof(struct mousedev));
-
-	init_waitqueue_head(&mousedev_single.wait);
-	mousedev_single.misc.minor = MOUSEDEV_MINOR_BASE;
-	mousedev_single.misc.name = "mousedev";
-	mousedev_single.misc.fops = &mousedev_fops;
+	memset(&mousedev_mix, 0, sizeof(struct mousedev));
+	init_waitqueue_head(&mousedev_mix.wait);
+	mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
+	mousedev_mix.used = 1;
+	mousedev_mix.minor = MOUSEDEV_MIX;
+	mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
 
-	misc_register(&mousedev_single.misc);
-
-	printk("mousedev: PS/2 mouse device on misc%d\n", mousedev_single.misc.minor);
-#endif
+	printk("mice: PS/2 mouse device common for all mice\n");
 
 	return 0;
 }
 
 static void __exit mousedev_exit(void)
 {
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
-	misc_deregister(&mousedev_single.misc);
-#endif
+	input_unregister_minor(mousedev_mix.devfs);
 	input_unregister_handler(&mousedev_handler);
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- v2.3.99-pre3/linux/drivers/usb/ov511.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/usb/ov511.c	Wed Apr  5 17:01:56 2000
@@ -4,12 +4,13 @@
  * Many improvements by Bret Wallach
  * Color fixes by by Orion Sky Lawlor, olawlor@acm.org, 2/26/2000
  * Snapshot code by Kevin Moore
+ * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
  * 
  * Based on the Linux CPiA driver.
  * 
  * Released under GPL v.2 license.
  *
- * Version: 1.09
+ * Version: 1.11
  *
  * Please see the file: linux/Documentation/usb/ov511.txt 
  * and the website at:  http://alpha.dyndns.org/ov511 
@@ -34,8 +35,6 @@
 
 #define __NO_VERSION__
 
-/* Handle mangled (versioned) external symbols */
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/list.h>
@@ -83,10 +82,14 @@
 /* Snapshot mode enabled flag */
 static int snapshot = 0;
 
+/* Sensor detection override (global for all attached cameras) */
+static int sensor = 0;
+
 MODULE_PARM(autoadjust, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(fix_rgb_offset, "i");
 MODULE_PARM(snapshot, "i");
+MODULE_PARM(sensor, "i");
 
 MODULE_AUTHOR("Mark McClelland (and others)");
 MODULE_DESCRIPTION("OV511 USB Camera Driver");
@@ -210,7 +213,9 @@
 	vfree(mem);
 }
 
-int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+static int ov511_reg_write(struct usb_device *dev,
+                           unsigned char reg,
+                           unsigned char value)
 {
 	int rc;
 
@@ -219,14 +224,17 @@
 		2 /* REG_IO */,
 		USB_TYPE_CLASS | USB_RECIP_DEVICE,
 		0, (__u16)reg, &value, 1, HZ);	
-			
+
 	PDEBUG(5, "reg write: 0x%02X:0x%02X, 0x%x", reg, value, rc);
-		
+
+	if (rc < 0)
+		err("ov511_reg_write: error %d", rc);
+
 	return rc;
 }
 
 /* returns: negative is error, pos or zero is data */
-int ov511_reg_read(struct usb_device *dev, unsigned char reg)
+static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
 {
 	int rc;
 	unsigned char buffer[1];
@@ -239,13 +247,17 @@
                                
 	PDEBUG(5, "reg read: 0x%02X:0x%02X", reg, buffer[0]);
 	
-	if(rc < 0)
+	if(rc < 0) {
+		err("ov511_reg_read: error %d", rc);
 		return rc;
+	}
 	else
 		return buffer[0];	
 }
 
-int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+static int ov511_i2c_write(struct usb_device *dev,
+                           unsigned char reg,
+                           unsigned char value)
 {
 	int rc, retries;
 
@@ -255,19 +267,19 @@
 	for(retries = OV511_I2C_RETRIES;;) {
 		/* Select camera register */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
-		if (rc < 0) return rc;
+		if (rc < 0) goto error;
 
 		/* Write "value" to I2C data port of OV511 */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);	
-		if (rc < 0) return rc;
+		if (rc < 0) goto error;
 
 		/* Initiate 3-byte write cycle */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01);
-		if (rc < 0) return rc;
+		if (rc < 0) goto error;
 
 		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
 		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) return rc;
+		if (rc < 0) goto error;
 
 		if((rc&2) == 0) /* Ack? */
 			break;
@@ -275,14 +287,22 @@
 		/* I2C abort */	
 		ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
 #endif
-		if (--retries < 0) return -1;
+		if (--retries < 0) {
+			err("i2c write retries exhausted");
+			rc = -1;
+			goto error;
+		}
 	}
 
 	return 0;
+
+error:
+	err("ov511_i2c_write: error %d", rc);
+	return rc;
 }
 
 /* returns: negative is error, pos or zero is data */
-int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
+static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
 {
 	int rc, value, retries;
 
@@ -290,15 +310,15 @@
 	for(retries = OV511_I2C_RETRIES;;) {
 		/* Select camera register */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
-		if (rc < 0) return rc;
+		if (rc < 0) goto error;
 
 		/* Initiate 2-byte write cycle */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
-		if (rc < 0) return rc;
+		if (rc < 0) goto error;
 
 		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
 		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) return rc;
+		if (rc < 0) goto error;
 
 		if((rc&2) == 0) /* Ack? */
 			break;
@@ -306,27 +326,35 @@
 		/* I2C abort */	
 		ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
 
-		if (--retries < 0) return -1;
+		if (--retries < 0) {
+			err("i2c write retries exhausted");
+			rc = -1;
+			goto error;
+		}
 	}
 
 	/* Two byte read cycle */
 	for(retries = OV511_I2C_RETRIES;;) {
 		/* Initiate 2-byte read cycle */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
-		if (rc < 0) return rc;
+		if (rc < 0) goto error;
 
 		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
 		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) return rc;
+		if (rc < 0) goto error;
 
 		if((rc&2) == 0) /* Ack? */
 			break;
 
 		/* I2C abort */	
 		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
-		if (rc < 0) return rc;
+		if (rc < 0) goto error;
 
-		if (--retries < 0) return -1;
+		if (--retries < 0) {
+			err("i2c read retries exhausted");
+			rc = -1;
+			goto error;
+		}
 	}
 
 	value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
@@ -335,60 +363,41 @@
 		
 	/* This is needed to make ov511_i2c_write() work */
 	rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
-	if (rc < 0) return rc;
+	if (rc < 0) goto error;
 	
-	return (value);
-}
-
-
-// This version doesn't always work
-#if 0
- /* returns: negative is error, pos or zero is data */
- int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
- {
-	int rc, value;
-
-	/* Select camera register */
-	rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
-	if (rc < 0) return rc;
- 
-
-	/* Initiate 2-byte write cycle */
-	rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
-	if (rc < 0) return rc;
- 
-
-	/* Initiate 2-byte read cycle */
-	rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
-	if (rc < 0) return rc;
- 
- 	value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
+	return value;
 
- 	PDEBUG(5, "i2c read: 0x%02X:0x%02X", reg, value);
- 		
- 	return (value);
- }
-#endif
+error:
+	err("ov511_i2c_read: error %d", rc);
+	return rc;
+}
 
 static int ov511_write_regvals(struct usb_device *dev,
 			       struct ov511_regvals * pRegvals)
 {
-	int ret;
+	int rc;
+
 	while(pRegvals->bus != OV511_DONE_BUS) {
 		if (pRegvals->bus == OV511_REG_BUS) {
-			if ((ret = ov511_reg_write(dev, pRegvals->reg,
+			if ((rc = ov511_reg_write(dev, pRegvals->reg,
 			                           pRegvals->val)) < 0)
-				return ret;
+				goto error;
 		} else if (pRegvals->bus == OV511_I2C_BUS) {
-			if ((ret = ov511_i2c_write(dev, pRegvals->reg, 
+			if ((rc = ov511_i2c_write(dev, pRegvals->reg, 
 			                           pRegvals->val)) < 0)
-				return ret;
+				goto error;
 		} else {
-		  err("Bad regval array");
+			err("Bad regval array");
+			rc = -1;
+			goto error;
 		}
 		pRegvals++;
 	}
 	return 0;
+
+error:
+	err("ov511_write_regvals: error %d", rc);
+	return rc;
 }
 
 #if 0
@@ -396,10 +405,9 @@
 {
 	int i;
 	int rc;
-	for(i=reg1; i<=regn; i++) {
-	  rc = ov511_i2c_read(dev, i);
-
-	  PDEBUG(1, "OV7610[0x%X] = 0x%X", i, rc);
+	for(i = reg1; i <= regn; i++) {
+		rc = ov511_i2c_read(dev, i);
+		PDEBUG(1, "OV7610[0x%X] = 0x%X", i, rc);
 	}
 }
 
@@ -413,7 +421,7 @@
 {
 	int i;
 	int rc;
-	for(i=reg1; i<=regn; i++) {
+	for(i = reg1; i <= regn; i++) {
 	  rc = ov511_reg_read(dev, i);
 	  PDEBUG(1, "OV511[0x%X] = 0x%X", i, rc);
 	}
@@ -443,72 +451,82 @@
 }
 #endif
 
-int ov511_reset(struct usb_device *dev, unsigned char reset_type)
+static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
 {
 	int rc;
 	
 	PDEBUG(3, "Reset: type=0x%X", reset_type);
 	rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
-	if (rc < 0)
-		err("reset: command failed");
-
 	rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
+
 	if (rc < 0)
 		err("reset: command failed");
 
 	return rc;
 }
 
-int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
+/* Temporarily stops OV511 from functioning. Must do this before changing
+ * registers while the camera is streaming */
+static inline int ov511_stop(struct usb_device *dev)
 {
-	int alt, multiplier, rc;
-		
-	PDEBUG(3, "set packet size: %d", size);
-	
-	switch (size) {
-		case 992:
-			alt = 0;
-			multiplier = 31;
-			break;
-		case 993:
-			alt = 1;
-			multiplier = 31;
-			break;
-		case 768:
-			alt = 2;
-			multiplier = 24;
-			break;
-		case 769:
-			alt = 3;
-			multiplier = 24;
-			break;
-		case 512:
-			alt = 4;
-			multiplier = 16;
-			break;
-		case 513:
-			alt = 5;
-			multiplier = 16;
-			break;
-		case 257:
-			alt = 6;
-			multiplier = 8;
-			break;
-		case 0:
-			alt = 7;
-			multiplier = 1; // FIXME - is this correct?
-			break;
-		default:
+	PDEBUG(4, "ov511_stop()");
+	return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d));
+}
+
+/* Restarts OV511 after ov511_stop() is called */
+static inline int ov511_restart(struct usb_device *dev)
+{
+	PDEBUG(4, "ov511_restart()");
+	return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00));
+}
+
+static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
+{
+	int alt, mult;
+
+	if (ov511_stop(ov511->dev) < 0)
+		return -EIO;
+
+	mult = size / 32;
+
+	if (ov511->bridge == BRG_OV511) {
+		if (size == 0) alt = OV511_ALT_SIZE_0;
+		else if (size == 257) alt = OV511_ALT_SIZE_257;
+//		else if (size == 512) alt = OV511_ALT_SIZE_512;
+		else if (size == 513) alt = OV511_ALT_SIZE_513;
+//		else if (size == 768) alt = OV511_ALT_SIZE_768;
+		else if (size == 769) alt = OV511_ALT_SIZE_769;
+//		else if (size == 992) alt = OV511_ALT_SIZE_992;
+		else if (size == 993) alt = OV511_ALT_SIZE_993;
+		else {
+			err("Set packet size: invalid size (%d)", size);
+			return -EINVAL;
+		}
+	}
+	else if (ov511->bridge == BRG_OV511PLUS) {
+		if (size == 0) alt = OV511PLUS_ALT_SIZE_0;
+		else if (size == 33) alt = OV511PLUS_ALT_SIZE_33;
+		else if (size == 129) alt = OV511PLUS_ALT_SIZE_129;
+		else if (size == 257) alt = OV511PLUS_ALT_SIZE_257;
+		else if (size == 385) alt = OV511PLUS_ALT_SIZE_385;
+		else if (size == 513) alt = OV511PLUS_ALT_SIZE_513;
+		else if (size == 769) alt = OV511PLUS_ALT_SIZE_769;
+		else if (size == 961) alt = OV511PLUS_ALT_SIZE_961;
+		else {
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
+		}
+	}
+	else {
+		err("Set packet size: Invalid bridge type");
+		return -EINVAL;
 	}
 
-	rc = ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
-	                     multiplier);
-	if (rc < 0) {
-		err("Set packet size: Set FIFO size ret %d", rc);
+	PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt);
+
+	if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
+	                     mult) < 0)
 		return -ENOMEM;
-	}
 	
 	if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) {
 		err("Set packet size: set interface error");
@@ -519,6 +537,11 @@
 	if (ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0)
 		return -ENOMEM;
 
+	ov511->packet_size = size;
+
+	if (ov511_restart(ov511->dev) < 0)
+		return -EIO;
+
 	return 0;
 }
 
@@ -526,34 +549,44 @@
                                      struct video_picture *p)
 {
 	int ret;
+	struct usb_device *dev = ov511->dev;
 
-	/* Stop the camera */
-	if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) {
-		err("reset: command failed");
+	PDEBUG(4, "ov511_set_picture");
+
+	if (ov511_stop(dev) < 0)
 		return -EIO;
-	}
 
-	if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_COM_B)) < 0)
+	if((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0)
 		return -EIO;
 #if 0
-	if(ov511_i2c_write(ov511->dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
+	if(ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
 		return -EIO;
 #endif
+	if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE)
+		if(ov511_i2c_write(dev, OV7610_REG_SAT, p->colour >> 8) < 0)
+			return -EIO;
+
+	if (ov511->sensor == SEN_OV7610) {
+		if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+			return -EIO;
+
+		if(ov511_i2c_write(dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
+			return -EIO;
+	}		
+	else if ((ov511->sensor == SEN_OV7620) 
+	         || (ov511->sensor == SEN_OV7620AE)) {
+//		cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
+//		cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
+//	        // DEBUG_CODE
+//	        PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
+//	                                   ov511_i2c_read(dev, OV7610_REG_BRT)); 
+//
+//		if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+//			return -EIO;
+	}
 
-	if(ov511_i2c_write(ov511->dev, OV7610_REG_SAT, p->colour >> 8) < 0)
-		return -EIO;
-
-	if(ov511_i2c_write(ov511->dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
-		return -EIO;
-
-	if(ov511_i2c_write(ov511->dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
-		return -EIO;
-
-	/* Restart the camera */
-	if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x0) < 0) {
-		err("reset: command failed");
+	if (ov511_restart(dev) < 0)
 		return -EIO;
-	}
 
 	return 0;
 }
@@ -562,20 +595,20 @@
                                      struct video_picture *p)
 {
 	int ret;
+	struct usb_device *dev = ov511->dev;
 
-	/* Stop the camera */
-	if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) {
-		err("reset: command failed");
+	PDEBUG(4, "ov511_get_picture");
+
+	if (ov511_stop(dev) < 0)
 		return -EIO;
-	}
 
-	if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_SAT)) < 0) return -EIO;
+	if((ret = ov511_i2c_read(dev, OV7610_REG_SAT)) < 0) return -EIO;
 	p->colour = ret << 8;
 
-	if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_CNT)) < 0) return -EIO;
+	if((ret = ov511_i2c_read(dev, OV7610_REG_CNT)) < 0) return -EIO;
 	p->contrast = ret << 8;
 
-	if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_BRT)) < 0) return -EIO;
+	if((ret = ov511_i2c_read(dev, OV7610_REG_BRT)) < 0) return -EIO;
 	p->brightness = ret << 8;
 
 	p->hue = 0x8000;
@@ -583,11 +616,8 @@
 	p->depth = 3;  /* Don't know if this is right */
 	p->palette = VIDEO_PALETTE_RGB24;
 
-	/* Restart the camera */
-	if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x0) < 0) {
-		err("reset: command failed");
+	if (ov511_restart(dev) < 0)
 		return -EIO;
-	}
 
 	return 0;
 }
@@ -597,67 +627,93 @@
 {
 	int rc = 0;
 	struct usb_device *dev = ov511->dev;
+        int hwsbase = 0;
+        int hwebase = 0;
 
 	PDEBUG(3, "ov511_mode_init_regs(ov511, w:%d, h:%d, mode:%d, sub:%d)",
 	       width, height, mode, sub_flag);
 
-//	ov511_set_packet_size(ov511, 0);
-	if (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) {
-		err("reset: command failed");
+	if (ov511_stop(ov511->dev) < 0)
 		return -EIO;
-	}
 
 	if (mode == VIDEO_PALETTE_GREY) {
 		ov511_reg_write(dev, 0x16, 0x00);
-		ov511_i2c_write(dev, 0x0e, 0x44);
-		ov511_i2c_write(dev, 0x13, 0x21);
+		if (ov511->sensor == SEN_OV7610
+		    || ov511->sensor == SEN_OV7620AE) {
+			/* these aren't valid on the OV7620 */
+			ov511_i2c_write(dev, 0x0e, 0x44);
+		}
+		ov511_i2c_write(dev, 0x13, autoadjust ? 0x21 : 0x20);
 		/* For snapshot */
 		ov511_reg_write(dev, 0x1e, 0x00);
 		ov511_reg_write(dev, 0x1f, 0x01);
 	} else {
 		ov511_reg_write(dev, 0x16, 0x01);
-		ov511_i2c_write(dev, 0x0e, 0x04);
-		ov511_i2c_write(dev, 0x13, 0x01);
+	   	if (ov511->sensor == SEN_OV7610
+		    || ov511->sensor == SEN_OV7620AE) {
+		   /* not valid on the OV7620 */
+		   ov511_i2c_write(dev, 0x0e, 0x04);
+		}
+		ov511_i2c_write(dev, 0x13, autoadjust ? 0x01 : 0x00);
 		/* For snapshot */
 		ov511_reg_write(dev, 0x1e, 0x01);
 		ov511_reg_write(dev, 0x1f, 0x03);
 	}
 
+	/* The different sensor ICs handle setting up of window differently */
+        switch (ov511->sensor) {
+	 case SEN_OV7610:
+	 case SEN_OV7620AE:
+	   hwsbase = 0x38;
+	   hwebase = 0x3a; break;
+	 case SEN_OV7620:
+	   hwsbase = 0x2c;
+	   hwebase = 0x2d; break;
+	 default:
+	   hwsbase = 0;
+	   hwebase = 0; break;
+	}
+
 	if (width == 640 && height == 480) {
 		if (sub_flag) {
-			ov511_i2c_write(ov511->dev, 0x17, 0x38+(ov511->subx>>2));
-			ov511_i2c_write(ov511->dev, 0x18,
-					0x3a+((ov511->subx+ov511->subw)>>2));
-			ov511_i2c_write(ov511->dev, 0x19, 0x5+(ov511->suby>>1));
-			ov511_i2c_write(ov511->dev, 0x1a,
+			/* horizontal window start */
+			ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>2));
+			/* horizontal window end */
+			ov511_i2c_write(dev, 0x18,
+					hwebase+((ov511->subx+ov511->subw)>>2));
+			/* vertical window start */
+		   	ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1));
+			/* vertical window end */
+		    ov511_i2c_write(dev, 0x1a,
 					0x5+((ov511->suby+ov511->subh)>>1));
-			ov511_reg_write(ov511->dev, 0x12, (ov511->subw>>3)-1);
-			ov511_reg_write(ov511->dev, 0x13, (ov511->subh>>3)-1);
+			ov511_reg_write(dev, 0x12, (ov511->subw>>3)-1);
+			ov511_reg_write(dev, 0x13, (ov511->subh>>3)-1);
+			/* clock rate control */
 			ov511_i2c_write(dev, 0x11, 0x01);
 
 			/* Snapshot additions */
-			ov511_reg_write(ov511->dev, 0x1a, (ov511->subw>>3)-1);
-			ov511_reg_write(ov511->dev, 0x1b, (ov511->subh>>3)-1);
-			ov511_reg_write(ov511->dev, 0x1c, 0x00);
-			ov511_reg_write(ov511->dev, 0x1d, 0x00);
+			ov511_reg_write(dev, 0x1a, (ov511->subw>>3)-1);
+			ov511_reg_write(dev, 0x1b, (ov511->subh>>3)-1);
+			ov511_reg_write(dev, 0x1c, 0x00);
+			ov511_reg_write(dev, 0x1d, 0x00);
 		} else {
-			ov511_i2c_write(ov511->dev, 0x17, 0x38);
-			ov511_i2c_write(ov511->dev, 0x18, 0x3a + (640>>2));
-			ov511_i2c_write(ov511->dev, 0x19, 0x5);
-			ov511_i2c_write(ov511->dev, 0x1a, 5 + (480>>1));
+			ov511_i2c_write(dev, 0x17, hwsbase);
+			ov511_i2c_write(dev, 0x18, hwebase + (640>>2));
+			ov511_i2c_write(dev, 0x19, 0x5);
+			ov511_i2c_write(dev, 0x1a, 5 + (480>>1));
 			ov511_reg_write(dev, 0x12, 0x4f);
 			ov511_reg_write(dev, 0x13, 0x3d);
 
 			/* Snapshot additions */
-			ov511_reg_write(ov511->dev, 0x1a, 0x4f);
-			ov511_reg_write(ov511->dev, 0x1b, 0x3d);
-			ov511_reg_write(ov511->dev, 0x1c, 0x00);
-			ov511_reg_write(ov511->dev, 0x1d, 0x00);
+			ov511_reg_write(dev, 0x1a, 0x4f);
+			ov511_reg_write(dev, 0x1b, 0x3d);
+			ov511_reg_write(dev, 0x1c, 0x00);
+			ov511_reg_write(dev, 0x1d, 0x00);
 
 			if (mode == VIDEO_PALETTE_GREY) {
-			  ov511_i2c_write(dev, 0x11, 4); /* check */
+				ov511_i2c_write(dev, 0x11, 4); /* check */
 			} else {
-			  ov511_i2c_write(dev, 0x11, 6); /* check */
+				ov511_i2c_write(dev, 0x11, 6); /* check */
 			}
 		}
 
@@ -669,7 +725,10 @@
 
 		ov511_i2c_write(dev, 0x12, 0x24);
 		ov511_i2c_write(dev, 0x14, 0x04);
-		ov511_i2c_write(dev, 0x35, 0x9e);
+
+		/* 7620 doesn't have register 0x35, so play it safe */
+		if (ov511->sensor != SEN_OV7620)
+			ov511_i2c_write(dev, 0x35, 0x9e);
 	} else if (width == 320 && height == 240) {
 		ov511_reg_write(dev, 0x12, 0x27);
 		ov511_reg_write(dev, 0x13, 0x1f);
@@ -697,12 +756,8 @@
 		rc = -EINVAL;
 	}
 
-//	ov511_set_packet_size(ov511, 993);
-
-	if (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00) < 0) {
-		err("reset: command failed");
+	if (ov511_restart(ov511->dev) < 0)
 		return -EIO;
-	}
 
 	return rc;
 }
@@ -928,29 +983,30 @@
  *************************************************************/
 static void fixFrameRGBoffset(struct ov511_frame *frame)
 {
-  int x,y;
-  int rowBytes=frame->width*3,w=frame->width;
-  unsigned char *rgb=frame->data;
-  const int shift=1;//Distance to shift pixels by, vertically
+  int x, y;
+  int rowBytes = frame->width*3, w = frame->width;
+  unsigned char *rgb = frame->data;
+  const int shift = 1;   //Distance to shift pixels by, vertically
 
-  if (frame->width<400) 
-	   return;//Don't bother with little images
+  if (frame->width < 400) 
+	   return;     //Don't bother with little images
 
   //Shift red channel up
-  for (y=shift;y<frame->height;y++)
+  for (y = shift; y < frame->height; y++)
   {
-    int lp=(y-shift)*rowBytes;//Previous line offset
-    int lc=y*rowBytes;//Current line offset
-    for (x=0;x<w;x++)
-      rgb[lp+x*3+2]=rgb[lc+x*3+2];//Shift red up
+    int lp = (y-shift)*rowBytes;     //Previous line offset
+    int lc = y*rowBytes;             //Current line offset
+    for (x = 0; x < w; x++)
+      rgb[lp+x*3+2] = rgb[lc+x*3+2]; //Shift red up
   }
+
   //Shift blue channel down
-  for (y=frame->height-shift-1;y>=0;y--)
+  for (y=frame->height-shift-1; y >= 0; y--)
   {
-    int ln=(y+shift)*rowBytes;//Next line offset
-    int lc=y*rowBytes;//Current line offset
-    for (x=0;x<w;x++)
-      rgb[ln+x*3+0]=rgb[lc+x*3+0];//Shift blue down
+    int ln = (y+shift)*rowBytes;   //Next line offset
+    int lc = y*rowBytes;           //Current line offset
+    for (x = 0; x < w; x++)
+      rgb[ln+x*3+0] = rgb[lc+x*3+0]; //Shift blue down
   }
 }
 
@@ -962,6 +1018,8 @@
 	int aPackNum[10];
 	struct ov511_frame *frame;
 
+	PDEBUG(4, "ov511_move_data");
+
 	for (i = 0; i < urb->number_of_packets; i++) {
 		int n = urb->iso_frame_desc[i].actual_length;
 		int st = urb->iso_frame_desc[i].status;
@@ -969,7 +1027,7 @@
 		urb->iso_frame_desc[i].status = 0;
 		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
 
-		aPackNum[i] = n ? cdata[992] : -1;
+		aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1;
 
 		if (!n || ov511->curframe == -1) continue;
 
@@ -988,7 +1046,7 @@
 		    do_gettimeofday(ts);
 
 		    PDEBUG(4, "Frame End, curframe = %d, packnum=%d, hw=%d, vw=%d",
-			   ov511->curframe, (int)(cdata[992]),
+			   ov511->curframe, (int)(cdata[ov511->packet_size - 1]),
 			   (int)(cdata[9]), (int)(cdata[10]));
 
 		    if (frame->scanstate == STATE_LINES) {
@@ -1051,7 +1109,7 @@
 		 	}
 
 			/* Parse the segments */
-			while(iPix <= 992 - frame->segsize &&
+			while(iPix <= (ov511->packet_size - 1) - frame->segsize &&
 			      frame->segment < frame->width * frame->height / 256) {
 			  int iSegY;
 			  int iSegUV;
@@ -1099,7 +1157,7 @@
 
 			/* Save extra data for next time */
 			if (frame->segment < frame->width * frame->height / 256) {
-			  ov511->scratchlen = 992 - iPix;
+			  ov511->scratchlen = (ov511->packet_size - 1) - iPix;
 			  if (ov511->scratchlen < frame->segsize) {
 			    memmove(ov511->scratch, pData, ov511->scratchlen);
 			  } else {
@@ -1149,13 +1207,20 @@
 {
 	urb_t *urb;
 	int fx, err;
-	
+
+	PDEBUG(4, "ov511_init_isoc");
+
 	ov511->compress = 0;
 	ov511->curframe = -1;
 	ov511->cursbuf = 0;
 	ov511->scratchlen = 0;
 
-	ov511_set_packet_size(ov511, 993);
+	if (ov511->bridge == BRG_OV511)
+		ov511_set_packet_size(ov511, 993);
+	else if (ov511->bridge == BRG_OV511PLUS)
+		ov511_set_packet_size(ov511, 961);
+	else
+		err("invalid bridge type");
 
 	/* We double buffer the Iso lists */
 	urb = usb_alloc_urb(FRAMES_PER_DESC);
@@ -1172,10 +1237,10 @@
 	urb->transfer_buffer = ov511->sbuf[0].data;
  	urb->complete = ov511_isoc_irq;
  	urb->number_of_packets = FRAMES_PER_DESC;
- 	urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+ 	urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
  	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- 		urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
-		urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ 		urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+		urb->iso_frame_desc[fx].length = ov511->packet_size;
 	}
 
 	urb = usb_alloc_urb(FRAMES_PER_DESC);
@@ -1191,10 +1256,10 @@
 	urb->transfer_buffer = ov511->sbuf[1].data;
  	urb->complete = ov511_isoc_irq;
  	urb->number_of_packets = FRAMES_PER_DESC;
- 	urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+ 	urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
  	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- 		urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
-		urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ 		urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+		urb->iso_frame_desc[fx].length = ov511->packet_size;
 	}
 
 	ov511->sbuf[1].urb->next = ov511->sbuf[0].urb;
@@ -1215,6 +1280,7 @@
 
 static void ov511_stop_isoc(struct usb_ov511 *ov511)
 {
+	PDEBUG(4, "ov511_stop_isoc");
 	if (!ov511->streaming || !ov511->dev)
 		return;
 
@@ -1239,10 +1305,11 @@
 
 static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
 {
-#if 1
 	struct ov511_frame *frame;
 	int width, height;
 
+	PDEBUG(4, "ov511_new_frame");
+
 	if (!ov511->dev)
 		return -1;
 
@@ -1277,7 +1344,6 @@
 //	/* We want a fresh frame every 30 we get */
 //	ov511->compress = (ov511->compress + 1) % 30;
 
-#endif
 	return 0;
 }
 
@@ -1311,10 +1377,10 @@
 	PDEBUG(4, "frame [0] @ %p", ov511->frame[0].data);
 	PDEBUG(4, "frame [1] @ %p", ov511->frame[1].data);
 
-	ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+	ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
 	if (!ov511->sbuf[0].data)
 		goto open_err_on0;
-	ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+	ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
 	if (!ov511->sbuf[1].data)
 		goto open_err_on1;
 		
@@ -1835,9 +1901,11 @@
 	initialize:	ov511_init_done,
 };
 
-static int ov7610_configure(struct usb_device *dev)
+static int ov7610_configure(struct usb_ov511 *ov511)
 {
+	struct usb_device *dev = ov511->dev;
 	int tries;
+	int rc;
 
 	if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
 	                        OV7610_I2C_WRITE_ID) < 0)
@@ -1865,13 +1933,42 @@
 		--tries;
 	}
 	
-	if (tries == 0) {
-		err("Failed to read OV7610 ID. You might not have an OV7610,");
+	if (tries == 1) {
+		err("Failed to read sensor ID. You might not have an OV7610/20,");
 		err("or it may be not responding. Report this to");
 		err("mmcclelland@delphi.com");
 		return -1;
 	}
 
+	if (sensor == 0) {
+		rc = ov511_i2c_read(dev, OV7610_REG_COM_I);
+
+		if (rc < 0) {
+			err("Error detecting sensor type");
+			return -1;
+		}
+		else if((rc & 3) == 3) {
+			printk("ov511: Sensor is an OV7610\n");
+			ov511->sensor = SEN_OV7610;
+		}
+		else if((rc & 3) == 1) {
+			printk("ov511: Sensor is an OV7620AE\n");
+			ov511->sensor = SEN_OV7620AE;
+		}
+		else if((rc & 3) == 0) {
+			printk("ov511: Sensor is an OV7620\n");
+			ov511->sensor = SEN_OV7620;
+		}
+		else {
+			err("Unknown image sensor version: %d", rc & 3);
+			return -1;
+		}
+	}
+	else {  /* sensor != 0; user overrode detection */
+		ov511->sensor = sensor;
+		printk("ov511: Sensor set to type %d\n", ov511->sensor);
+	}
+
 	return 0;
 }
 
@@ -1890,9 +1987,9 @@
 	 {OV511_REG_BUS,  OV511_REG_SYSTEM_RESET, 0x3d},
 	 {OV511_DONE_BUS, 0x0, 0x00},
 	};
-	static struct ov511_regvals aRegvalsNorm[] =
-	{{OV511_REG_BUS, 0x20, 1},
-#if 1
+
+	static struct ov511_regvals aRegvalsNorm7610[] =
+	{{OV511_REG_BUS, 0x20, 0x01},
 	 {OV511_REG_BUS, 0x52, 0x02},
 	 {OV511_REG_BUS, 0x52, 0x00},
 	 {OV511_REG_BUS, 0x31, 0x1f}, /* 0f */
@@ -1907,16 +2004,14 @@
 	 {OV511_REG_BUS, 0x78, 0x06},
 	 {OV511_REG_BUS, 0x79, 0x03},
 
-
 	 {OV511_I2C_BUS, 0x10, 0xff},
 	 {OV511_I2C_BUS, 0x16, 0x06},
-	 {OV511_I2C_BUS, 0x28, 0x24}, /* 24 */
+	 {OV511_I2C_BUS, 0x28, 0x24},
 	 {OV511_I2C_BUS, 0x2b, 0xac},
 	 {OV511_I2C_BUS, 0x05, 0x00},
 	 {OV511_I2C_BUS, 0x06, 0x00},
 
 	 {OV511_I2C_BUS, 0x12, 0x00},
-//	 {OV511_I2C_BUS, 0x13, 0x00},
 	 {OV511_I2C_BUS, 0x38, 0x81},
 	 {OV511_I2C_BUS, 0x28, 0x24}, /* 0c */
 	 {OV511_I2C_BUS, 0x05, 0x00},
@@ -1931,26 +2026,64 @@
 	 {OV511_I2C_BUS, 0x29, 0x03}, /* 91 */
 	 {OV511_I2C_BUS, 0x2a, 0x04},
 	 {OV511_I2C_BUS, 0x2c, 0xfe},
-	 {OV511_I2C_BUS, 0x2d, 0x93}, /* d7 */
 	 {OV511_I2C_BUS, 0x30, 0x71},
 	 {OV511_I2C_BUS, 0x31, 0x60},
 	 {OV511_I2C_BUS, 0x32, 0x26},
 	 {OV511_I2C_BUS, 0x33, 0x20},
 	 {OV511_I2C_BUS, 0x34, 0x48},
 	 {OV511_I2C_BUS, 0x12, 0x24},
-//	 {OV511_I2C_BUS, 0x13, 0x01},
 	 {OV511_I2C_BUS, 0x11, 0x01},
 	 {OV511_I2C_BUS, 0x0c, 0x24},
 	 {OV511_I2C_BUS, 0x0d, 0x24},
-#endif
 	 {OV511_DONE_BUS, 0x0, 0x00},
 	};
 
-	/* Set altsetting 0 */
-	if (usb_set_interface(dev, ov511->iface, 0) < 0) {
-		err("usb_set_interface error");
-		return -EBUSY;
-	}
+	static struct ov511_regvals aRegvalsNorm7620[] =
+	{{OV511_REG_BUS, 0x20, 0x01},
+	 {OV511_REG_BUS, 0x52, 0x02},
+	 {OV511_REG_BUS, 0x52, 0x00},
+	 {OV511_REG_BUS, 0x31, 0x1f},
+	 {OV511_REG_BUS, 0x70, 0x3f},
+	 {OV511_REG_BUS, 0x71, 0x3f},
+	 {OV511_REG_BUS, 0x72, 0x01},
+	 {OV511_REG_BUS, 0x73, 0x01},
+	 {OV511_REG_BUS, 0x74, 0x01},
+	 {OV511_REG_BUS, 0x75, 0x01},
+	 {OV511_REG_BUS, 0x76, 0x01},
+	 {OV511_REG_BUS, 0x77, 0x01},
+	 {OV511_REG_BUS, 0x78, 0x06},
+	 {OV511_REG_BUS, 0x79, 0x03},
+
+	 {OV511_I2C_BUS, 0x10, 0xff},
+	 {OV511_I2C_BUS, 0x16, 0x06},
+	 {OV511_I2C_BUS, 0x28, 0x24},
+	 {OV511_I2C_BUS, 0x2b, 0xac},
+
+	 {OV511_I2C_BUS, 0x12, 0x00},
+
+	 {OV511_I2C_BUS, 0x28, 0x24},
+	 {OV511_I2C_BUS, 0x05, 0x00},
+	 {OV511_I2C_BUS, 0x0f, 0x05},
+	 {OV511_I2C_BUS, 0x15, 0x01},
+	 {OV511_I2C_BUS, 0x23, 0x00},
+	 {OV511_I2C_BUS, 0x24, 0x10},
+	 {OV511_I2C_BUS, 0x25, 0x8a},
+	 {OV511_I2C_BUS, 0x26, 0xa2},
+	 {OV511_I2C_BUS, 0x27, 0xe2},
+	 {OV511_I2C_BUS, 0x29, 0x03},
+	 {OV511_I2C_BUS, 0x2a, 0x00},
+	 {OV511_I2C_BUS, 0x2c, 0xfe},
+	 {OV511_I2C_BUS, 0x30, 0x71},
+	 {OV511_I2C_BUS, 0x31, 0x60},
+	 {OV511_I2C_BUS, 0x32, 0x26},
+	 {OV511_I2C_BUS, 0x33, 0x20},
+	 {OV511_I2C_BUS, 0x34, 0x48},
+	 {OV511_I2C_BUS, 0x12, 0x24},
+	 {OV511_I2C_BUS, 0x11, 0x01},
+	 {OV511_I2C_BUS, 0x0c, 0x24},
+	 {OV511_I2C_BUS, 0x0d, 0x24},
+	 {OV511_DONE_BUS, 0x0, 0x00},
+	};
 
 	memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template));
 
@@ -1966,18 +2099,17 @@
 	if ((rc = ov511_write_regvals(dev, aRegvalsInit)))
 		return rc;
 
-	if(ov7610_configure(dev) < 0) {
+	if(ov7610_configure(ov511) < 0) {
 		err("failed to configure OV7610");
  		goto error;	
 	}
 
+	ov511_set_packet_size(ov511, 0);
+
 	/* Disable compression */
-	if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) {
-		err("disable compression: command failed");
+	if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0)
 		goto error;
-	}
 
-	ov511->compress = 0;
 	ov511->snap_enabled = snapshot;	
 
 	/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
@@ -1990,15 +2122,27 @@
 	ov511->frame[1].bytes_read = 0;
 
 	/* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
-	if ((rc = ov511_write_regvals(dev, aRegvalsNorm))) goto error;
-	if ((rc = ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT,
-				       VIDEO_PALETTE_RGB24, 0)) < 0) goto error;
+
+	if (ov511->sensor == SEN_OV7620) {
+		if (ov511_write_regvals(dev, aRegvalsNorm7620)) goto error;
+	}
+	else {
+		if (ov511_write_regvals(dev, aRegvalsNorm7610)) goto error;
+	}
+
+	if (ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+				       VIDEO_PALETTE_RGB24, 0) < 0) goto error;
 
 	if (autoadjust) {
 		if (ov511_i2c_write(dev, 0x13, 0x01) < 0) goto error;
+		if (ov511_i2c_write(dev, 0x2d, 
+		     ov511->sensor==SEN_OV7620?0x91:0x93) < 0) goto error;
 	}
 	else {
-		if (ov511_i2c_write(dev, 0x13, 0x00) < 0 ) goto error;
+		if (ov511_i2c_write(dev, 0x13, 0x00) < 0) goto error;
+		if (ov511_i2c_write(dev, 0x2d, 
+		     ov511->sensor==SEN_OV7620?0x81:0x83) < 0) goto error;
+		ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8);
 	}
 
 	return 0;
@@ -2009,6 +2153,7 @@
 		&dev->actconfig->interface[ov511->iface]);
 
 	kfree(ov511);
+	ov511 = NULL;
 
 	return -EBUSY;	
 }
@@ -2027,10 +2172,11 @@
 
 	interface = &dev->actconfig->interface[ifnum].altsetting[0];
 
-	/* Is it an OV511? */
+	/* Is it an OV511/OV511+? */
 	if (dev->descriptor.idVendor != 0x05a9)
 		return NULL;
-	if (dev->descriptor.idProduct != 0x0511)
+	if (dev->descriptor.idProduct != 0x0511
+	 && dev->descriptor.idProduct != 0xA511)
 		return NULL;
 
 	/* Checking vendor/product should be enough, but what the hell */
@@ -2039,9 +2185,6 @@
 	if (interface->bInterfaceSubClass != 0x00)
 		return NULL;
 
-	/* We found one */
-	printk(KERN_INFO "ov511: USB OV511-based camera found\n");
-
 	if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) {
 		err("couldn't kmalloc ov511 struct");
 		return NULL;
@@ -2052,15 +2195,24 @@
 	ov511->dev = dev;
 	ov511->iface = interface->bInterfaceNumber;
 
+	if (dev->descriptor.idProduct == 0x0511) {
+		info("USB OV511 camera found");
+		ov511->bridge = BRG_OV511;
+	}
+	else if (dev->descriptor.idProduct == 0xA511) {
+		info("USB OV511+ camera found");
+		ov511->bridge = BRG_OV511PLUS;
+	}
+
 	rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
 	if (rc < 0) {
 		err("Unable to read camera bridge registers");
-		return NULL;
+		goto error;
 	}
 	
 	switch(ov511->customid = rc) {
 	case 0: /* This also means that no custom ID was set */
-		printk("ov511: Camera is probably a MediaForte MV300\n");
+		printk("ov511: Camera is a generic model (no ID)\n");
 		break;
 	case 3:
 		printk("ov511: Camera is a D-Link DSB-C300\n");
@@ -2077,6 +2229,11 @@
 	case 36:
 		printk("ov511: Camera is a Koala-Cam\n");
 		break;
+	case 38:
+		printk("ov511: Camera is a Lifeview USB Life TV\n");
+		printk("ov511: This device is not supported, exiting...\n");
+		goto error;
+		break;
 	case 100:
 		printk("ov511: Camera is a Lifeview RoboCam\n");
 		break;
@@ -2090,9 +2247,13 @@
 		err("Specific camera type (%d) not recognized", rc);
 		err("Please contact mmcclelland@delphi.com to request");
 		err("support for your camera.");
-		return NULL;
 	}
 
+//	if (ov511->bridge == BRG_OV511PLUS) {
+//		err("Sorry, the OV511+ chip is not supported yet");
+//		goto error;
+//	}
+
 	if (!ov511_configure(ov511)) {
 		ov511->user=0;
 		init_MUTEX(&ov511->lock);	/* to 1 == available */
@@ -2100,10 +2261,18 @@
 	}
 	else {
 		err("Failed to configure camera");
-		return NULL;
+		goto error;
 	}
     	
      	return ov511;
+
+error:
+	if (ov511) {
+		kfree(ov511);
+		ov511 = NULL;
+	}
+
+	return NULL;	
 }
 
 static void ov511_disconnect(struct usb_device *dev, void *ptr)
@@ -2147,7 +2316,7 @@
 		usb_unlink_urb(ov511->sbuf[0].urb);
 		usb_free_urb(ov511->sbuf[0].urb);
 		ov511->sbuf[0].urb = NULL;
-	}	
+	}
 
 	/* Free the memory */
 	if (!ov511->user) {
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/ov511.h linux/drivers/usb/ov511.h
--- v2.3.99-pre3/linux/drivers/usb/ov511.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/usb/ov511.h	Mon Mar 27 09:44:58 2000
@@ -1,8 +1,6 @@
 #ifndef __LINUX_OV511_H
 #define __LINUX_OV511_H
 
-//#include <linux/list.h>
-
 #define OV511_DEBUG	/* Turn on debug messages */
 
 #ifdef OV511_DEBUG
@@ -75,14 +73,16 @@
 #define OV511_REG_SYSTEM_CLOCK_DIVISOR		0x51
 #define OV511_REG_SYSTEM_SNAPSHOT			0x52
 #define OV511_REG_SYSTEM_INIT         		0x53
+#define OV511_REG_SYSTEM_PWR_CLK      		0x54    /* OV511+ only */
+#define OV511_REG_SYSTEM_LED_CTL      		0x55    /* OV511+ only */
 #define OV511_REG_SYSTEM_USER_DEFINED		0x5E
 #define OV511_REG_SYSTEM_CUSTOM_ID			0x5F
 
 /* OmniCE register numbers */
-#define OV511_OMNICE_PREDICATION_HORIZ_Y	0x70
-#define OV511_OMNICE_PREDICATION_HORIZ_UV	0x71
-#define OV511_OMNICE_PREDICATION_VERT_Y		0x72
-#define OV511_OMNICE_PREDICATION_VERT_UV	0x73
+#define OV511_OMNICE_PREDICTION_HORIZ_Y	0x70
+#define OV511_OMNICE_PREDICTION_HORIZ_UV	0x71
+#define OV511_OMNICE_PREDICTION_VERT_Y		0x72
+#define OV511_OMNICE_PREDICTION_VERT_UV	0x73
 #define OV511_OMNICE_QUANTIZATION_HORIZ_Y	0x74
 #define OV511_OMNICE_QUANTIZATION_HORIZ_UV	0x75
 #define OV511_OMNICE_QUANTIZATION_VERT_Y	0x76
@@ -94,15 +94,25 @@
 #define OV511_OMNICE_UV_LUT_BEGIN			0xA0
 #define OV511_OMNICE_UV_LUT_END				0xBF
 
-/* Alternate numbers for various max packet sizes */
-#define OV511_ALTERNATE_SIZE_992	0
-#define OV511_ALTERNATE_SIZE_993	1
-#define OV511_ALTERNATE_SIZE_768	2
-#define OV511_ALTERNATE_SIZE_769	3
-#define OV511_ALTERNATE_SIZE_512	4
-#define OV511_ALTERNATE_SIZE_513	5
-#define OV511_ALTERNATE_SIZE_257	6
-#define OV511_ALTERNATE_SIZE_0		7
+/* Alternate numbers for various max packet sizes (OV511 only) */
+#define OV511_ALT_SIZE_992	0
+#define OV511_ALT_SIZE_993	1
+#define OV511_ALT_SIZE_768	2
+#define OV511_ALT_SIZE_769	3
+#define OV511_ALT_SIZE_512	4
+#define OV511_ALT_SIZE_513	5
+#define OV511_ALT_SIZE_257	6
+#define OV511_ALT_SIZE_0	7
+
+/* Alternate numbers for various max packet sizes (OV511+ only) */
+#define OV511PLUS_ALT_SIZE_0	0
+#define OV511PLUS_ALT_SIZE_33	1
+#define OV511PLUS_ALT_SIZE_129	2
+#define OV511PLUS_ALT_SIZE_257	3
+#define OV511PLUS_ALT_SIZE_385	4
+#define OV511PLUS_ALT_SIZE_513	5
+#define OV511PLUS_ALT_SIZE_769	6
+#define OV511PLUS_ALT_SIZE_961	7
 
 /* ov7610 registers */
 #define OV7610_REG_GAIN          0x00
@@ -154,7 +164,8 @@
 #define SCRATCH_BUF_SIZE 384
 
 #define FRAMES_PER_DESC		10  /* FIXME - What should this be? */
-#define FRAME_SIZE_PER_DESC	993	/* FIXME - Shouldn't be hardcoded */
+#define FRAME_SIZE_PER_DESC	993	/* FIXME - Deprecated */
+#define MAX_FRAME_SIZE_PER_DESC	993  /* For statically allocated stuff */
 
 // FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
 #define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */
@@ -171,6 +182,19 @@
                         unsigned char reg,
                         unsigned char value);
 
+/* Bridge types */
+enum {
+	BRG_OV511,
+	BRG_OV511PLUS,
+};
+
+/* Sensor types */
+enum {
+	SEN_UNKNOWN,
+	SEN_OV7610,
+	SEN_OV7620,
+	SEN_OV7620AE,
+};
 
 enum {
 	STATE_SCANNING,		/* Scanning for start */
@@ -214,7 +238,7 @@
 	int hdrheight;		/* Height */
 
 	int sub_flag;		/* Sub-capture mode for this frame? */
-	int format;		/* Format for this frame */
+	int format;			/* Format for this frame */
 	int segsize;		/* How big is each segment from the camera? */
 
 	volatile int grabstate;	/* State of grabbing */
@@ -274,6 +298,11 @@
 	wait_queue_head_t wq;	/* Processes waiting */
 
 	int snap_enabled;   /* Snapshot mode enabled */
+	
+	int bridge;         /* Type of bridge (OV511 or OV511+) */
+	int sensor;         /* Type of image sensor chip */
+
+	int packet_size;    /* Frame size per isoc desc */
 };
 
 #endif
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
--- v2.3.99-pre3/linux/drivers/usb/pegasus.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/pegasus.c	Tue Apr 11 09:57:43 2000
@@ -16,11 +16,13 @@
 #include <linux/usb.h>
 
 
-static const char *version = __FILE__ ": v0.3.5 2000/03/21 Written by Petko Manolov (petkan@spct.net)\n";
+static const char *version = __FILE__ ": v0.3.9 2000/04/11 Written by Petko Manolov (petkan@spct.net)\n";
 
 
 #define	PEGASUS_MTU		1500
-#define PEGASUS_MAX_MTU		1536
+#define	PEGASUS_MAX_MTU		1536
+#define	SROM_WRITE		0x01
+#define	SROM_READ		0x02
 #define	PEGASUS_TX_TIMEOUT	(HZ*5)
 #define	ALIGN(x)		x __attribute__((aligned(16)))
 
@@ -51,12 +53,18 @@
 
 
 static struct usb_eth_dev usb_dev_id[] = {
-	{ "D-Link DSB-650TX", 0x2001, 0x4001, NULL },
-	{ "Linksys USB100TX", 0x066b, 0x2203, NULL },
-	{ "SMC 202 USB Ethernet", 0x0707, 0x0200, NULL },
-	{ "ADMtek AN986 (Pegasus) USB Ethernet", 0x07a6, 0x0986, NULL },
-	{ "Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL },
-	{ NULL, 0, 0, NULL }
+	{"Billionton USB-100", 0x08dd, 0x0986, NULL},
+	{"Corega FEter USB-TX", 0x7aa, 0x0004, NULL},
+	{"MELCO/BUFFALO LUA-TX", 0x0411, 0x0001, NULL},
+	{"D-Link DSB-650TX", 0x2001, 0x4001, NULL},
+	{"D-Link DSB-650TX", 0x2001, 0x4002, NULL},
+	{"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, NULL},
+	{"Linksys USB100TX", 0x066b, 0x2203, NULL},
+	{"Linksys USB100TX", 0x066b, 0x2204, NULL},
+	{"SMC 202 USB Ethernet", 0x0707, 0x0200, NULL},
+	{"ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986, NULL},
+	{"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL},
+	{NULL, 0, 0, NULL}
 };
 
 
@@ -105,10 +113,10 @@
 	return 1;
 }
 
-static int pegasus_read_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata)
+static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction)
 {
 	int i;
-	__u8 data[4] = { index, 0, 0, 0x02 };
+	__u8 data[4] = { index, 0, 0, direction };
 
 	pegasus_set_registers(dev, 0x20, 4, data);
 	for (i = 0; i < 100; i++) {
@@ -120,7 +128,7 @@
 		}
 	}
 
-	warn("read_srom_word() failed");
+	warn("pegasus_rw_srom_word() failed");
 	return 1;
 }
 
@@ -128,7 +136,7 @@
 {
 	int i;
 	for (i = 0; i < 3; i++)
-		if (pegasus_read_srom_word(dev, i, (__u16 *)&id[i * 2]))
+		if (pegasus_rw_srom_word(dev,i,(__u16 *)&id[i * 2],SROM_READ))
 			return 1;
 	return 0;
 }
@@ -170,8 +178,9 @@
 		return 2;
 
 	if ((~temp & 4) && !loopback) {
-		err("link NOT established - %x", temp);
-		return 3;
+		warn("%s: link NOT established (0x%x), check the cable.",
+			dev->name, temp);
+		/* return 3; FIXME */
 	}
 
 	if (pegasus_read_phy_word(usb, 5, &partmedia))
@@ -376,13 +385,14 @@
 
 	if (net->flags & IFF_PROMISC) {
 		info("%s: Promiscuous mode enabled", net->name);
-		pegasus_set_register(pegasus->usb, 2, 0x04);
+/*		pegasus_set_register(pegasus->usb, 2, 0x04); FIXME */
 	} else if ((net->mc_count > multicast_filter_limit) ||
 			(net->flags & IFF_ALLMULTI)) {
 		pegasus_set_register(pegasus->usb, 0, 0xfa);
 		pegasus_set_register(pegasus->usb, 2, 0);
+		info("%s set allmulti", net->name);
 	} else {
-		dbg("%s: set Rx mode", net->name);
+		info("%s: set Rx mode", net->name);
 	}
 
 	netif_wake_queue(net);
@@ -395,18 +405,19 @@
 	while ( usb_dev_id[i].name ) {
 		if ( (usb_dev_id[i].vendor == vendor) && 
 			(usb_dev_id[i].device == product) )
-			return 0;
+			return i;
 		i++;
 	}
-	return	1;
+	return	-1;
 }
 
 static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	struct net_device *net;
 	struct pegasus *pegasus;
+	int	dev_indx;
 
-	if ( check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct) ) {
+	if ( (dev_indx = check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct)) == -1 ) {
 		return NULL;
 	}
 
@@ -449,11 +460,11 @@
 	FILL_BULK_URB(&pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2),
 			pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk,
 			pegasus);
-	FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 0),
+	FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3),
 			pegasus->intr_buff, 8, pegasus_irq, pegasus, 250);
 
 
-	printk(KERN_INFO "%s: ADMtek AN986 Pegasus usb device\n", net->name);
+	printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name);
 
 	return pegasus;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.99-pre3/linux/drivers/usb/printer.c	Fri Mar 10 16:40:45 2000
+++ linux/drivers/usb/printer.c	Wed Apr  5 16:58:38 2000
@@ -160,10 +160,13 @@
 	if (usblp->used)
 		return -EBUSY;
 
-	if ((retval = usblp_check_status(usblp)))
+	MOD_INC_USE_COUNT;
+
+	if ((retval = usblp_check_status(usblp))) {
+		MOD_DEC_USE_COUNT;
 		return retval;
+	}
 
-	MOD_INC_USE_COUNT;
 	usblp->used = 1;
 	file->private_data = usblp;
 
@@ -179,17 +182,18 @@
 {
 	struct usblp *usblp = file->private_data;
 
-	MOD_DEC_USE_COUNT;
 	usblp->used = 0;
 			
 	if (usblp->dev) {
         	usb_unlink_urb(&usblp->readurb);
         	usb_unlink_urb(&usblp->writeurb);
+		MOD_DEC_USE_COUNT;
 		return 0;
 	}
 
 	usblp_table[usblp->minor] = NULL;
 	kfree(usblp);
+	MOD_DEC_USE_COUNT;
 
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.3.99-pre3/linux/drivers/usb/scanner.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/usb/scanner.c	Mon Mar 27 09:44:58 2000
@@ -1,7 +1,7 @@
 /* -*- linux-c -*- */
 
 /* 
- * Driver for USB Scanners (linux-2.3.42)
+ * Driver for USB Scanners (linux-2.3.99-pre3-7)
  *
  * Copyright (C) 1999, 2000 David E. Nelson
  *
@@ -148,8 +148,29 @@
  *    - Increased the timeout parameter in read_scanner() to 120 Secs.
  *
  *
+ *  0.4.2  3/23/2000
+ *
+ *    - Added Umax 1236U ID.  Thanks to Philipp Baer <ph_baer@npw.net>.
+ *    - Added Primax, ReadyScan, Visioneer, Colorado, and Genius ID's.
+ *      Thanks to Adrian Perez Jorge <adrianpj@easynews.com>.
+ *    - Fixed error number reported for non-existant devices.  Thanks to
+ *      Spyridon Papadimitriou <Spyridon_Papadimitriou@gs91.sp.cs.cmu.edu>.
+ *    - Added Acer Prisascan 620U ID's.  Thanks to Joao <joey@knoware.nl>.
+ *    - Replaced __initcall() with module_init()/module_exit(). Updates
+ *      from patch-2.3.48.
+ *    - Replaced file_operations structure with new syntax.  Updates
+ *      from patch-2.3.49.
+ *    - Changed #include "usb.h" to #include <linux/usb.h>
+ *    - Added #define SCN_IOCTL to exclude development areas 
+ *      since 2.4.x is about to be released. This mainly affects the 
+ *      ioctl() stuff.  See scanner.h for more details.
+ *    - Changed the return value for signal_pending() from -ERESTARTSYS to
+ *      -EINTR.
+ *
+ *
  *  TODO
  *
+ *    - Performance
  *    - Select/poll methods
  *    - More testing
  *    - Proper registry/assignment for LM9830 ioctl's
@@ -214,7 +235,7 @@
 
 	if (!p_scn_table[scn_minor]) {
 		err("open_scanner(%d): invalid scn_minor", scn_minor);
-		return -ENOIOCTLCMD;
+		return -ENODEV;
 	}
 
 	scn = p_scn_table[scn_minor];
@@ -255,7 +276,7 @@
 
 	if (!p_scn_table[scn_minor]) {
 		err("close_scanner(%d): invalid scn_minor", scn_minor);
-		return -ENOIOCTLCMD;
+		return -ENODEV;
 	}
 
 	scn = p_scn_table[scn_minor];
@@ -279,6 +300,8 @@
 	ssize_t bytes_written = 0; /* Overall count of bytes written */
 	ssize_t ret = 0;
 
+	kdev_t scn_minor;
+
 	int this_write;		/* Number of bytes to write */
 	int partial;		/* Number of bytes successfully written */
 	int result = 0;
@@ -287,6 +310,8 @@
 
 	scn = file->private_data;
 
+	scn_minor = scn->scn_minor;
+
 	obuf = scn->obuf;
 
 	dev = scn->scn_dev;
@@ -294,7 +319,7 @@
 	while (count > 0) {
 
 		if (signal_pending(current)) {
-			ret = -ERESTARTSYS;
+			ret = -EINTR;
 			break;
 		}
 
@@ -306,14 +331,14 @@
 		}
 
 		result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
-		dbg("write stats(%d): result:%d this_write:%d partial:%d", scn->scn_minor, result, this_write, partial);
+		dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
 
 		if (result == USB_ST_TIMEOUT) {	/* NAK -- shouldn't happen */
 			warn("write_scanner: NAK recieved.");
 			ret = -ETIME;
 			break;
 		} else if (result < 0) { /* We should not get any I/O errors */
-			warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn->scn_minor, result);
+			warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn_minor, result);
 			ret = -EIO;
 			break;
 		} 
@@ -322,7 +347,7 @@
 		if (partial) {
 			unsigned char cnt, cnt_max;
 			cnt_max = (partial > 24) ? 24 : partial;
-			printk(KERN_DEBUG "dump(%d): ", scn->scn_minor);
+			printk(KERN_DEBUG "dump(%d): ", scn_minor);
 			for (cnt=0; cnt < cnt_max; cnt++) {
 				printk("%X ", obuf[cnt]);
 			}
@@ -355,8 +380,10 @@
 	struct scn_usb_data *scn;
 	struct usb_device *dev;
 
-	ssize_t bytes_read = 0;	/* Overall count of bytes_read */
-	ssize_t ret = 0;
+	ssize_t bytes_read;	/* Overall count of bytes_read */
+	ssize_t ret;
+
+	kdev_t scn_minor;
 
 	int partial;		/* Number of bytes successfully read */
 	int this_read;		/* Max number of bytes to read */
@@ -366,29 +393,32 @@
 
 	scn = file->private_data;
 
+	scn_minor = scn->scn_minor;
+
 	ibuf = scn->ibuf;
 
 	dev = scn->scn_dev;
 
 	bytes_read = 0;
+	ret = 0;
 
 	while (count) {
 		if (signal_pending(current)) {
-			ret = -ERESTARTSYS;
+			ret = -EINTR;
 			break;
 		}
 
 		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
 		
 		result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, 120*HZ);
-		dbg("read stats(%d): result:%d this_read:%d partial:%d", scn->scn_minor, result, this_read, partial);
+		dbg("read stats(%d): result:%d this_read:%d partial:%d", scn_minor, result, this_read, partial);
 
 		if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */
-			warn("read_scanner(%d): NAK received", scn->scn_minor);
+			warn("read_scanner(%d): NAK received", scn_minor);
 			ret = -ETIME;
 			break;
 		} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
-			warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn->scn_minor, (int)result);
+			warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result);
 			ret = -EIO;
 			break;
 		}
@@ -397,7 +427,7 @@
 		if (partial) {
 			unsigned char cnt, cnt_max;
 			cnt_max = (partial > 24) ? 24 : partial;
-			printk(KERN_DEBUG "dump(%d): ", scn->scn_minor);
+			printk(KERN_DEBUG "dump(%d): ", scn_minor);
 			for (cnt=0; cnt < cnt_max; cnt++) {
 				printk("%X ", ibuf[cnt]);
 			}
@@ -492,15 +522,17 @@
 		
 		if (dev->descriptor.idVendor == 0x1606) {          /* Umax */
 			if (dev->descriptor.idProduct == 0x0010 || /* Astra 1220U */
-			    dev->descriptor.idProduct == 0x0030) { /* Astra 2000U */
+			    dev->descriptor.idProduct == 0x0030 || /* Astra 2000U */
+			    dev->descriptor.idProduct == 0x0002) { /* Astra 1236U */
 				valid_device = 1;
 				break;
 			}
 		}
 		
 		if (dev->descriptor.idVendor == 0x04b8)	{          /* Seiko/Epson Corp. */
-			if (dev->descriptor.idProduct == 0x0101 || /* Perfection 636 */
-			    dev->descriptor.idProduct == 0x0104) { /* Perfection 1200U */
+			if (dev->descriptor.idProduct == 0x0101 || /* Perfection 636U and 636Photo */
+			    dev->descriptor.idProduct == 0x0103 || /* Perfection 610 */
+			    dev->descriptor.idProduct == 0x0104) { /* Perfection 1200U and 1200Photo */
 				valid_device = 1;
 				break;
 			}
@@ -526,15 +558,56 @@
 			}
 		}
 
+		if (dev->descriptor.idVendor == 0x0461) {          /* Primax/Colorado */
+			if (dev->descriptor.idProduct == 0x0300 || /* G2-300 #1 */
+			    dev->descriptor.idProduct == 0x0380 || /* G2-600 #1 */
+			    dev->descriptor.idProduct == 0x0301 || /* G2E-300 */
+			    dev->descriptor.idProduct == 0x0381 || /* ReadyScan 636i */
+			    dev->descriptor.idProduct == 0x0302 || /* G2-300 #2 */
+			    dev->descriptor.idProduct == 0x0382 || /* G2-600 #2 */
+			    dev->descriptor.idProduct == 0x0303 || /* G2E-300 */
+			    dev->descriptor.idProduct == 0x0383 || /* G2E-600 */
+			    dev->descriptor.idProduct == 0x0340 || /* Colorado USB 9600 */
+			    dev->descriptor.idProduct == 0x0360 || /* Colorado USB 19200 */
+			    dev->descriptor.idProduct == 0x0341 || /* Colorado 600u */
+			    dev->descriptor.idProduct == 0x0361) { /* Colorado 1200u */
+				valid_device = 1;
+				break;
+			}
+		}
+		
+		if (dev->descriptor.idVendor == 0x04a7) {          /* Visioneer */
+			if (dev->descriptor.idProduct == 0x0221 || /* OneTouch 5300 */
+			    dev->descriptor.idProduct == 0x0221 || /* OneTouch 7600 */
+			    dev->descriptor.idProduct == 0x0231) { /* 6100 */
+				valid_device = 1;
+				break;
+			}
+		}
+		
+		if (dev->descriptor.idVendor == 0x0458) {          /* Genius */
+			if(dev->descriptor.idProduct == 0x2001) { /* ColorPage-Vivid Pro */
+				valid_device = 1;
+				break;
+			}
+		}
+		
+		if (dev->descriptor.idVendor == 0x04a5) {          /* Acer */
+			if(dev->descriptor.idProduct == 0x2060) { /* Prisa Acerscan 620U */
+				valid_device = 1;
+				break;
+			}
+		}
+		
 		if (dev->descriptor.idVendor == vendor &&   /* User specified */
 		    dev->descriptor.idProduct == product) { /* User specified */
 			valid_device = 1;
 			break;
 		}
-
-
+		
+		
 	} while (0);
-
+	
 	if (!valid_device)	
 		return NULL;	/* We didn't find anything pleasing */
 
@@ -714,6 +787,7 @@
 	kfree (scn);
 }
 
+#ifdef SCN_IOCTL
 static int
 ioctl_scanner(struct inode *inode, struct file *file,
 	      unsigned int cmd, unsigned long arg)
@@ -728,7 +802,7 @@
 
 	if (!p_scn_table[scn_minor]) {
 		err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
-		return -ENOIOCTLCMD;
+		return -ENODEV;
 	}
 
 	dev = p_scn_table[scn_minor]->scn_dev;
@@ -790,12 +864,15 @@
 	}
 	return 0;
 }
+#endif /* SCN_IOCTL */
 
 static struct
 file_operations usb_scanner_fops = {
 	read:		read_scanner,
 	write:		write_scanner,
+#ifdef SCN_IOCTL
 	ioctl:		ioctl_scanner,
+#endif /* SCN_IOCTL */
 	open:		open_scanner,
 	release:	close_scanner,
 };
@@ -810,12 +887,14 @@
        SCN_BASE_MNR
 };
 
-void __exit usb_scanner_exit(void)
+void __exit
+usb_scanner_exit(void)
 {
 	usb_deregister(&scanner_driver);
 }
 
-int __init usb_scanner_init(void)
+int __init
+usb_scanner_init (void)
 {
         if (usb_register(&scanner_driver) < 0)
                 return -1;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h
--- v2.3.99-pre3/linux/drivers/usb/scanner.h	Fri Mar 10 16:40:45 2000
+++ linux/drivers/usb/scanner.h	Mon Mar 27 09:44:58 2000
@@ -6,8 +6,15 @@
 #include <linux/malloc.h>
 #include <linux/delay.h>
 #include <linux/ioctl.h>
+
 // #define DEBUG
+
+/* Enable to activate the ioctl interface.  This is mainly meant for */
+/* development purposes until an ioctl number is officially registered */
+// #define SCN_IOCTL
+
 #include <linux/usb.h>
+// #include "usb.h"
 
 /* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
 // #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile
--- v2.3.99-pre3/linux/drivers/usb/serial/Makefile	Sun Mar 19 18:35:31 2000
+++ linux/drivers/usb/serial/Makefile	Mon Mar 27 14:25:28 2000
@@ -1,67 +1,11 @@
 #
-# Makefile for the kernel USB device drivers.
+# Makefile for the USB serial device drivers.
 #
 
-# Subdirs.
-
-SUB_DIRS	:=
-MOD_SUB_DIRS	:= $(SUB_DIRS)
-MOD_IN_SUB_DIRS	:= $(SUB_DIRS)
-ALL_SUB_DIRS	:= $(SUB_DIRS)
-
-# The target object and module list name.
-
-O_TARGET	:= serial.o
+O_TARGET	:= usb-serial.o
 M_OBJS		:= usb-serial.o
-O_OBJS		:= usb-serial.o
+O_OBJS		:= usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o
 MOD_LIST_NAME	:= USB_SERIAL_MODULES
 
-# Objects that export symbols.
-
-# Multipart objects.
-
-# Optional parts of multipart objects.
-
-# Object file lists.
-
-obj-y	:=
-obj-m	:=
-obj-n	:=
-obj-	:=
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_USB_SERIAL)	+= usb-serial.o
-
-# Extract lists of the multi-part drivers.
-# The 'int-*' lists are the intermediate files used to build the multi's.
-
-multi-y		:= $(filter $(list-multi), $(obj-y))
-multi-m		:= $(filter $(list-multi), $(obj-m))
-int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
-int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
-
-# Files that are both resident and modular: remove from modular.
-
-obj-m		:= $(filter-out $(obj-y), $(obj-m))
-int-m		:= $(filter-out $(int-y), $(int-m))
-
-# Take multi-part drivers out of obj-y and put components in.
-
-obj-y		:= $(filter-out $(list-multi), $(obj-y)) $(int-y)
-
-# Translate to Rules.make lists.
-
-O_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-y)))
-OX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-y)))
-M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
-MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
-MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
-
-# The global Rules.make.
-
 include $(TOPDIR)/Rules.make
-
-# Link rules for multi-part drivers.
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/ezusb_convert.pl linux/drivers/usb/serial/ezusb_convert.pl
--- v2.3.99-pre3/linux/drivers/usb/serial/ezusb_convert.pl	Fri Mar 10 16:40:45 2000
+++ linux/drivers/usb/serial/ezusb_convert.pl	Mon Apr 10 22:54:09 2000
@@ -27,6 +27,8 @@
     push(@records, [$addr, \@bytes]);
 }
 
+@sorted_records = sort { $a->[0] <=> $b->[0] } @records;
+
 print <<"EOF";
 /*
  * ${basename}_fw.h
@@ -39,7 +41,7 @@
 EOF
 
 print "static const struct ezusb_hex_record ${basename}_firmware[] = {\n";
-foreach $r (@records) {
+foreach $r (@sorted_records) {
     printf("{ 0x%04x,\t%d,\t{", $r->[0], scalar(@{$r->[1]}));
     print join(", ", map {sprintf('0x%02x', $_);} @{$r->[1]});
     print "} },\n";
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- v2.3.99-pre3/linux/drivers/usb/serial/ftdi_sio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/ftdi_sio.c	Wed Apr  5 16:58:38 2000
@@ -0,0 +1,728 @@
+/*
+ * USB FTDI SIO driver
+ *
+ * 	(C) Copyright (C) 1999, 2000
+ * 	    Greg Kroah-Hartman (greg@kroah.com)
+ *          Bill Ryder (bryder@sgi.com)
+ *
+ * 	This program is free software; you can redistribute it and/or modify
+ * 	it under the terms of the GNU General Public License as published by
+ * 	the Free Software Foundation; either version 2 of the License, or
+ * 	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (04/04/2000) Bill Ryder 
+ *         Fixed bugs in TCGET/TCSET ioctls (by removing them - they are 
+ *             handled elsewhere in the serial driver chain).
+ *
+ * (03/30/2000) Bill Ryder 
+ *         Implemented lots of ioctls
+ * 	Fixed a race condition in write
+ * 	Changed some dbg's to errs
+ *
+ * (03/26/2000) gkh
+ * 	Split driver up into device specific pieces.
+ *
+ */
+
+/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
+/* Thanx to FTDI for so kindly providing details of the protocol required */
+/*   to talk to the device */
+
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_FTDI_SIO
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#include "ftdi_sio.h"
+
+#define FTDI_VENDOR_ID			0x0403
+#define FTDI_SIO_SERIAL_CONVERTER_ID	0x8372
+
+/* function prototypes for a FTDI serial converter */
+static int  ftdi_sio_startup		(struct usb_serial *serial);
+static int  ftdi_sio_open		(struct usb_serial_port *port, struct file *filp);
+static void ftdi_sio_close		(struct usb_serial_port *port, struct file *filp);
+static int  ftdi_sio_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static void ftdi_sio_write_bulk_callback (struct urb *urb);
+static void ftdi_sio_read_bulk_callback	(struct urb *urb);
+static void ftdi_sio_set_termios	(struct usb_serial_port *port, struct termios * old);
+static int  ftdi_sio_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+
+/* All of the device info needed for the FTDI SIO serial converter */
+static __u16	ftdi_vendor_id		= FTDI_VENDOR_ID;
+static __u16	ftdi_sio_product_id	= FTDI_SIO_SERIAL_CONVERTER_ID;
+struct usb_serial_device_type ftdi_sio_device = {
+	name:			"FTDI SIO",
+	idVendor:		&ftdi_vendor_id,	/* the FTDI vendor ID */
+	idProduct:		&ftdi_sio_product_id,	/* the FTDI SIO product id */
+	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
+	num_interrupt_in:	0,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			ftdi_sio_open,
+	close:			ftdi_sio_close,
+	write:			ftdi_sio_write,
+	read_bulk_callback:	ftdi_sio_read_bulk_callback,
+	write_bulk_callback:	ftdi_sio_write_bulk_callback,
+	ioctl:			ftdi_sio_ioctl,
+	set_termios:		ftdi_sio_set_termios,
+	startup:		ftdi_sio_startup,
+};
+
+
+/*
+ * ***************************************************************************
+ * FTDI SIO Serial Converter specific driver functions
+ * ***************************************************************************
+ *
+ * Bill Ryder bryder@sgi.com of Silicon Graphics, Inc. did the FTDI_SIO code
+ * Thanx to FTDI for so kindly providing details of the protocol required
+ *   to talk to the device - http://www.ftdi.co.uk
+ *
+ * Tested as at this version - other stuff might work
+ * 23 March 2000
+ *     Works:
+ *      Baudrates - 9600, 38400,19200, 57600, 115200  
+ *      TIOCMBIC - TIOCM_DTR / TIOCM_RTS 
+ *      TIOCMBIS - TIOCM_DTR / TIOCM_RTS 
+ *      TIOCMSET - DTR on/RTSon  / DTR off, RTS off 
+ *      no parity:CS8 even parity:CS7 odd parity:CS7 
+ *      CRTSCTS flow control 
+ *     
+ *      Pilot-xfer zillions of times
+ *  
+ *      cu works with dir option 
+ *
+ *   Not Tested (ie might not work): 
+ *      xon/xoff flow control 
+ *      ppp (modem handling in general) 
+ *
+ *   KNOWN BUGS:
+ *    Multiple Opens
+ *    ==============
+ *      Seems to have problem when opening an already open port, 
+ *      Get I/O error on first attempt, then it lets you in. 
+ *      Need to do proper usage counting - keep registered callbacks for first opener.
+ *     
+ *     Reproduce with: 
+ *       cu -l /dev/ttyUSB0 dir 
+ *       whilst cu is running do:
+ *        stty -a < /dev/ttyUSB0  
+ *
+ *     from stty get: 'bash: /dev/ttyUSB0: Invalid argument ' 
+ *     from cu get 
+ *        write: Invalid argument 
+ *    
+ *    Initialisation Problem
+ *    ======================
+ *    Pilot transfer required me to run the serial_loopback program before it would work.
+ *    Still working on this. See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio
+ *
+ */
+
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int ftdi_sio_startup (struct usb_serial *serial)
+{
+	init_waitqueue_head(&serial->write_wait);
+	
+	return (0);
+}
+
+static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
+{ /* ftdi_sio_open */
+	struct termios tmp_termios;
+	struct usb_serial *serial = port->serial;
+	char buf[1]; /* Needed for the usb_control_msg I think */
+
+	dbg("ftdi_sio_open port %d", port->number);
+
+        /* FIXME - multiple concurrent opens cause trouble */
+	if (port->active) {
+		err ("port already open");
+		return -EINVAL;
+	}
+	port->active = 1; /* FIXME - For multiple open this should increment */
+
+	/* See ftdi_sio.h for description of what is reset */
+	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
+			FTDI_SIO_RESET_SIO, 
+			0, buf, 0, WDR_TIMEOUT);
+
+	/* Setup termios */
+	port->tty->termios->c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+	
+	ftdi_sio_set_termios(port, &tmp_termios);	
+
+	/* Disable flow control */
+	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+			    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+			    0, 0, 
+			    buf, 0, WDR_TIMEOUT) < 0) {
+		err("error from flowcontrol urb");
+		return(-EINVAL);
+	}	    
+
+	/* Turn on RTS and DTR since we are not flow controlling*/
+	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+			    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+			    (unsigned)FTDI_SIO_SET_DTR_HIGH, 0, 
+			    buf, 0, WDR_TIMEOUT) < 0) {
+		err("Error from DTR HIGH urb");
+	}
+	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+			    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+			    (unsigned)FTDI_SIO_SET_RTS_HIGH, 0, 
+			    buf, 0, WDR_TIMEOUT) < 0) {
+		err("Error from RTS HIGH urb");
+	}
+	
+	/*Start reading from the device*/
+	if (usb_submit_urb(port->read_urb))
+		err("usb_submit_urb(read bulk) failed");
+
+	return (0);
+} /* ftdi_sio_open */
+
+
+static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
+{ /* ftdi_sio_close */
+	struct usb_serial *serial = port->serial;
+	unsigned int c_cflag = port->tty->termios->c_cflag;
+	char buf[1];
+
+	dbg("ftdi_sio_close port %d", port->number);
+	
+	if (c_cflag & HUPCL){
+		/* Disable flow control */
+		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+				    0, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("error from flowcontrol urb");
+		}	    
+
+		/* drop DTR */
+ 		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    (unsigned)FTDI_SIO_SET_DTR_LOW, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("Error from DTR LOW urb");
+		}
+		/* drop RTS */
+		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    (unsigned)FTDI_SIO_SET_RTS_LOW, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("Error from RTS LOW urb");
+		}	
+	}
+
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+	port->active = 0;
+} /* ftdi_sio_close */
+
+
+  
+/* The ftdi_sio requires the first byte to have:
+ *  B0 1
+ *  B1 0
+ *  B2..7 length of message excluding byte 0
+ */
+static int ftdi_sio_write (struct usb_serial_port *port, int from_user, 
+			   const unsigned char *buf, int count)
+{ /* ftdi_sio_write */
+	struct usb_serial *serial = port->serial;
+	const int data_offset = 1;
+	int rc; 
+	DECLARE_WAITQUEUE(wait, current);
+	
+	dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
+
+	if (count == 0) {
+		err("write request of 0 bytes");
+		return 0;
+	}
+
+	/* only do something if we have a bulk out endpoint */
+	if (serial->num_bulk_out) {
+		unsigned char *first_byte = port->write_urb->transfer_buffer;
+
+		/* Was seeing a race here, got a read callback, then write callback before
+		   hitting interuptible_sleep_on  - so wrapping in add_wait_queue stuff */
+
+		add_wait_queue(&serial->write_wait, &wait);
+		set_current_state (TASK_INTERRUPTIBLE);
+		while (port->write_urb->status == -EINPROGRESS) {
+			dbg("ftdi_sio - write in progress - retrying");
+			if (0 /* file->f_flags & O_NONBLOCK */) {
+				rc = -EAGAIN;
+				goto err;
+			}
+			if (signal_pending(current)) {
+				current->state = TASK_RUNNING;
+				remove_wait_queue(&serial->write_wait, &wait);				
+				rc = -ERESTARTSYS;
+				goto err;
+			}
+			schedule();
+		}		
+		remove_wait_queue(&serial->write_wait, &wait);
+		set_current_state(TASK_RUNNING);
+
+		count += data_offset;
+		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+		if (count == 0) {
+			return 0;
+		}
+
+		/* Copy in the data to send */
+		if (from_user) {
+			copy_from_user(port->write_urb->transfer_buffer + data_offset , 
+				       buf, count - data_offset );
+		}
+		else {
+			memcpy(port->write_urb->transfer_buffer + data_offset,
+			       buf, count - data_offset );
+		}  
+
+		/* Write the control byte at the front of the packet*/
+		first_byte = port->write_urb->transfer_buffer;
+		*first_byte = 1 | ((count-data_offset) << 2) ; 
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+		dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
+
+		if (count) {
+			int i;
+			printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count);
+			for (i = 0; i < count; ++i) {
+				printk ( "0x%02x ", first_byte[i]);
+				if (first_byte[i] > ' ' && first_byte[i] < '~') {
+					printk( "%c ", first_byte[i]);
+				} else {
+					printk( "  ");
+				}
+			}
+
+		     
+			printk ( "\n");
+		}
+
+#endif
+		/* send the data out the bulk port */
+		port->write_urb->transfer_buffer_length = count;
+
+		if (usb_submit_urb(port->write_urb))
+			err("usb_submit_urb(write bulk) failed");
+
+		dbg("write returning: %d", count - data_offset);
+		return (count - data_offset);
+	}
+	
+	/* no bulk out, so return 0 bytes written */
+	return 0;
+ err: /* error exit */
+	return(rc);
+} /* ftdi_sio_write */
+
+static void ftdi_sio_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+       	struct tty_struct *tty = port->tty;
+
+	dbg("ftdi_sio_write_bulk_callback");
+
+	if (port_paranoia_check (port, "ftdi_sio_write_bulk_callback")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "ftdi_sio_write_bulk_callback")) {
+		return;
+	}
+	
+	if (urb->status) {
+		dbg("nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	wake_up_interruptible(&serial->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+	
+	return;
+} /* ftdi_sio_write_bulk_callback */
+
+static void ftdi_sio_read_bulk_callback (struct urb *urb)
+{ /* ftdi_sio_serial_buld_callback */
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+       	struct tty_struct *tty = port->tty ;
+       	unsigned char *data = urb->transfer_buffer;
+
+	const int data_offset = 2;
+	int i;
+
+	dbg("ftdi_sio read callback");
+
+	if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
+		return;
+	}
+	
+	/* TO DO -- check for hung up line and handle appropriately: */
+	/*   send hangup (need to find out how to do this) */
+ 
+
+	if (urb->status) {
+		/* This will happen at close every time so it is a dbg not an err */
+		dbg("nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	if (urb->actual_length > 2) {
+		printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+		for (i = 0; i < urb->actual_length; ++i) {
+			printk ( "0x%.2x ", data[i]);
+			if (data[i] > ' ' && data[i] < '~') {
+				printk( "%c ", data[i]);
+			} else {
+				printk( "  ");
+			}
+		}
+		printk ( "\n");
+	} else {
+                dbg("Just status");
+        }
+#endif
+	
+
+	if (urb->actual_length > data_offset) {
+		for (i = data_offset ; i < urb->actual_length ; ++i) {
+			tty_insert_flip_char(tty, data[i], 0);
+	  	}
+	  	tty_flip_buffer_push(tty);
+	}
+
+	/* Continue trying to always read  */
+	if (usb_submit_urb(urb))
+		err("failed resubmitting read urb");
+
+	return;
+} /* ftdi_sio_serial_read_bulk_callback */
+
+/* As I understand this - old_termios contains the original termios settings */
+/*  and tty->termios contains the new setting to be used */
+/* */
+/*   WARNING: set_termios calls this with old_termios in kernel space */
+
+static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{ /* ftdi_sio_set_termios */
+	struct usb_serial *serial = port->serial;
+	unsigned int cflag = port->tty->termios->c_cflag;
+	__u16 urb_value; /* Will hold the new flags */
+	char buf[1]; /* Perhaps I should dynamically alloc this? */
+	
+	dbg("ftdi_sio_set_termios port %d", port->number);
+
+
+	/* FIXME -For this cut I don't care if the line is really changing or 
+	   not  - so just do the change regardless  - should be able to 
+	   compare old_termios and tty->termios */
+	/* NOTE These routines can get interrupted by 
+	   ftdi_sio_read_bulk_callback  - need to examine what this 
+           means - don't see any problems yet */
+	
+	/* Set number of data bits, parity, stop bits */
+	
+	urb_value = 0;
+	urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
+		      FTDI_SIO_SET_DATA_STOP_BITS_1);
+	urb_value |= (cflag & PARENB ? 
+		      (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : 
+		       FTDI_SIO_SET_DATA_PARITY_EVEN) :
+		      FTDI_SIO_SET_DATA_PARITY_NONE);
+	if (cflag & CSIZE) {
+		switch (cflag & CSIZE) {
+		case CS5: urb_value |= 5; dbg("Setting CS5"); break;
+		case CS6: urb_value |= 6; dbg("Setting CS6"); break;
+		case CS7: urb_value |= 7; dbg("Setting CS7"); break;
+		case CS8: urb_value |= 8; dbg("Setting CS8"); break;
+		default:
+			err("CSIZE was set but not CS5-CS8");
+		}
+	}
+	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			    FTDI_SIO_SET_DATA_REQUEST, 
+			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
+			    urb_value , 0,
+			    buf, 0, 100) < 0) {
+		err("FAILED to set databits/stopbits/parity");
+	}	   
+
+	/* Now do the baudrate */
+
+	switch(cflag & CBAUD){
+	case B0: break; /* Handled below */
+	case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
+	case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
+	case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
+	case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
+	case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
+	case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
+	case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
+	case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
+	case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
+	case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
+	default: dbg("FTDI_SIO does not support the baudrate requested"); 
+		/* FIXME - how to return an error for this? */ break;
+	}
+	if ((cflag & CBAUD) == B0 ) {
+		/* Disable flow control */
+		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+				    0, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("error from disable flowcontrol urb");
+		}	    
+		/* Drop RTS and DTR */
+		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    (unsigned)FTDI_SIO_SET_DTR_LOW, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("Error from DTR LOW urb");
+		}
+		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    (unsigned)FTDI_SIO_SET_RTS_LOW, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("Error from RTS LOW urb");
+		}	
+		
+	} else {
+		if (usb_control_msg(serial->dev, 
+				    usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_BAUDRATE_REQUEST, 
+				    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+				    urb_value, 0, 
+				    buf, 0, 100) < 0) {
+			err("urb failed to set baurdrate");
+		}
+	}
+	/* Set flow control */
+	/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
+	if (cflag & CRTSCTS) {
+		dbg("Setting to CRTSCTS flow control");
+		if (usb_control_msg(serial->dev, 
+				    usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+				    0 , FTDI_SIO_RTS_CTS_HS,
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("urb failed to set to rts/cts flow control");
+		}		
+		
+	} else { 
+		/* CHECK Assuming XON/XOFF handled by stack - not by device */
+		/* Disable flow control */
+		dbg("Turning off hardware flow control");
+		if (usb_control_msg(serial->dev, 
+				    usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+				    0, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("urb failed to clear flow control");
+		}				
+		
+	}
+	return;
+} /* ftdi_sio_set_termios */
+
+static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial *serial = port->serial;
+	__u16 urb_value=0; /* Will hold the new flags */
+	char buf[1];
+	int  ret, mask;
+	
+	dbg("ftdi_sio_ioctl - cmd 0x%04x", cmd);
+
+	/* Based on code from acm.c and others */
+	switch (cmd) {
+
+	case TIOCMGET:
+		dbg("TIOCMGET");
+		/* Request the status from the device */
+		if ((ret = usb_control_msg(serial->dev, 
+					   usb_rcvctrlpipe(serial->dev, 0),
+					   FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
+					   FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+					   0, 0, 
+					   buf, 1, HZ * 5)) < 0 ) {
+			dbg("Get not get modem status of device");
+			return(ret);
+		}
+
+		return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
+				(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
+				(buf[0]  & FTDI_SIO_RI_MASK  ? TIOCM_RI  : 0) |
+				(buf[0]  & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0),
+				(unsigned long *) arg);
+		break;
+
+	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+		dbg("TIOCMSET");
+		if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+		urb_value = ((mask & TIOCM_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW);
+		if ((ret = usb_control_msg(serial->dev, 
+				    usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    urb_value , 0,
+				    buf, 0, WDR_TIMEOUT)) < 0){
+			err("Urb to set DTR failed");
+			return(ret);
+		}
+		urb_value = ((mask & TIOCM_RTS) ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW);
+		if ((ret = usb_control_msg(serial->dev, 
+				    usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    urb_value , 0,
+				    buf, 0, WDR_TIMEOUT)) < 0){
+			err("Urb to set RTS failed");
+			return(ret);
+		}
+		break;
+					
+	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+		dbg("TIOCMBIS");
+ 	        if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+  	        if (mask & TIOCM_DTR){
+			if ((ret = usb_control_msg(serial->dev, 
+					    usb_sndctrlpipe(serial->dev, 0),
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+					    FTDI_SIO_SET_DTR_HIGH , 0,
+					    buf, 0, WDR_TIMEOUT)) < 0){
+				err("Urb to set DTR failed");
+				return(ret);
+				}
+			}
+			if (mask & TIOCM_RTS) {
+			if ((ret = usb_control_msg(serial->dev, 
+					    usb_sndctrlpipe(serial->dev, 0),
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+					    FTDI_SIO_SET_RTS_HIGH , 0,
+					    buf, 0, WDR_TIMEOUT)) < 0){
+				err("Urb to set RTS failed");
+				return(ret);
+			}
+		}
+					break;
+
+	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+		dbg("TIOCMBIC");
+ 	        if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+  	        if (mask & TIOCM_DTR){
+			if ((ret = usb_control_msg(serial->dev, 
+					    usb_sndctrlpipe(serial->dev, 0),
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+					    FTDI_SIO_SET_DTR_LOW , 0,
+					    buf, 0, WDR_TIMEOUT)) < 0){
+				err("Urb to unset DTR failed");
+				return(ret);
+			}
+		}	
+		if (mask & TIOCM_RTS) {
+			if ((ret = usb_control_msg(serial->dev, 
+					       usb_sndctrlpipe(serial->dev, 0),
+					       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+					       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+					    FTDI_SIO_SET_RTS_LOW , 0,
+					    buf, 0, WDR_TIMEOUT)) < 0){
+				err("Urb to unset RTS failed");
+				return(ret);
+			}
+		}
+		break;
+
+		/*
+		 * I had originally implemented TCSET{A,S}{,F,W} and
+		 * TCGET{A,S} here separately, however when testing I
+		 * found that the higher layers actually do the termios
+		 * conversions themselves and pass the call onto
+		 * ftdi_sio_set_termios. 
+		 *
+		 */
+
+	default:
+	  /* This is not an error - turns out the higher layers will do 
+	   *  some ioctls itself (see comment above)
+ 	   */
+		dbg("ftdi_sio ioctl arg not supported - it was 0x%04x",cmd);
+		return(-ENOIOCTLCMD);
+		break;
+	}
+	dbg("ftdi_sio_ioctl returning 0");
+	return 0;
+} /* ftdi_sio_ioctl */
+
+#endif 	/* CONFIG_USB_SERIAL_FTDI_SIO */
+
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/ftdi_sio.h linux/drivers/usb/serial/ftdi_sio.h
--- v2.3.99-pre3/linux/drivers/usb/serial/ftdi_sio.h	Fri Mar 10 16:40:45 2000
+++ linux/drivers/usb/serial/ftdi_sio.h	Sun Apr  2 15:20:16 2000
@@ -1,15 +1,23 @@
-/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
-/* The device is based on the FTDI FT8U100AX chip, DB25 on one side, USB on the other */
-/* Thanx to FTDI for so kindly providing details of the protocol required */
-/* http://www.ftdi.co.uk  */
-
-/* The implementation of the device I have is called a USC-1000 */
-/*  which is available from http://www.dse.co.nz - cat no XH4214 */
-/* It looks similar to this: http://www.dansdata.com/usbser.htm but I can't be sure */
-/* There are other USC-1000s which don't look like my device though so beware */
-
-/* Definitions for the FTDI USB Single Port Serial Converter */
-/* known as FTDI_SIO (Serial Input/Output application of the chipset) */
+/*
+ * Definitions for the FTDI USB Single Port Serial Converter - 
+ * known as FTDI_SIO (Serial Input/Output application of the chipset) 
+ *
+ * The example I have is known as the USC-1000 which is available from
+ * http://www.dse.co.nz - cat no XH4214 It looks similar to this:
+ * http://www.dansdata.com/usbser.htm but I can't be sure There are other
+ * USC-1000s which don't look like my device though so beware!
+ *
+ * The device is based on the FTDI FT8U100AX chip. It has a DB25 on one side, 
+ * USB on the other.
+ *
+ * Thanx to FTDI (http://www.ftdi.co.uk) for so kindly providing details
+ * of the protocol required to talk to the device and ongoing assistence
+ * during development.
+ *
+ * Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the 
+ * FTDI_SIO implementation.
+ *
+ */
 
 #define FTDI_VID	0x0403	/* Vendor Id */
 #define FTDI_SIO_PID	0x8372	/* Product Id */
@@ -27,7 +35,7 @@
 /* Port Identifier Table */
 #define PIT_DEFAULT 		0 /* SIOA */
 #define PIT_SIOA		1 /* SIOA */
-/* The device this is tested with one has one port */
+/* The device this driver is tested with one has only one port */
 #define PIT_SIOB		2 /* SIOB */
 #define PIT_PARALLEL		3 /* Parallel */
 
@@ -37,17 +45,31 @@
 #define FTDI_SIO_RESET_SIO 0
 #define FTDI_SIO_RESET_PURGE_RX 1
 #define FTDI_SIO_RESET_PURGE_TX 2
-/* 
-   BmRequestType:  0100 0000B
-   bRequest:       FTDI_SIO_RESET
-   wValue:         Control Value 
-                         0 = Reset SIO
-                         1 = Purge RX buffer
-                         2 = Purge TX buffer
-   wIndex:         Port
-   wLength:        0
-   Data:           None
 
+/*
+ * BmRequestType:  0100 0000B
+ * bRequest:       FTDI_SIO_RESET
+ * wValue:         Control Value 
+ *                   0 = Reset SIO
+ *                   1 = Purge RX buffer
+ *                   2 = Purge TX buffer
+ * wIndex:         Port
+ * wLength:        0
+ * Data:           None
+ *
+ * The Reset SIO command has this effect:
+ *
+ *    Sets flow control set to 'none'
+ *    Event char = $0D
+ *    Event trigger = disabled
+ *    Purge RX buffer
+ *    Purge TX buffer
+ *    Clear DTR
+ *    Clear RTS
+ *    baud and data format not reset
+ *
+ * The Purge RX and TX buffer commands affect nothing except the buffers
+ *
    */
 
 /* FTDI_SIO_SET_BAUDRATE */
@@ -55,13 +77,13 @@
 #define FTDI_SIO_SET_BAUDRATE_REQUEST 3
 
 /*
-  BmRequestType:  0100 0000B
-  bRequest:       FTDI_SIO_SET_BAUDRATE
-  wValue:         BaudRate value - see below
-  wIndex:         Port
-  wLength:        0
-  Data:           None
-*/
+ * BmRequestType:  0100 0000B
+ * bRequest:       FTDI_SIO_SET_BAUDRATE
+ * wValue:         BaudRate value - see below
+ * wIndex:         Port
+ * wLength:        0
+ * Data:           None
+ */
 
 typedef enum {
  ftdi_sio_b300 = 0, 
@@ -89,28 +111,30 @@
 
 /* FTDI_SIO_SET_DATA */
 
-/*    BmRequestType:  0100 0000B */
-/*    bRequest:       FTDI_SIO_SET_DATA */
-/*    wValue:         Data characteristics (see below) */
-/*    wIndex:         Port */
-/*    wLength:        0 */
-/*    Data:           None */
-/* 
-  Data characteristics
-
-B0..7   Number of data bits
-B8..10  Parity
-           0 = None
-           1 = Odd
-           2 = Even
-           3 = Mark
-           4 = Space
- B11..13 Stop Bits
-           0 = 1
-           1 = 1.5
-           2 = 2
- B14..15 Reserved
-*/
+/*
+ * BmRequestType:  0100 0000B 
+ * bRequest:       FTDI_SIO_SET_DATA
+ * wValue:         Data characteristics (see below)
+ * wIndex:         Port
+ * wLength:        0
+ * Data:           No
+ *
+ * Data characteristics
+ *
+ *   B0..7   Number of data bits
+ *   B8..10  Parity
+ *           0 = None
+ *           1 = Odd
+ *           2 = Even
+ *           3 = Mark
+ *           4 = Space
+ *   B11..13 Stop Bits
+ *           0 = 1
+ *           1 = 1.5
+ *           2 = 2
+ *   B14..15 Reserved
+ *
+ */
 
 
 
@@ -119,16 +143,17 @@
 #define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL
 
 /* 
-  BmRequestType:   0100 0000B
-  bRequest:        FTDI_SIO_MODEM_CTRL
-  wValue:          ControlValue (see below)
-  wIndex:          Port
-  wLength:         0
-  Data:            None
-
-  NOTE: If the device is in RTS/CTS flow control, the RTS set by this
-        command will be IGNORED without an error being returned
-*/
+ * BmRequestType:   0100 0000B
+ * bRequest:        FTDI_SIO_MODEM_CTRL
+ * wValue:          ControlValue (see below)
+ * wIndex:          Port
+ * wLength:         0
+ * Data:            None
+ *
+ * NOTE: If the device is in RTS/CTS flow control, the RTS set by this
+ * command will be IGNORED without an error being returned
+ * Also - you can not set DTR and RTS with one control message
+ */
 
 #define FTDI_SIO_SET_DTR_MASK 0x1
 #define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK  << 8))
@@ -137,100 +162,107 @@
 #define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
 #define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
 
-/* ControlValue
-   B0    DTR state
-           0 = reset
-           1 = set
-   B1    RTS state
-           0 = reset
-           1 = set
-   B2..7 Reserved
-   B8    DTR state enable
-           0 = ignore
-           1 = use DTR state
-   B9    RTS state enable
-           0 = ignore
-           1 = use RTS state
-   B10..15 Reserved
-*/
+/*
+ * ControlValue
+ * B0    DTR state
+ *          0 = reset
+ *          1 = set
+ * B1    RTS state
+ *          0 = reset
+ *          1 = set
+ * B2..7 Reserved
+ * B8    DTR state enable
+ *          0 = ignore
+ *          1 = use DTR state
+ * B9    RTS state enable
+ *          0 = ignore
+ *          1 = use RTS state
+ * B10..15 Reserved
+ */
 
 /* FTDI_SIO_SET_FLOW_CTRL */
 #define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40
 #define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL
 #define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 
-#define FTDI_SIO_RTS_CTS_HS 0x1
-#define FTDI_SIO_DTR_DSR_HS 0x2
-#define FTDI_SIO_XON_XOFF_HS 0x4
-/* 
-   BmRequestType:  0100 0000b
-   bRequest:       FTDI_SIO_SET_FLOW_CTRL
-   wValue:         Xoff/Xon
-   wIndex:         Protocol/Port - hIndex is protocl / lIndex is port
-   wLength:        0 
-   Data:           None
-
-hIndex - protocol has
- B0 Output handshaking using RTS/CTS
-      0 = disabled
-      1 = enabled
- B1 Output handshaking using DTR/DSR
-      0 = disabled
-      1 = enabled
- B2 Xon/Xoff handshaking
-      0 = disabled
-      1 = enabled
-
-A value of zero in the hIndex field selects no handshaking
+#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
+#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
+#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
+/*
+ *   BmRequestType:  0100 0000b
+ *   bRequest:       FTDI_SIO_SET_FLOW_CTRL
+ *   wValue:         Xoff/Xon
+ *   wIndex:         Protocol/Port - hIndex is protocl / lIndex is port
+ *   wLength:        0 
+ *   Data:           None
+ *
+ * hIndex protocol is:
+ *   B0 Output handshaking using RTS/CTS
+ *       0 = disabled
+ *       1 = enabled
+ *   B1 Output handshaking using DTR/DSR
+ *       0 = disabled
+ *       1 = enabled
+ *   B2 Xon/Xoff handshaking
+ *       0 = disabled
+ *       1 = enabled
+ *
+ * A value of zero in the hIndex field disables handshaking
+ *
+ * If Xon/Xoff handshaking is specified, the hValue field should contain the XOFF character 
+ * and the lValue field contains the XON character.
+ */  
+ 
+/*
+ * FTDI_SIO_SET_EVENT_CHAR 
+ *
+ * Set the special event character for the specified communications port.
+ * If the device sees this character it will immediately return the
+ * data read so far - rather than wait 40ms or until 62 bytes are read
+ * which is what normally happens.
+ */
 
-If Xon/Xoff handshaking is specified, the hValue field contains the Xoff character 
-and the lValue field contains the Xon character.
 
-*/  
- 
-/* FTDI_SIO_SET_EVENT_CHAR */
-/* Set the special event character for the specified communications port */
-/* If the device sees this character it will immediately return the */
-/* data read so far - rather than wait 40ms or until 62 bytes is read */
 #define  FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR
 #define  FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40
 
 
 /* 
-  BmRequestType:   0100 0000b
-  bRequest:        FTDI_SIO_SET_EVENT_CHAR
-  wValue:          EventChar
-  wIndex:          Port
-  wLength:         0
-  Data:            None
-
-wValue:
-   B0..7   Event Character
-   B8      Event Character Processing
-             0 = disabled
-             1 = enabled
-   B9..15  Reserved
-
-*/
+ *  BmRequestType:   0100 0000b
+ *  bRequest:        FTDI_SIO_SET_EVENT_CHAR
+ *  wValue:          EventChar
+ *  wIndex:          Port
+ *  wLength:         0
+ *  Data:            None
+ *
+ * wValue:
+ *   B0..7   Event Character
+ *   B8      Event Character Processing
+ *             0 = disabled
+ *             1 = enabled
+ *   B9..15  Reserved
+ *
+ */
           
 /* FTDI_SIO_SET_ERROR_CHAR */
+
 /* Set the parity error replacement character for the specified communications port */
 
 /* 
-  BmRequestType:  0100 0000b
-  bRequest:       FTDI_SIO_SET_EVENT_CHAR
-  wValue:         Error Char
-  wIndex:         Port
-  wLength:        0
-  Data:           None
-
-Error Char
-  B0..7  Error Character
-  B8     Error Character Processing
-           0 = disabled
-           1 = enabled
-  B9..15 Reserved
-
-*/
+ *  BmRequestType:  0100 0000b
+ *  bRequest:       FTDI_SIO_SET_EVENT_CHAR
+ *  wValue:         Error Char
+ *  wIndex:         Port
+ *  wLength:        0
+ *  Data:           None
+ *
+ *Error Char
+ *  B0..7  Error Character
+ *  B8     Error Character Processing
+ *           0 = disabled
+ *           1 = enabled
+ *  B9..15 Reserved
+ *
+ */
 
 /* FTDI_SIO_GET_MODEM_STATUS */
 /* Retreive the current value of the modem status register */
@@ -242,139 +274,140 @@
 #define FTDI_SIO_RI_MASK  0x40
 #define FTDI_SIO_RLSD_MASK 0x80
 /* 
-  BmRequestType:   1100 0000b
-  bRequest:        FTDI_SIO_GET_MODEM_STATUS
-  wValue:          zero
-  wIndex:          Port
-  wLength:         1
-  Data:            Status
-
-One byte of data is returned 
-B0..3 0
-B4    CTS
-        0 = inactive
-        1 = active
-B5    DSR
-        0 = inactive
-        1 = active
-B6    Ring Indicator (RI)
-        0 = inactive
-        1 = active
-B7    Receive Line Signal Detect (RLSD)
-        0 = inactive
-        1 = active 
-*/
+ *   BmRequestType:   1100 0000b
+ *   bRequest:        FTDI_SIO_GET_MODEM_STATUS
+ *   wValue:          zero
+ *   wIndex:          Port
+ *   wLength:         1
+ *   Data:            Status
+ * 
+ * One byte of data is returned 
+ * B0..3 0
+ * B4    CTS
+ *         0 = inactive
+ *         1 = active
+ * B5    DSR
+ *         0 = inactive
+ *         1 = active
+ * B6    Ring Indicator (RI)
+ *         0 = inactive
+ *         1 = active
+ * B7    Receive Line Signal Detect (RLSD)
+ *         0 = inactive
+ *         1 = active 
+ */
 
 
 
 /* Descriptors returned by the device 
+ * 
+ *  Device Descriptor
+ * 
+ * Offset	Field		Size	Value	Description
+ * 0	bLength		1	0x12	Size of descriptor in bytes
+ * 1	bDescriptorType	1	0x01	DEVICE Descriptor Type
+ * 2	bcdUSB		2	0x0110	USB Spec Release Number
+ * 4	bDeviceClass	1	0x00	Class Code
+ * 5	bDeviceSubClass	1	0x00	SubClass Code
+ * 6	bDeviceProtocol	1	0x00	Protocol Code
+ * 7	bMaxPacketSize0 1	0x08	Maximum packet size for endpoint 0
+ * 8	idVendor	2	0x0403	Vendor ID
+ * 10	idProduct	2	0x8372	Product ID (FTDI_SIO_PID)
+ * 12	bcdDevice	2	0x0001	Device release number
+ * 14	iManufacturer	1	0x01	Index of man. string desc
+ * 15	iProduct	1	0x02	Index of prod string desc
+ * 16	iSerialNumber	1	0x02	Index of serial nmr string desc
+ * 17	bNumConfigurations 1    0x01	Number of possible configurations
+ * 
+ * Configuration Descriptor
+ * 
+ * Offset	Field			Size	Value
+ * 0	bLength			1	0x09	Size of descriptor in bytes
+ * 1	bDescriptorType		1	0x02	CONFIGURATION Descriptor Type
+ * 2	wTotalLength		2	0x0020	Total length of data
+ * 4	bNumInterfaces		1	0x01	Number of interfaces supported
+ * 5	bConfigurationValue	1	0x01	Argument for SetCOnfiguration() req
+ * 6	iConfiguration		1	0x02	Index of config string descriptor
+ * 7	bmAttributes		1	0x20	Config characteristics Remote Wakeup
+ * 8	MaxPower		1	0x1E	Max power consumption
+ * 
+ * Interface Descriptor
+ * 
+ * Offset	Field			Size	Value
+ * 0	bLength			1	0x09	Size of descriptor in bytes
+ * 1	bDescriptorType		1	0x04	INTERFACE Descriptor Type
+ * 2	bInterfaceNumber	1	0x00	Number of interface
+ * 3	bAlternateSetting	1	0x00	Value used to select alternate
+ * 4	bNumEndpoints		1	0x02	Number of endpoints
+ * 5	bInterfaceClass		1	0xFF	Class Code
+ * 6	bInterfaceSubClass	1	0xFF	Subclass Code
+ * 7	bInterfaceProtocol	1	0xFF	Protocol Code
+ * 8	iInterface		1	0x02	Index of interface string description
+ * 
+ * IN Endpoint Descriptor
+ * 
+ * Offset	Field			Size	Value
+ * 0	bLength			1	0x07	Size of descriptor in bytes
+ * 1	bDescriptorType		1	0x05	ENDPOINT descriptor type
+ * 2	bEndpointAddress	1	0x82	Address of endpoint
+ * 3	bmAttributes		1	0x02	Endpoint attributes - Bulk
+ * 4	bNumEndpoints		2	0x0040	maximum packet size
+ * 5	bInterval		1	0x00	Interval for polling endpoint
+ * 
+ * OUT Endpoint Descriptor
+ * 
+ * Offset	Field			Size	Value
+ * 0	bLength			1	0x07	Size of descriptor in bytes
+ * 1	bDescriptorType		1	0x05	ENDPOINT descriptor type
+ * 2	bEndpointAddress	1	0x02	Address of endpoint
+ * 3	bmAttributes		1	0x02	Endpoint attributes - Bulk
+ * 4	bNumEndpoints		2	0x0040	maximum packet size
+ * 5	bInterval		1	0x00	Interval for polling endpoint
+ *     
+ * DATA FORMAT
+ * 
+ * IN Endpoint
+ * 
+ * The device reserves the first two bytes of data on this endpoint to contain the current
+ * values of the modem and line status registers. In the absence of data, the device 
+ * generates a message consisting of these two status bytes every 40 ms
+ * 
+ * Byte 0: Modem Status
+ * 
+ * Offset	Description
+ * B0	Reserved - must be 1
+ * B1	Reserved - must be 0
+ * B2	Reserved - must be 0
+ * B3	Reserved - must be 0
+ * B4	Clear to Send (CTS)
+ * B5	Data Set Ready (DSR)
+ * B6	Ring Indicator (RI)
+ * B7	Receive Line Signal Detect (RLSD)
+ * 
+ * Byte 1: Line Status
+ * 
+ * Offset	Description
+ * B0	Data Ready (DR)
+ * B1	Overrun Error (OE)
+ * B2	Parity Error (PE)
+ * B3	Framing Error (FE)
+ * B4	Break Interrupt (BI)
+ * B5	Transmitter Holding Register (THRE)
+ * B6	Transmitter Empty (TEMT)
+ * B7	Error in RCVR FIFO
+ * 
+ * OUT Endpoint
+ * 
+ * This device reserves the first bytes of data on this endpoint contain the length
+ * and port identifier of the message. For the FTDI USB Serial converter the port 
+ * identifier is always 1.
+ * 
+ * Byte 0: Line Status
+ * 
+ * Offset	Description
+ * B0	Reserved - must be 1
+ * B1	Reserved - must be 0
+ * B2..7	Length of message - (not including Byte 0)
+ * 
+ */
 
- Device Descriptor
-
-Offset	Field		Size	Value	Description
-0	bLength		1	0x12	Size of descriptor in bytes
-1	bDescriptorType	1	0x01	DEVICE Descriptor Type
-2	bcdUSB		2	0x0110	USB Spec Release Number
-4	bDeviceClass	1	0x00	Class Code
-5	bDeviceSubClass	1	0x00	SubClass Code
-6	bDeviceProtocol	1	0x00	Protocol Code
-7	bMaxPacketSize0 1	0x08	Maximum packet size for endpoint 0
-8	idVendor	2	0x0403	Vendor ID
-10	idProduct	2	0x8372	Product ID (FTDI_SIO_PID)
-12	bcdDevice	2	0x0001	Device release number
-14	iManufacturer	1	0x01	Index of man. string desc
-15	iProduct	1	0x02	Index of prod string desc
-16	iSerialNumber	1	0x02	Index of serial nmr string desc
-17	bNumConfigurations 1    0x01	Number of possible configurations
-
-Configuration Descriptor
-
-Offset	Field			Size	Value
-0	bLength			1	0x09	Size of descriptor in bytes
-1	bDescriptorType		1	0x02	CONFIGURATION Descriptor Type
-2	wTotalLength		2	0x0020	Total length of data
-4	bNumInterfaces		1	0x01	Number of interfaces supported
-5	bConfigurationValue	1	0x01	Argument for SetCOnfiguration() req
-6	iConfiguration		1	0x02	Index of config string descriptor
-7	bmAttributes		1	0x20	Config characteristics Remote Wakeup
-8	MaxPower		1	0x1E	Max power consumption
-
-Interface Descriptor
-
-Offset	Field			Size	Value
-0	bLength			1	0x09	Size of descriptor in bytes
-1	bDescriptorType		1	0x04	INTERFACE Descriptor Type
-2	bInterfaceNumber	1	0x00	Number of interface
-3	bAlternateSetting	1	0x00	Value used to select alternate
-4	bNumEndpoints		1	0x02	Number of endpoints
-5	bInterfaceClass		1	0xFF	Class Code
-6	bInterfaceSubClass	1	0xFF	Subclass Code
-7	bInterfaceProtocol	1	0xFF	Protocol Code
-8	iInterface		1	0x02	Index of interface string description
-
-IN Endpoint Descriptor
-
-Offset	Field			Size	Value
-0	bLength			1	0x07	Size of descriptor in bytes
-1	bDescriptorType		1	0x05	ENDPOINT descriptor type
-2	bEndpointAddress	1	0x82	Address of endpoint
-3	bmAttributes		1	0x02	Endpoint attributes - Bulk
-4	bNumEndpoints		2	0x0040	maximum packet size
-5	bInterval		1	0x00	Interval for polling endpoint
-
-OUT Endpoint Descriptor
-
-Offset	Field			Size	Value
-0	bLength			1	0x07	Size of descriptor in bytes
-1	bDescriptorType		1	0x05	ENDPOINT descriptor type
-2	bEndpointAddress	1	0x02	Address of endpoint
-3	bmAttributes		1	0x02	Endpoint attributes - Bulk
-4	bNumEndpoints		2	0x0040	maximum packet size
-5	bInterval		1	0x00	Interval for polling endpoint
-    
-DATA FORMAT
-
-IN Endpoint
-
-The device reserves the first two bytes of data on this endpoint to contain the current
-values of the modem and line status registers. In the absence of data, the device 
-generates a message consisting of these two status bytes every 40 ms
-
-Byte 0: Modem Status
-
-Offset	Description
-B0	Reserved - must be 1
-B1	Reserved - must be 0
-B2	Reserved - must be 0
-B3	Reserved - must be 0
-B4	Clear to Send (CTS)
-B5	Data Set Ready (DSR)
-B6	Ring Indicator (RI)
-B7	Receive Line Signal Detect (RLSD)
-
-Byte 1: Line Status
-
-Offset	Description
-B0	Data Ready (DR)
-B1	Overrun Error (OE)
-B2	Parity Error (PE)
-B3	Framing Error (FE)
-B4	Break Interrupt (BI)
-B5	Transmitter Holding Register (THRE)
-B6	Transmitter Empty (TEMT)
-B7	Error in RCVR FIFO
-
-OUT Endpoint
-
-This device reserves the first bytes of data on this endpoint contain the length
-and port identifier of the message. For the FTDI USB Serial converter the port 
-identifier is always 1.
-
-Byte 0: Line Status
-
-Offset	Description
-B0	Reserved - must be 1
-B1	Reserved - must be 0
-B2..7	Length of message - (not including Byte 0)
-
-*/
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c
--- v2.3.99-pre3/linux/drivers/usb/serial/keyspan_pda.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/keyspan_pda.c	Mon Mar 27 14:25:28 2000
@@ -0,0 +1,717 @@
+/*
+ * USB Keyspan PDA Converter driver
+ *
+ *	(C) Copyright (C) 1999, 2000
+ *	    Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ * 
+ * (03/26/2000) gkh
+ *	Split driver up into device specific pieces.
+ * 
+ */
+
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+struct ezusb_hex_record {
+	__u16 address;
+	__u8 data_size;
+	__u8 data[16];
+};
+
+#include "keyspan_pda_fw.h"
+
+#include "usb-serial.h"
+
+#define KEYSPAN_VENDOR_ID		0x06cd
+#define KEYSPAN_PDA_FAKE_ID		0x0103
+#define KEYSPAN_PDA_ID			0x0104 /* no clue */
+
+/* function prototypes for a Keyspan PDA serial converter */
+static int  keyspan_pda_open		(struct usb_serial_port *port,
+					 struct file *filp);
+static void keyspan_pda_close		(struct usb_serial_port *port,
+					 struct file *filp);
+static int  keyspan_pda_startup		(struct usb_serial *serial);
+static void keyspan_pda_rx_throttle	(struct usb_serial_port *port);
+static void keyspan_pda_rx_unthrottle	(struct usb_serial_port *port);
+static int  keyspan_pda_setbaud		(struct usb_serial *serial, int baud);
+static int  keyspan_pda_write_room	(struct usb_serial_port *port);
+static int  keyspan_pda_write		(struct usb_serial_port *port,
+					 int from_user,
+					 const unsigned char *buf,
+					 int count);
+static void keyspan_pda_write_bulk_callback (struct urb *urb);
+static int  keyspan_pda_chars_in_buffer (struct usb_serial_port *port);
+static int  keyspan_pda_ioctl		(struct usb_serial_port *port,
+					 struct file *file,
+					 unsigned int cmd,
+					 unsigned long arg);
+static void keyspan_pda_set_termios	(struct usb_serial_port *port,
+					 struct termios *old);
+static void keyspan_pda_break_ctl	(struct usb_serial_port *port,
+					 int break_state);
+static int  keyspan_pda_fake_startup	(struct usb_serial *serial);
+
+
+/* All of the device info needed for the Keyspan PDA serial converter */
+static __u16	keyspan_vendor_id		= KEYSPAN_VENDOR_ID;
+static __u16	keyspan_pda_fake_product_id	= KEYSPAN_PDA_FAKE_ID;
+static __u16	keyspan_pda_product_id		= KEYSPAN_PDA_ID;
+struct usb_serial_device_type keyspan_pda_fake_device = {
+	name:			"Keyspan PDA - (prerenumeration)",
+	idVendor:		&keyspan_vendor_id,		/* the Keyspan PDA vendor ID */
+	idProduct:		&keyspan_pda_fake_product_id,	/* the Keyspan PDA initial product id */
+	needs_interrupt_in:	DONT_CARE,			/* don't have to have an interrupt in endpoint */
+	needs_bulk_in:		DONT_CARE,			/* don't have to have a bulk in endpoint */
+	needs_bulk_out:		DONT_CARE,			/* don't have to have a bulk out endpoint */
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	startup:		keyspan_pda_fake_startup
+};
+struct usb_serial_device_type keyspan_pda_device = {
+	name:			"Keyspan PDA",
+	idVendor:		&keyspan_vendor_id,		/* the Keyspan PDA vendor ID */
+	idProduct:		&keyspan_pda_product_id,	/* the Keyspan PDA product id */
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		0,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			keyspan_pda_open,
+	close:			keyspan_pda_close,
+	write:			keyspan_pda_write,
+	write_room:		keyspan_pda_write_room,
+	write_bulk_callback: 	keyspan_pda_write_bulk_callback,
+	chars_in_buffer:	keyspan_pda_chars_in_buffer,
+	throttle:		keyspan_pda_rx_throttle,
+	unthrottle:		keyspan_pda_rx_unthrottle,
+	startup:		keyspan_pda_startup,
+	ioctl:			keyspan_pda_ioctl,
+	set_termios:		keyspan_pda_set_termios,
+	break_ctl:		keyspan_pda_break_ctl,
+};
+
+
+static void keyspan_pda_rx_interrupt (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+       	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	int i;
+
+	/* the urb might have been killed. */
+	if (urb->status)
+		return;
+	
+	if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
+		return;
+	}
+	
+ 	/* see if the message is data or a status interrupt */
+	switch (data[0]) {
+	case 0:
+		/* rest of message is rx data */
+		if (urb->actual_length) {
+			tty = serial->port[0].tty;
+			for (i = 1; i < urb->actual_length ; ++i) {
+				tty_insert_flip_char(tty, data[i], 0);
+			}
+			tty_flip_buffer_push(tty);
+		}
+		break;
+	case 1:
+		/* status interrupt */
+		dbg(" rx int, d1=%d, d2=%d", data[1], data[2]);
+		switch (data[1]) {
+		case 1: /* modemline change */
+			break;
+		case 2: /* tx unthrottle interrupt */
+			tty = serial->port[0].tty;
+			serial->tx_throttled = 0;
+			wake_up(&serial->write_wait); /* wake up writer */
+			wake_up(&tty->write_wait); /* them too */
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* INT urbs are automatically re-submitted */
+}
+
+
+static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
+{
+	/* stop receiving characters. We just turn off the URB request, and
+	   let chars pile up in the device. If we're doing hardware
+	   flowcontrol, the device will signal the other end when its buffer
+	   fills up. If we're doing XON/XOFF, this would be a good time to
+	   send an XOFF, although it might make sense to foist that off
+	   upon the device too. */
+
+	dbg("keyspan_pda_rx_throttle port %d", port->number);
+	usb_unlink_urb(port->read_urb);
+}
+
+
+static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
+{
+	/* just restart the receive interrupt URB */
+	dbg("keyspan_pda_rx_unthrottle port %d", port->number);
+	if (usb_submit_urb(port->read_urb))
+		dbg(" usb_submit_urb(read urb) failed");
+	return;
+}
+
+
+static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
+{
+	int rc;
+	int bindex;
+
+	switch(baud) {
+		case 110: bindex = 0; break;
+		case 300: bindex = 1; break;
+		case 1200: bindex = 2; break;
+		case 2400: bindex = 3; break;
+		case 4800: bindex = 4; break;
+		case 9600: bindex = 5; break;
+		case 19200: bindex = 6; break;
+		case 38400: bindex = 7; break;
+		case 57600: bindex = 8; break;
+		case 115200: bindex = 9; break;
+		default: return -EINVAL;
+	}
+
+	/* rather than figure out how to sleep while waiting for this
+	   to complete, I just use the "legacy" API. */
+	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			     0, /* set baud */
+			     USB_TYPE_VENDOR 
+			     | USB_RECIP_INTERFACE
+			     | USB_DIR_OUT, /* type */
+			     bindex, /* value */
+			     0, /* index */
+			     NULL, /* &data */
+			     0, /* size */
+			     2*HZ); /* timeout */
+	return(rc);
+}
+
+
+static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state)
+{
+	struct usb_serial *serial = port->serial;
+	int value;
+	if (break_state == -1)
+		value = 1; /* start break */
+	else
+		value = 0; /* clear break */
+	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			4, /* set break */
+			USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			value, 0, NULL, 0, 2*HZ);
+	/* there is something funky about this.. the TCSBRK that 'cu' performs
+	   ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
+	   seconds apart, but it feels like the break sent isn't as long as it
+	   is on /dev/ttyS0 */
+}
+
+
+static void keyspan_pda_set_termios (struct usb_serial_port *port, 
+				     struct termios *old_termios)
+{
+	struct usb_serial *serial = port->serial;
+	unsigned int cflag = port->tty->termios->c_cflag;
+
+	/* cflag specifies lots of stuff: number of stop bits, parity, number
+	   of data bits, baud. What can the device actually handle?:
+	   CSTOPB (1 stop bit or 2)
+	   PARENB (parity)
+	   CSIZE (5bit .. 8bit)
+	   There is minimal hw support for parity (a PSW bit seems to hold the
+	   parity of whatever is in the accumulator). The UART either deals
+	   with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
+	   1 special, stop). So, with firmware changes, we could do:
+	   8N1: 10 bit
+	   8N2: 11 bit, extra bit always (mark?)
+	   8[EOMS]1: 11 bit, extra bit is parity
+	   7[EOMS]1: 10 bit, b0/b7 is parity
+	   7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
+
+	   HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
+	   bit.
+
+	   For now, just do baud. */
+
+	switch (cflag & CBAUD) {
+		/* we could support more values here, just need to calculate
+		   the necessary divisors in the firmware. <asm/termbits.h>
+		   has the Bnnn constants. */
+		case B110: keyspan_pda_setbaud(serial, 110); break;
+		case B300: keyspan_pda_setbaud(serial, 300); break;
+		case B1200: keyspan_pda_setbaud(serial, 1200); break;
+		case B2400: keyspan_pda_setbaud(serial, 2400); break;
+		case B4800: keyspan_pda_setbaud(serial, 4800); break;
+		case B9600: keyspan_pda_setbaud(serial, 9600); break;
+		case B19200: keyspan_pda_setbaud(serial, 19200); break;
+		case B38400: keyspan_pda_setbaud(serial, 38400); break;
+		case B57600: keyspan_pda_setbaud(serial, 57600); break;
+		case B115200: keyspan_pda_setbaud(serial, 115200); break;
+		default: dbg("can't handle requested baud rate"); break;
+	}
+}
+
+
+/* modem control pins: DTR and RTS are outputs and can be controlled.
+   DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
+   read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */
+
+static int keyspan_pda_get_modem_info(struct usb_serial *serial,
+				      unsigned char *value)
+{
+	int rc;
+	unsigned char data;
+	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     3, /* get pins */
+			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
+			     0, 0, &data, 1, 2*HZ);
+	if (rc > 0)
+		*value = data;
+	return rc;
+}
+
+
+static int keyspan_pda_set_modem_info(struct usb_serial *serial,
+				      unsigned char value)
+{
+	int rc;
+	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			     3, /* set pins */
+			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
+			     value, 0, NULL, 0, 2*HZ);
+	return rc;
+}
+
+
+static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file,
+			     unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial *serial = port->serial;
+	int rc;
+	unsigned int value;
+	unsigned char status, mask;
+
+	switch (cmd) {
+	case TIOCMGET: /* get modem pins state */
+		rc = keyspan_pda_get_modem_info(serial, &status);
+		if (rc < 0)
+			return rc;
+		value =
+			((status & (1<<7)) ? TIOCM_DTR : 0) |
+			((status & (1<<6)) ? TIOCM_CAR : 0) |
+			((status & (1<<5)) ? TIOCM_RNG : 0) |
+			((status & (1<<4)) ? TIOCM_DSR : 0) |
+			((status & (1<<3)) ? TIOCM_CTS : 0) |
+			((status & (1<<2)) ? TIOCM_RTS : 0);
+		if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
+			return -EFAULT;
+		return 0;
+	case TIOCMSET: /* set a state as returned by MGET */
+		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+			return -EFAULT;
+		status =
+			((value & TIOCM_DTR) ? (1<<7) : 0) |
+			((value & TIOCM_CAR) ? (1<<6) : 0) |
+			((value & TIOCM_RNG) ? (1<<5) : 0) |
+			((value & TIOCM_DSR) ? (1<<4) : 0) |
+			((value & TIOCM_CTS) ? (1<<3) : 0) |
+			((value & TIOCM_RTS) ? (1<<2) : 0);
+		rc = keyspan_pda_set_modem_info(serial, status);
+		if (rc < 0)
+			return rc;
+		return 0;
+	case TIOCMBIS: /* set bits in bitmask <arg> */
+	case TIOCMBIC: /* clear bits from bitmask <arg> */
+		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+			return -EFAULT;
+		rc = keyspan_pda_get_modem_info(serial, &status);
+		if (rc < 0)
+			return rc;
+		mask =
+			((value & TIOCM_RTS) ? (1<<2) : 0) |
+			((value & TIOCM_DTR) ? (1<<7) : 0);
+		if (cmd == TIOCMBIS)
+			status |= mask;
+		else
+			status &= ~mask;
+		rc = keyspan_pda_set_modem_info(serial, status);
+		if (rc < 0)
+			return rc;
+		return 0;
+	case TIOCMIWAIT:
+		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+		/* TODO */
+	case TIOCGICOUNT:
+		/* return count of modemline transitions */
+		return 0; /* TODO */
+	}
+	
+	return -ENOIOCTLCMD;
+}
+
+static int keyspan_pda_write(struct usb_serial_port *port, int from_user, 
+			     const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = port->serial;
+	int request_unthrottle = 0;
+	int rc = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* guess how much room is left in the device's ring buffer, and if we
+	   want to send more than that, check first, updating our notion of
+	   what is left. If our write will result in no room left, ask the
+	   device to give us an interrupt when the room available rises above
+	   a threshold, and hold off all writers (eventually, those using
+	   select() or poll() too) until we receive that unthrottle interrupt.
+	   Block if we can't write anything at all, otherwise write as much as
+	   we can. */
+
+	if (count == 0) {
+		dbg(" write request of 0 bytes");
+		return (0);
+	}
+
+	/* we might block because of:
+	   the TX urb is in-flight (wait until it completes)
+	   the device is full (wait until it says there is room)
+	*/
+	while (port->write_urb->status == -EINPROGRESS) {
+		if (0 /* file->f_flags & O_NONBLOCK */) {
+			rc = -EAGAIN;
+			goto err;
+		}
+		interruptible_sleep_on(&serial->write_wait);
+		if (signal_pending(current)) {
+			rc = -ERESTARTSYS;
+			goto err;
+		}
+	}
+
+	/* at this point the URB is in our control, nobody else can submit it
+	   again (the only sudden transition was the one from EINPROGRESS to
+	   finished) */
+
+	/* the next potential block is that our TX process might be throttled.
+	   The transition from throttled->not happens because of an Rx
+	   interrupt, and the wake_up occurs during the same interrupt, so we
+	   have to be careful to avoid a race that would cause us to sleep
+	   forever. */
+
+	add_wait_queue(&serial->write_wait, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (serial->tx_throttled) {
+		/* device can't accomodate any more characters. Sleep until it
+		   can. Woken up by an Rx interrupt message, which clears
+		   tx_throttled first. */
+		dbg(" tx_throttled, going to sleep");
+		if (signal_pending(current)) {
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&serial->write_wait, &wait);
+			dbg(" woke up because of signal");
+			rc = -ERESTARTSYS;
+			goto err;
+		}
+		schedule();
+		dbg(" woke up");
+	}
+	remove_wait_queue(&serial->write_wait, &wait);
+	set_current_state(TASK_RUNNING);
+
+	count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+	if (count > serial->tx_room) {
+		unsigned char room;
+		/* Looks like we might overrun the Tx buffer. Ask the device
+		   how much room it really has */
+		rc = usb_control_msg(serial->dev, 
+				     usb_rcvctrlpipe(serial->dev, 0),
+				     6, /* write_room */
+				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+				     | USB_DIR_IN,
+				     0, /* value: 0 means "remaining room" */
+				     0, /* index */
+				     &room,
+				     1,
+				     2*HZ);
+		if (rc < 0) {
+			dbg(" roomquery failed");
+			return rc; /* failed */
+		}
+		if (rc == 0) {
+			dbg(" roomquery returned 0 bytes");
+			return -EIO; /* device didn't return any data */
+		}
+		dbg(" roomquery says %d", room);
+		serial->tx_room = room;
+		if (count > serial->tx_room) {
+			/* we're about to completely fill the Tx buffer, so
+			   we'll be throttled afterwards. */
+			count = serial->tx_room;
+			request_unthrottle = 1;
+		}
+	}
+	serial->tx_room -= count;
+
+	if (count) {
+		/* now transfer data */
+		if (from_user) {
+			copy_from_user(port->write_urb->transfer_buffer, buf, count);
+		}
+		else {
+			memcpy (port->write_urb->transfer_buffer, buf, count);
+		}  
+		/* send the data out the bulk port */
+		port->write_urb->transfer_buffer_length = count;
+		
+		if (usb_submit_urb(port->write_urb))
+			dbg(" usb_submit_urb(write bulk) failed");
+	}
+	else {
+		/* There wasn't any room left, so we are throttled until
+		   the buffer empties a bit */
+		request_unthrottle = 1;
+	}
+
+	if (request_unthrottle) {
+		dbg(" request_unthrottle");
+		/* ask the device to tell us when the tx buffer becomes
+		   sufficiently empty */
+		serial->tx_throttled = 1; /* block writers */
+		rc = usb_control_msg(serial->dev, 
+				     usb_sndctrlpipe(serial->dev, 0),
+				     7, /* request_unthrottle */
+				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+				     | USB_DIR_OUT,
+				     16, /* value: threshold */
+				     0, /* index */
+				     NULL,
+				     0,
+				     2*HZ);
+	}
+
+	return (count);
+ err:
+	return (rc);
+}
+
+
+static void keyspan_pda_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+       	struct tty_struct *tty;
+
+	if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
+		return;
+	}
+	
+	wake_up_interruptible(&serial->write_wait);
+
+	tty = port->tty;
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+}
+
+
+static int keyspan_pda_write_room (struct usb_serial_port *port)
+{
+	struct usb_serial *serial = port->serial;
+
+	/* used by n_tty.c for processing of tabs and such. Giving it our
+	   conservative guess is probably good enough, but needs testing by
+	   running a console through the device. */
+
+	return (serial->tx_room);
+}
+
+
+static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
+{
+	struct usb_serial *serial = port->serial;
+	
+	/* when throttled, return at least WAKEUP_CHARS to tell select() (via
+	   n_tty.c:normal_poll() ) that we're not writeable. */
+	if (serial->tx_throttled)
+		return 256;
+	return 0;
+}
+
+
+static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+	unsigned char room;
+	int rc;
+
+	if (port->active) {
+		return -EINVAL;
+	}
+	port->active = 1;
+ 
+	/* find out how much room is in the Tx ring */
+	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     6, /* write_room */
+			     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+			     | USB_DIR_IN,
+			     0, /* value */
+			     0, /* index */
+			     &room,
+			     1,
+			     2*HZ);
+	if (rc < 0) {
+		dbg(" roomquery failed");
+		return rc; /* failed */
+	}
+	if (rc == 0) {
+		dbg(" roomquery returned 0 bytes");
+		return -EIO; /* device didn't return any data */
+	}
+	serial->tx_room = room;
+	serial->tx_throttled = room ? 0 : 1;
+
+	/* the normal serial device seems to always turn on DTR and RTS here,
+	   so do the same */
+	if (port->tty->termios->c_cflag & CBAUD)
+		keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
+	else
+		keyspan_pda_set_modem_info(serial, 0);
+
+	/*Start reading from the device*/
+	if (usb_submit_urb(port->read_urb))
+		dbg(" usb_submit_urb(read int) failed");
+
+	return (0);
+}
+
+
+static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+
+	/* the normal serial device seems to always shut off DTR and RTS now */
+	if (port->tty->termios->c_cflag & HUPCL)
+		keyspan_pda_set_modem_info(serial, 0);
+
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+	port->active = 0;
+}
+
+
+/* download the firmware to a "fake" device (pre-renumeration) */
+static int keyspan_pda_fake_startup (struct usb_serial *serial)
+{
+	int response;
+	const struct ezusb_hex_record *record;
+
+	/* download the firmware here ... */
+	response = ezusb_set_reset(serial, 1);
+
+	record = &keyspan_pda_firmware[0];
+	while(record->address != 0xffff) {
+		response = ezusb_writememory(serial, record->address,
+					     (unsigned char *)record->data,
+					     record->data_size, 0xa0);
+		if (response < 0) {
+			err("ezusb_writememory failed for Keyspan PDA "
+			    "firmware (%d %04X %p %d)",
+			    response, 
+			    record->address, record->data, record->data_size);
+			break;
+		}
+		record++;
+	}
+	/* bring device out of reset. Renumeration will occur in a moment
+	   and the new device will bind to the real driver */
+	response = ezusb_set_reset(serial, 0);
+
+	/* we want this device to fail to have a driver assigned to it. */
+	return (1);
+}
+
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int keyspan_pda_startup (struct usb_serial *serial)
+{
+	struct usb_endpoint_descriptor *intin;
+	intin = serial->port[0].interrupt_in_endpoint;
+
+	/* set up the receive interrupt urb */
+	FILL_INT_URB(serial->port[0].read_urb, serial->dev,
+		     usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
+		     serial->port[0].interrupt_in_buffer,
+		     intin->wMaxPacketSize,
+		     keyspan_pda_rx_interrupt,
+		     serial,
+		     intin->bInterval);
+
+	init_waitqueue_head(&serial->write_wait);
+	
+	return (0);
+}
+
+#endif	/* CONFIG_USB_SERIAL_KEYSPAN_PDA */
+
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/usb-serial.c linux/drivers/usb/serial/usb-serial.c
--- v2.3.99-pre3/linux/drivers/usb/serial/usb-serial.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/serial/usb-serial.c	Wed Dec 31 16:00:00 1969
@@ -1,2593 +0,0 @@
-/*
- * USB Serial Converter driver
- *
- *	(C) Copyright (C) 1999, 2000
- *	    Greg Kroah-Hartman (greg@kroah.com)
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- * This driver was originally based on the ACM driver by Armin Fuerst (which was 
- * based on a driver by Brad Keryan)
- *
- * See Documentation/usb/usb-serial.txt for more information on using this driver
- * 
- * (03/19/2000) gkh
- *	Fixed oops that could happen when device was removed while a program
- *	was talking to the device.
- *	Removed the static urbs and now all urbs are created and destroyed
- *	dynamically.
- *	Reworked the internal interface. Now everything is based on the 
- *	usb_serial_port structure instead of the larger usb_serial structure.
- *	This fixes the bug that a multiport device could not have more than
- *	one port open at one time.
- *
- * (03/17/2000) gkh
- *	Added config option for debugging messages.
- *	Added patch for keyspan pda from Brian Warner.
- *
- * (03/06/2000) gkh
- *	Added the keyspan pda code from Brian Warner <warner@lothar.com>
- *	Moved a bunch of the port specific stuff into its own structure. This
- *	is in anticipation of the true multiport devices (there's a bug if you
- *	try to access more than one port of any multiport device right now)
- *
- * (02/21/2000) gkh
- *	Made it so that any serial devices only have to specify which functions
- *	they want to overload from the generic function calls (great, 
- *	inheritance in C, in a driver, just what I wanted...)
- *	Added support for set_termios and ioctl function calls. No drivers take
- *	advantage of this yet.
- *	Removed the #ifdef MODULE, now there is no module specific code.
- *	Cleaned up a few comments in usb-serial.h that were wrong (thanks again
- *	to Miles Lott).
- *	Small fix to get_free_serial.
- *
- * (02/14/2000) gkh
- *	Removed the Belkin and Peracom functionality from the driver due to
- *	the lack of support from the vendor, and me not wanting people to 
- *	accidenatly buy the device, expecting it to work with Linux.
- *	Added read_bulk_callback and write_bulk_callback to the type structure
- *	for the needs of the FTDI and WhiteHEAT driver.
- *	Changed all reverences to FTDI to FTDI_SIO at the request of Bill
- *	Ryder.
- *	Changed the output urb size back to the max endpoint size to make
- *	the ftdi_sio driver have it easier, and due to the fact that it didn't
- *	really increase the speed any.
- *
- * (02/11/2000) gkh
- *	Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
- *	patch from Miles Lott (milos@insync.net).
- *	Fixed bug with not restoring the minor range that a device grabs, if
- *	the startup function fails (thanks Miles for finding this).
- *
- * (02/05/2000) gkh
- *	Added initial framework for the Keyspan PDA serial converter so that
- *	Brian Warner has a place to put his code.
- *	Made the ezusb specific functions generic enough that different
- *	devices can use them (whiteheat and keyspan_pda both need them).
- *	Split out a whole bunch of structure and other stuff to a seperate
- *	usb-serial.h file.
- *	Made the Visor connection messages a little more understandable, now
- *	that Miles Lott (milos@insync.net) has gotten the Generic channel to
- *	work. Also made them always show up in the log file.
- * 
- * (01/25/2000) gkh
- *	Added initial framework for FTDI serial converter so that Bill Ryder
- *	has a place to put his code.
- *	Added the vendor specific info from Handspring. Now we can print out
- *	informational debug messages as well as understand what is happening.
- *
- * (01/23/2000) gkh
- *	Fixed problem of crash when trying to open a port that didn't have a
- *	device assigned to it. Made the minor node finding a little smarter,
- *	now it looks to find a continous space for the new device.
- *
- * (01/21/2000) gkh
- *	Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
- *	Fixed get_serial_by_minor which was all messed up for multi port 
- *	devices. Fixed multi port problem for generic devices. Now the number
- *	of ports is determined by the number of bulk out endpoints for the
- *	generic device.
- *
- * (01/19/2000) gkh
- *	Removed lots of cruft that was around from the old (pre urb) driver 
- *	interface.
- *	Made the serial_table dynamic. This should save lots of memory when
- *	the number of minor nodes goes up to 256.
- *	Added initial support for devices that have more than one port. 
- *	Added more debugging comments for the Visor, and added a needed 
- *	set_configuration call.
- *
- * (01/17/2000) gkh
- *	Fixed the WhiteHEAT firmware (my processing tool had a bug)
- *	and added new debug loader firmware for it.
- *	Removed the put_char function as it isn't really needed.
- *	Added visor startup commands as found by the Win98 dump.
- * 
- * (01/13/2000) gkh
- *	Fixed the vendor id for the generic driver to the one I meant it to be.
- *
- * (01/12/2000) gkh
- *	Forget the version numbering...that's pretty useless...
- *	Made the driver able to be compiled so that the user can select which
- *	converter they want to use. This allows people who only want the Visor
- *	support to not pay the memory size price of the WhiteHEAT.
- *	Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
- *	grabbed the root hub. Not good.
- * 
- * version 0.4.0 (01/10/2000) gkh
- *	Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
- *	device. Added startup function to allow firmware to be downloaded to
- *	a device if it needs to be.
- *	Added firmware download logic to the WhiteHEAT device.
- *	Started to add #defines to split up the different drivers for potential
- *	configuration option.
- *	
- * version 0.3.1 (12/30/99) gkh
- *      Fixed problems with urb for bulk out.
- *      Added initial support for multiple sets of endpoints. This enables
- *      the Handspring Visor to be attached successfully. Only the first
- *      bulk in / bulk out endpoint pair is being used right now.
- *
- * version 0.3.0 (12/27/99) gkh
- *	Added initial support for the Handspring Visor based on a patch from
- *	Miles Lott (milos@sneety.insync.net)
- *	Cleaned up the code a bunch and converted over to using urbs only.
- *
- * version 0.2.3 (12/21/99) gkh
- *	Added initial support for the Connect Tech WhiteHEAT converter.
- *	Incremented the number of ports in expectation of getting the
- *	WhiteHEAT to work properly (4 ports per connection).
- *	Added notification on insertion and removal of what port the
- *	device is/was connected to (and what kind of device it was).
- *
- * version 0.2.2 (12/16/99) gkh
- *	Changed major number to the new allocated number. We're legal now!
- *
- * version 0.2.1 (12/14/99) gkh
- *	Fixed bug that happens when device node is opened when there isn't a
- *	device attached to it. Thanks to marek@webdesign.no for noticing this.
- *
- * version 0.2.0 (11/10/99) gkh
- *	Split up internals to make it easier to add different types of serial 
- *	converters to the code.
- *	Added a "generic" driver that gets it's vendor and product id
- *	from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
- *	for the idea and sample code (from the usb scanner driver.)
- *	Cleared up any licensing questions by releasing it under the GNU GPL.
- *
- * version 0.1.2 (10/25/99) gkh
- * 	Fixed bug in detecting device.
- *
- * version 0.1.1 (10/05/99) gkh
- * 	Changed the major number to not conflict with anything else.
- *
- * version 0.1 (09/28/99) gkh
- * 	Can recognize the two different devices and start up a read from
- *	device when asked to. Writes also work. No control signals yet, this
- *	all is vendor specific data (i.e. no spec), also no control for
- *	different baud rates or other bit settings.
- *	Currently we are using the same devid as the acm driver. This needs
- *	to change.
- * 
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-#include <linux/fcntl.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-
-#ifdef CONFIG_USB_SERIAL_DEBUG
-	#define DEBUG
-#else
-	#undef DEBUG
-#endif
-#include <linux/usb.h>
-
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-#include "whiteheat.h"		/* firmware for the ConnectTech WhiteHEAT device */
-#endif
-
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-struct ezusb_hex_record {
-	__u16 address;
-	__u8 data_size;
-	__u8 data[16];
-};
-#include "keyspan_pda_fw.h"
-#endif
-
-#include "usb-serial.h"
-
-/* parity check flag */
-#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-/* local function prototypes */
-static int  serial_open (struct tty_struct *tty, struct file * filp);
-static void serial_close (struct tty_struct *tty, struct file * filp);
-static int  serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
-static int  serial_write_room (struct tty_struct *tty);
-static int  serial_chars_in_buffer (struct tty_struct *tty);
-static void serial_throttle (struct tty_struct * tty);
-static void serial_unthrottle (struct tty_struct * tty);
-static int  serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
-static void serial_set_termios (struct tty_struct *tty, struct termios * old);
-
-static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
-static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
-
-static struct usb_driver usb_serial_driver = {
-	name:		"serial",
-	probe:		usb_serial_probe,
-	disconnect:	usb_serial_disconnect,
-};
-
-static int			serial_refcount;
-static struct tty_struct *	serial_tty[SERIAL_TTY_MINORS];
-static struct termios *		serial_termios[SERIAL_TTY_MINORS];
-static struct termios *		serial_termios_locked[SERIAL_TTY_MINORS];
-static struct usb_serial	*serial_table[SERIAL_TTY_MINORS] = {NULL, };
-
-
-static inline int serial_paranoia_check (struct usb_serial *serial, const char *function)
-{
-	if (!serial) {
-		dbg("%s - serial == NULL", function);
-		return -1;
-	}
-	if (serial->magic != USB_SERIAL_MAGIC) {
-		dbg("%s - bad magic number for serial", function);
-		return -1;
-	}
-	if (!serial->type) {
-		dbg("%s - serial->type == NULL!", function);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static inline int port_paranoia_check (struct usb_serial_port *port, const char *function)
-{
-	if (!port) {
-		dbg("%s - port == NULL", function);
-		return -1;
-	}
-	if (port->magic != USB_SERIAL_PORT_MAGIC) {
-		dbg("%s - bad magic number for port", function);
-		return -1;
-	}
-	if (!port->serial) {
-		dbg("%s - port->serial == NULL", function);
-		return -1;
-	}
-	if (!port->tty) {
-		dbg("%s - port->tty == NULL", function);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static struct usb_serial *get_serial_by_minor (int minor)
-{
-	return serial_table[minor];
-}
-
-
-static struct usb_serial *get_free_serial (int num_ports, int *minor)
-{
-	struct usb_serial *serial = NULL;
-	int i, j;
-	int good_spot;
-
-	dbg("get_free_serial %d", num_ports);
-
-	*minor = 0;
-	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
-		if (serial_table[i])
-			continue;
-
-		good_spot = 1;
-		for (j = 1; j <= num_ports-1; ++j)
-			if (serial_table[i+j])
-				good_spot = 0;
-		if (good_spot == 0)
-			continue;
-			
-		if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
-			err("Out of memory");
-			return NULL;
-		}
-		memset(serial, 0, sizeof(struct usb_serial));
-		serial->magic = USB_SERIAL_MAGIC;
-		serial_table[i] = serial;
-		*minor = i;
-		dbg("minor base = %d", *minor);
-		for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
-			serial_table[i] = serial;
-		return serial;
-		}
-	return NULL;
-}
-
-
-static void return_serial (struct usb_serial *serial)
-{
-	int i;
-
-	dbg("return_serial");
-
-	if (serial == NULL)
-		return;
-
-	for (i = 0; i < serial->num_ports; ++i) {
-		serial_table[serial->minor + i] = NULL;
-	}
-
-	return;
-}
-
-
-#ifdef USES_EZUSB_FUNCTIONS
-/* EZ-USB Control and Status Register.  Bit 0 controls 8051 reset */
-#define CPUCS_REG    0x7F92
-
-static int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest)
-{
-	int result;
-	unsigned char *transfer_buffer =  kmalloc (length, GFP_KERNEL);
-
-//	dbg("ezusb_writememory %x, %d", address, length);
-
-	if (!transfer_buffer) {
-		err("ezusb_writememory: kmalloc(%d) failed.", length);
-		return -ENOMEM;
-	}
-	memcpy (transfer_buffer, data, length);
-	result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
-	kfree (transfer_buffer);
-	return result;
-}
-
-
-static int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
-{
-	int	response;
-	dbg("ezusb_set_reset: %d", reset_bit);
-	response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
-	if (response < 0) {
-		err("ezusb_set_reset %d failed", reset_bit);
-	}
-	return response;
-}
-
-#endif	/* USES_EZUSB_FUNCTIONS */
-
-
-/*****************************************************************************
- * Driver tty interface functions
- *****************************************************************************/
-static int serial_open (struct tty_struct *tty, struct file * filp)
-{
-	struct usb_serial *serial;
-	struct usb_serial_port *port;
-	int portNumber;
-	
-	dbg("serial_open");
-
-	/* initialize the pointer incase something fails */
-	tty->driver_data = NULL;
-
-	/* get the serial object associated with this tty pointer */
-	serial = get_serial_by_minor (MINOR(tty->device));
-
-	if (serial_paranoia_check (serial, "serial_open")) {
-		return -ENODEV;
-	}
-
-	/* set up our port structure */
-	portNumber = MINOR(tty->device) - serial->minor;
-	port = &serial->port[portNumber];
-	port->number = portNumber;
-	port->serial = serial;
-	port->magic = USB_SERIAL_PORT_MAGIC;
-	
-	/* make the tty driver remember our port object, and us it */
-	tty->driver_data = port;
-	port->tty = tty;
-	 
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->open) {
-		return (serial->type->open(port, filp));
-	} else {
-		return (generic_open(port, filp));
-	}
-}
-
-
-static void serial_close(struct tty_struct *tty, struct file * filp)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-
-	dbg("serial_close");
-
-	if (port_paranoia_check (port, "serial_close")) {
-		return;
-	}
-
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_close")) {
-		return;
-	}
-
-	dbg("serial_close port %d", port->number);
-	
-	if (!port->active) {
-		dbg ("port not opened");
-		return;
-	}
-
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->close) {
-		serial->type->close(port, filp);
-	} else {
-		generic_close(port, filp);
-	}
-}	
-
-
-static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_write");
-	
-	if (port_paranoia_check (port, "serial_write")) {
-		return -ENODEV;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_write")) {
-		return -ENODEV;
-	}
-	
-	dbg("serial_write port %d, %d byte(s)", port->number, count);
-
-	if (!port->active) {
-		dbg ("port not opened");
-		return -EINVAL;
-	}
-	
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->write) {
-		return (serial->type->write(port, from_user, buf, count));
-	} else {
-		return (generic_write(port, from_user, buf, count));
-	}
-}
-
-
-static int serial_write_room (struct tty_struct *tty) 
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_write_room");
-	
-	if (port_paranoia_check (port, "serial_write")) {
-		return -ENODEV;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_write")) {
-		return -ENODEV;
-	}
-	
-	dbg("serial_write_room port %d", port->number);
-	
-	if (!port->active) {
-		dbg ("port not open");
-		return -EINVAL;
-	}
-	
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->write_room) {
-		return (serial->type->write_room(port));
-	} else {
-		return (generic_write_room(port));
-	}
-}
-
-
-static int serial_chars_in_buffer (struct tty_struct *tty) 
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_chars_in_buffer");
-	
-	if (port_paranoia_check (port, "serial_chars_in_buffer")) {
-		return -ENODEV;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
-		return -ENODEV;
-	}
-	
-	if (!port->active) {
-		dbg ("port not open");
-		return -EINVAL;
-	}
-	
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->chars_in_buffer) {
-		return (serial->type->chars_in_buffer(port));
-	} else {
-		return (generic_chars_in_buffer(port));
-	}
-}
-
-
-static void serial_throttle (struct tty_struct * tty)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_throttle");
-	
-	if (port_paranoia_check (port, "serial_throttle")) {
-		return;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_throttle")) {
-		return;
-	}
-	
-	dbg("serial_throttle port %d", port->number);
-	
-	if (!port->active) {
-		dbg ("port not open");
-		return;
-	}
-
-	/* pass on to the driver specific version of this function */
-	if (serial->type->throttle) {
-		serial->type->throttle(port);
-	}
-
-	return;
-}
-
-
-static void serial_unthrottle (struct tty_struct * tty)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_unthrottle");
-	
-	if (port_paranoia_check (port, "serial_unthrottle")) {
-		return;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_unthrottle")) {
-		return;
-	}
-	
-	dbg("serial_unthrottle port %d", port->number);
-	
-	if (!port->active) {
-		dbg ("port not open");
-		return;
-	}
-
-	/* pass on to the driver specific version of this function */
-	if (serial->type->unthrottle) {
-		serial->type->unthrottle(port);
-	}
-
-	return;
-}
-
-
-static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_ioctl");
-	
-	if (port_paranoia_check (port, "serial_ioctl")) {
-		return -ENODEV;
-	}
-
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_ioctl")) {
-		return -ENODEV;
-	}
-	
-	dbg("serial_ioctl port %d", port->number);
-	
-	if (!port->active) {
-		dbg ("port not open");
-		return -ENODEV;
-	}
-
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->ioctl) {
-		return (serial->type->ioctl(port, file, cmd, arg));
-	} else {
-		return -ENOIOCTLCMD;
-	}
-}
-
-
-static void serial_set_termios (struct tty_struct *tty, struct termios * old)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_set_termios");
-	
-	if (port_paranoia_check (port, "serial_set_termios")) {
-		return;
-	}
-
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_set_termios")) {
-		return;
-	}
-
-	dbg("serial_set_termios port %d", port->number);
-
-	if (!port->active) {
-		dbg ("port not open");
-		return;
-	}
-
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->set_termios) {
-		serial->type->set_termios(port, old);
-	}
-	
-	return;
-}
-
-
-static void serial_break (struct tty_struct *tty, int break_state)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_break");
-	
-	if (port_paranoia_check (port, "serial_break")) {
-		return;
-	}
-
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_break")) {
-		return;
-	}
-
-	dbg("serial_break port %d", port->number);
-
-	if (!port->active) {
-		dbg ("port not open");
-		return;
-	}
-
-	/* pass on to the driver specific version of this function if it is
-           available */
-	if (serial->type->break_ctl) {
-		serial->type->break_ctl(port, break_state);
-	}
-}
-
-
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-/*****************************************************************************
- * Connect Tech's White Heat specific driver functions
- *****************************************************************************/
-static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
-{
-	dbg("whiteheat_open port %d", port->number);
-
-	if (port->active) {
-		dbg ("device already open");
-		return -EINVAL;
-	}
-	port->active = 1;
- 
-	/*Start reading from the device*/
-	if (usb_submit_urb(port->read_urb))
-		dbg("usb_submit_urb(read bulk) failed");
-
-	/* Need to do device specific setup here (control lines, baud rate, etc.) */
-	/* FIXME!!! */
-
-	return (0);
-}
-
-
-static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
-{
-	dbg("whiteheat_close port %d", port->number);
-	
-	/* Need to change the control lines here */
-	/* FIXME */
-	
-	/* shutdown our bulk reads and writes */
-	usb_unlink_urb (port->write_urb);
-	usb_unlink_urb (port->read_urb);
-	port->active = 0;
-}
-
-
-static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
-{
-	unsigned int cflag = port->tty->termios->c_cflag;
-
-	dbg("whiteheat_set_termios port %d", port->number);
-
-	/* check that they really want us to change something */
-	if (old_termios) {
-		if ((cflag == old_termios->c_cflag) &&
-		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg("nothing to change...");
-			return;
-		}
-	}
-
-	/* do the parsing of the cflag to see what to set the line to */
-	/* FIXME!! */
-
-	return;
-}
-
-static void whiteheat_throttle (struct usb_serial_port *port)
-{
-	dbg("whiteheat_throttle port %d", port->number);
-
-	/* Change the control signals */
-	/* FIXME!!! */
-
-	return;
-}
-
-
-static void whiteheat_unthrottle (struct usb_serial_port *port)
-{
-	dbg("whiteheat_unthrottle port %d", port->number);
-
-	/* Change the control signals */
-	/* FIXME!!! */
-
-	return;
-}
-
-
-/* steps to download the firmware to the WhiteHEAT device:
- - hold the reset (by writing to the reset bit of the CPUCS register)
- - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
- - release the reset (by writing to the CPUCS register)
- - download the WH.HEX file for all addresses greater than 0x1b3f using
-   VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
- - hold the reset
- - download the WH.HEX file for all addresses less than 0x1b40 using
-   VENDOR_REQUEST_ANCHOR_LOAD
- - release the reset
- - device renumerated itself and comes up as new device id with all
-   firmware download completed.
-*/
-static int  whiteheat_startup (struct usb_serial *serial)
-{
-	int response;
-	const struct whiteheat_hex_record *record;
-	
-	dbg("whiteheat_startup");
-	
-	response = ezusb_set_reset (serial, 1);
-
-	record = &whiteheat_loader[0];
-	while (record->address != 0xffff) {
-		response = ezusb_writememory (serial, record->address, 
-				(unsigned char *)record->data, record->data_size, 0xa0);
-		if (response < 0) {
-			err("ezusb_writememory failed for loader (%d %04X %p %d)", 
-				response, record->address, record->data, record->data_size);
-			break;
-		}
-		++record;
-	}
-
-	response = ezusb_set_reset (serial, 0);
-
-	record = &whiteheat_firmware[0];
-	while (record->address < 0x1b40) {
-		++record;
-	}
-	while (record->address != 0xffff) {
-		response = ezusb_writememory (serial, record->address, 
-				(unsigned char *)record->data, record->data_size, 0xa0);
-		if (response < 0) {
-			err("ezusb_writememory failed for first firmware step (%d %04X %p %d)", 
-				response, record->address, record->data, record->data_size);
-			break;
-		}
-		++record;
-	}
-	
-	response = ezusb_set_reset (serial, 1);
-
-	record = &whiteheat_firmware[0];
-	while (record->address < 0x1b40) {
-		response = ezusb_writememory (serial, record->address, 
-				(unsigned char *)record->data, record->data_size, 0xa0);
-		if (response < 0) {
-			err("ezusb_writememory failed for second firmware step (%d %04X %p %d)", 
-				response, record->address, record->data, record->data_size);
-			break;
-		}
-		++record;
-	}
-
-	response = ezusb_set_reset (serial, 0);
-
-	/* we want this device to fail to have a driver assigned to it. */
-	return (1);
-}
-#endif	/* CONFIG_USB_SERIAL_WHITEHEAT */
-
-
-#ifdef CONFIG_USB_SERIAL_VISOR
-/******************************************************************************
- * Handspring Visor specific driver functions
- ******************************************************************************/
-static int visor_open (struct usb_serial_port *port, struct file *filp)
-{
-	dbg("visor_open port %d", port->number);
-
-	if (port->active) {
-		dbg ("device already open");
-		return -EINVAL;
-	}
-
-	port->active = 1;
-
-	/*Start reading from the device*/
-	if (usb_submit_urb(port->read_urb))
-		dbg("usb_submit_urb(read bulk) failed");
-
-	return (0);
-}
-
-
-static void visor_close (struct usb_serial_port *port, struct file * filp)
-{
-	struct usb_serial *serial = port->serial;
-	unsigned char *transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
-	
-	dbg("visor_close port %d", port->number);
-			 
-	if (!transfer_buffer) {
-		err("visor_close: kmalloc(%d) failed.", 0x12);
-	} else {
-		/* send a shutdown message to the device */
-		usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
-				0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
-	}
-
-	/* shutdown our bulk reads and writes */
-	usb_unlink_urb (port->write_urb);
-	usb_unlink_urb (port->read_urb);
-	port->active = 0;
-}
-
-
-static void visor_throttle (struct usb_serial_port *port)
-{
-	dbg("visor_throttle port %d", port->number);
-
-	usb_unlink_urb (port->read_urb);
-
-	return;
-}
-
-
-static void visor_unthrottle (struct usb_serial_port *port)
-{
-	dbg("visor_unthrottle port %d", port->number);
-
-	if (usb_unlink_urb (port->read_urb))
-		dbg("usb_submit_urb(read bulk) failed");
-
-	return;
-}
-
-
-static int  visor_startup (struct usb_serial *serial)
-{
-	int response;
-	int i;
-	unsigned char *transfer_buffer =  kmalloc (256, GFP_KERNEL);
-
-	if (!transfer_buffer) {
-		err("visor_startup: kmalloc(%d) failed.", 256);
-		return -ENOMEM;
-	}
-
-	dbg("visor_startup");
-
-	dbg("visor_setup: Set config to 1");
-	usb_set_configuration (serial->dev, 1);
-
-	/* send a get connection info request */
-	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
-					0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
-	if (response < 0) {
-		err("visor_startup: error getting connection information");
-	} else {
-		struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
-		char *string;
-		info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
-		for (i = 0; i < connection_info->num_ports; ++i) {
-			switch (connection_info->connections[i].port_function_id) {
-				case VISOR_FUNCTION_GENERIC:
-					string = "Generic";
-					break;
-				case VISOR_FUNCTION_DEBUGGER:
-					string = "Debugger";
-					break;
-				case VISOR_FUNCTION_HOTSYNC:
-					string = "HotSync";
-					break;
-				case VISOR_FUNCTION_CONSOLE:
-					string = "Console";
-					break;
-				case VISOR_FUNCTION_REMOTE_FILE_SYS:
-					string = "Remote File System";
-					break;
-				default:
-					string = "unknown";
-					break;	
-			}
-			info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name, connection_info->connections[i].port, string, serial->minor + i);
-		}
-	}
-
-	/* ask for the number of bytes available, but ignore the response as it is broken */
-	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
-					0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
-	if (response < 0) {
-		err("visor_startup: error getting bytes available request");
-	}
-
-	kfree (transfer_buffer);
-
-	/* continue on with initialization */
-	return (0);
-}
-
-
-#endif	/* CONFIG_USB_SERIAL_VISOR*/
-
-
-#ifdef CONFIG_USB_SERIAL_FTDI_SIO
-/******************************************************************************
- * FTDI SIO Serial Converter specific driver functions
- ******************************************************************************/
-
-/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
-/* Thanx to FTDI for so kindly providing details of the protocol required */
-/*   to talk to the device */
-
-#include "ftdi_sio.h"
-
-static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
-{
-	struct usb_serial *serial = port->serial;
-	char buf[1]; /* Needed for the usb_control_msg I think */
-
-	dbg("ftdi_sio_open port %d", port->number);
-
-	if (port->active) {
-		dbg ("port already open");
-		return -EINVAL;
-	}
-	port->active = 1;
-
-	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
-			FTDI_SIO_RESET_SIO, 
-			0, buf, 0, HZ * 5);
-
-	/* FIXME - Should I really purge the buffers? */
-	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
-			FTDI_SIO_RESET_PURGE_RX, 
-			0, buf, 0, HZ * 5);
-
-	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
-			FTDI_SIO_RESET_PURGE_TX, 
-			0, buf, 0, HZ * 5);	
-
-
-	/* As per usb_serial_init s/be CS8, B9600, 1 STOP BIT */
-	if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			     FTDI_SIO_SET_BAUDRATE_REQUEST,
-			     FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
-			     ftdi_sio_b9600, 0, 
-			     buf, 0, HZ * 5) < 0){
-		dbg("Error from baudrate urb");
-		return(-EINVAL);
-	}
-
-	if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			     FTDI_SIO_SET_DATA_REQUEST, 
-			     FTDI_SIO_SET_DATA_REQUEST_TYPE,
-			     8 | FTDI_SIO_SET_DATA_PARITY_NONE | 
-			     FTDI_SIO_SET_DATA_STOP_BITS_1, 0,
-			     buf, 0, HZ * 5) < 0){
-		dbg("Error from cs8/noparity/1 stopbit urb");
-		return(-EINVAL);
-	}
-
-	/* Disable flow control */
-	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
-			    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-			    0, 0, 
-			    buf, 0, HZ * 5) < 0) {
-		dbg("error from flowcontrol urb");
-		return(-EINVAL);
-	}	    
-
-	/* Turn on RTS and DTR since we are not flow controlling*/
-	/* FIXME - check for correct behaviour clocal vs non clocal */
-	/* FIXME - might be able to do both simultaneously */
-	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-			    (unsigned)FTDI_SIO_SET_DTR_HIGH, 0, 
-			    buf, 0, HZ * 5) < 0) {
-		dbg("Error from DTR HIGH urb");
-	}
-	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-			    (unsigned)FTDI_SIO_SET_RTS_HIGH, 0, 
-			    buf, 0, HZ * 5) < 0) {
-		dbg("Error from RTS HIGH urb");
-	}
-	
-	/*Start reading from the device*/
-	if (usb_submit_urb(port->read_urb))
-		dbg("usb_submit_urb(read bulk) failed");
-
-	return (0);
-}
-
-
-static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
-{
-	struct usb_serial *serial = port->serial;
-	char buf[1];
-
-	dbg("ftdi_sio_close port %d", port->number);
-	
-	/* FIXME - might be able to do both simultaneously */
-	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-			    (unsigned)FTDI_SIO_SET_DTR_LOW, 0, 
-			    buf, 0, HZ * 5) < 0) {
-		dbg("Error from DTR LOW urb");
-	}
-	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-			    (unsigned)FTDI_SIO_SET_RTS_LOW, 0, 
-			    buf, 0, HZ * 5) < 0) {
-		dbg("Error from RTS LOW urb");
-	}	
-
-	/* FIXME Should I flush the device here? - not doing it for now */
-
-	/* shutdown our bulk reads and writes */
-	usb_unlink_urb (port->write_urb);
-	usb_unlink_urb (port->read_urb);
-	port->active = 0;
-}
-
-
-  
-/* The ftdi_sio requires the first byte to have:
-   B0 1
-   B1 0
-   B2..7 length of message excluding byte 0
-*/
-static int ftdi_sio_write (struct usb_serial_port *port, int from_user, 
-			   const unsigned char *buf, int count)
-{
-	struct usb_serial *serial = port->serial;
-	const int data_offset = 1;
-
-	dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
-
-	if (count == 0) {
-		dbg("write request of 0 bytes");
-		return 0;
-	}
-
-	/* only do something if we have a bulk out endpoint */
-	if (serial->num_bulk_out) {
-		unsigned char *first_byte = port->write_urb->transfer_buffer;
-
-		if (port->write_urb->status == -EINPROGRESS) {
-			dbg ("already writing");
-			return 0;
-		}
-
-		count += data_offset;
-		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-		if (count == 0) {
-			return 0;
-		}
-
-		/* Copy in the data to send */
-		if (from_user) {
-			copy_from_user(port->write_urb->transfer_buffer + data_offset , 
-				       buf, count - data_offset );
-		}
-		else {
-			memcpy(port->write_urb->transfer_buffer + data_offset,
-			       buf, count - data_offset );
-		}  
-
-		/* Write the control byte at the front of the packet*/
-		first_byte = port->write_urb->transfer_buffer;
-		*first_byte = 1 | ((count-data_offset) << 2) ; 
-
-#ifdef DEBUG
-		dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
-
-		if (count) {
-			int i;
-			printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count);
-			for (i = 0; i < count; ++i) {
-				printk ("0x%02x ", first_byte[i]);
-				if (first_byte[i] > ' ' && first_byte[i] < '~') {
-					printk("%c ", first_byte[i]);
-				} else {
-					printk("  ");
-				}
-			}
-
-		     
-			printk ("\n");
-		}
-
-#endif
-		/* send the data out the bulk port */
-		port->write_urb->transfer_buffer_length = count;
-
-		if (usb_submit_urb(port->write_urb))
-			dbg("usb_submit_urb(write bulk) failed");
-
-		dbg("write returning: %d", count - data_offset);
-		return (count - data_offset);
-	}
-	
-	/* no bulk out, so return 0 bytes written */
-	return 0;
-} 
-
-
-static void ftdi_sio_read_bulk_callback (struct urb *urb)
-{ /* ftdi_sio_serial_buld_callback */
-	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial;
-       	struct tty_struct *tty;
-       	unsigned char *data = urb->transfer_buffer;
-	const int data_offset = 2;
-	int i;
-
-	dbg("ftdi_sio_read_bulk_callback");
-
-	if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
-		return;
-	}
-
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
-		return;
-	}
-	
-	if (urb->status) {
-		dbg("nonzero read bulk status received: %d", urb->status);
-		return;
-	}
-
-#ifdef DEBUG
-	if (urb->actual_length > 2) {
-		printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
-		for (i = 0; i < urb->actual_length; ++i) {
-			printk ("0x%.2x ", data[i]);
-			if (data[i] > ' ' && data[i] < '~') {
-				printk("%c ", data[i]);
-			} else {
-				printk("  ");
-			}
-		}
-		printk ("\n");
-	}
-#endif
-	
-
-	if (urb->actual_length > data_offset) {
-		tty = port->tty;
-		for (i = data_offset ; i < urb->actual_length ; ++i) {
-			tty_insert_flip_char(tty, data[i], 0);
-	  	}
-	  	tty_flip_buffer_push(tty);
-	}
-
-	/* Continue trying to always read  */
-	if (usb_submit_urb(urb))
-		dbg("failed resubmitting read urb");
-
-	return;
-} /* ftdi_sio_serial_read_bulk_callback */
-
-
-static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
-{
-	struct usb_serial *serial = port->serial;
-	unsigned int cflag = port->tty->termios->c_cflag;
-	__u16 urb_value; /* Will hold the new flags */
-	char buf[1]; /* Perhaps I should dynamically alloc this? */
-	
-	dbg("ftdi_sio_set_termios port %d", port->number);
-
-	/* FIXME - we should keep the old termios really */
-	/* FIXME -For this cut I don't care if the line is really changing or 
-	   not  - so just do the change regardless */
-	
-	/* Set number of data bits, parity, stop bits */
-	
-	urb_value = 0;
-	urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
-		      FTDI_SIO_SET_DATA_STOP_BITS_1);
-	urb_value |= (cflag & PARENB ? 
-		      (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : 
-		       FTDI_SIO_SET_DATA_PARITY_EVEN) :
-		      FTDI_SIO_SET_DATA_PARITY_NONE);
-	if (cflag & CSIZE) {
-		switch (cflag & CSIZE) {
-		case CS5: urb_value |= 5; dbg("Setting CS5"); break;
-		case CS6: urb_value |= 6; dbg("Setting CS6"); break;
-		case CS7: urb_value |= 7; dbg("Setting CS7"); break;
-		case CS8: urb_value |= 8; dbg("Setting CS8"); break;
-		default:
-			dbg("CSIZE was set but not CS5-CS8");
-		}
-	}
-	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			    FTDI_SIO_SET_DATA_REQUEST, 
-			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
-			    urb_value , 0,
-			    buf, 0, 100) < 0) {
-		dbg("FAILED to set databits/stopbits/parity");
-	}	   
-
-	/* Now do the baudrate */
-	/* FIXME - should drop lines on B0 */
-	/* FIXME Should also handle CLOCAL here  */
-     
-	switch(cflag & CBAUD){
-	case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
-	case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
-	case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
-	case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
-	case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
-	case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
-	case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
-	case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
-	case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
-	case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
-	default: dbg("FTDI_SIO does not support the baudrate requested"); 
-		/* FIXME - how to return an error for this? */ break;
-	}
-	/* Send the URB */
-	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			    FTDI_SIO_SET_BAUDRATE_REQUEST, 
-			    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
-			    urb_value, 0, 
-			    buf, 0, 100) < 0) {
-		dbg("urb failed to set baurdrate");
-	}
-	return;
-}
-
-
-/*FIXME - the beginnings of this implementation - not even hooked into the driver yet */
-static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
-{
-	struct usb_serial *serial = port->serial;
-	__u16 urb_value=0; /* Will hold the new flags */
-	char buf[1];
-	int  ret, mask;
-	
-	dbg("ftdi_sio_ioctl port %d", port->number);
-
-	/* Based on code from acm.c */
-	switch (cmd) {
-
-		case TIOCMGET:
-			/* Request the status from the device */
-			if ((ret = usb_control_msg(serial->dev, 
-					    usb_sndctrlpipe(serial->dev, 0),
-					    FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
-					    FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-					    0, 0, 
-					    buf, 1, HZ * 5)) < 0 ) {
-				dbg("Get not get modem status of device");
-				return(ret);
-			}
-
-			return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
-					(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
-					(buf[0]  & FTDI_SIO_RI_MASK  ? TIOCM_RI  : 0) |
-					(buf[0]  & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0),
-					(unsigned long *) arg);
-			break;
-
-		case TIOCMSET:
-		case TIOCMBIS:
-		case TIOCMBIC:
-			if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
-
-			/* FIXME Need to remember if we have set DTR or RTS since we
-			   can't ask the device  */
-			/* FIXME - also need to find the meaning of TIOCMBIS/BIC/SET */
-			if (mask & TIOCM_DTR) {
-				switch(cmd) {
-				case TIOCMSET:
-					urb_value = FTDI_SIO_SET_DTR_HIGH | FTDI_SIO_SET_RTS_LOW;
-					break;
-
-				case TIOCMBIS:
-					/* Will leave RTS alone and set DTR */
-					urb_value =  FTDI_SIO_SET_DTR_HIGH;
-					break;
-					
-				case TIOCMBIC:
-					urb_value = FTDI_SIO_SET_DTR_LOW;
-					break;
-				}
-			}
-
-			if (mask & TIOCM_RTS) {
-				switch(cmd) {
-				case TIOCMSET:
-					urb_value = FTDI_SIO_SET_DTR_LOW | FTDI_SIO_SET_RTS_HIGH;
-					break;
-
-				case TIOCMBIS:
-					/* Will leave DTR and set RTS */
-					urb_value = FTDI_SIO_SET_RTS_HIGH;
-					break;
-
-				case TIOCMBIC:
-					/* Will unset RTS */
-					urb_value = FTDI_SIO_SET_RTS_LOW;
-					break;
-				}
-			}	
-
-			
-			return(usb_control_msg(serial->dev, 
-					       usb_sndctrlpipe(serial->dev, 0),
-					       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-					       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-					       urb_value , 0,
-					       buf, 0, HZ * 5));
-	}
-
-	return -ENOIOCTLCMD;
-}
-
-#endif	/* CONFIG_USB_SERIAL_FTDI_SIO */
-
-
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-/*****************************************************************************
- * Keyspan PDA specific driver functions
- *****************************************************************************/
-
-static void keyspan_pda_rx_interrupt (struct urb *urb)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial;
-       	struct tty_struct *tty;
-	unsigned char *data = urb->transfer_buffer;
-	int i;
-
-	/* the urb might have been killed. */
-	if (urb->status)
-		return;
-	
-	if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
-		return;
-	}
-
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
-		return;
-	}
-	
- 	/* see if the message is data or a status interrupt */
-	switch (data[0]) {
-	case 0:
-		/* rest of message is rx data */
-		if (urb->actual_length) {
-			tty = serial->port[0].tty;
-			for (i = 1; i < urb->actual_length ; ++i) {
-				tty_insert_flip_char(tty, data[i], 0);
-			}
-			tty_flip_buffer_push(tty);
-		}
-		break;
-	case 1:
-		/* status interrupt */
-		dbg(" rx int, d1=%d, d2=%d", data[1], data[2]);
-		switch (data[1]) {
-		case 1: /* modemline change */
-			break;
-		case 2: /* tx unthrottle interrupt */
-			tty = serial->port[0].tty;
-			serial->tx_throttled = 0;
-			wake_up(&serial->write_wait); /* wake up writer */
-			wake_up(&tty->write_wait); /* them too */
-			break;
-		default:
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-
-	/* INT urbs are automatically re-submitted */
-}
-
-
-static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
-{
-	/* stop receiving characters. We just turn off the URB request, and
-	   let chars pile up in the device. If we're doing hardware
-	   flowcontrol, the device will signal the other end when its buffer
-	   fills up. If we're doing XON/XOFF, this would be a good time to
-	   send an XOFF, although it might make sense to foist that off
-	   upon the device too. */
-
-	dbg("keyspan_pda_rx_throttle port %d", port->number);
-	usb_unlink_urb(port->read_urb);
-}
-
-
-static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
-{
-	/* just restart the receive interrupt URB */
-	dbg("keyspan_pda_rx_unthrottle port %d", port->number);
-	if (usb_submit_urb(port->read_urb))
-		dbg(" usb_submit_urb(read urb) failed");
-	return;
-}
-
-
-static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
-{
-	int rc;
-	int bindex;
-
-	switch(baud) {
-		case 110: bindex = 0; break;
-		case 300: bindex = 1; break;
-		case 1200: bindex = 2; break;
-		case 2400: bindex = 3; break;
-		case 4800: bindex = 4; break;
-		case 9600: bindex = 5; break;
-		case 19200: bindex = 6; break;
-		case 38400: bindex = 7; break;
-		case 57600: bindex = 8; break;
-		case 115200: bindex = 9; break;
-		default: return -EINVAL;
-	}
-
-	/* rather than figure out how to sleep while waiting for this
-	   to complete, I just use the "legacy" API. */
-	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			     0, /* set baud */
-			     USB_TYPE_VENDOR 
-			     | USB_RECIP_INTERFACE
-			     | USB_DIR_OUT, /* type */
-			     bindex, /* value */
-			     0, /* index */
-			     NULL, /* &data */
-			     0, /* size */
-			     2*HZ); /* timeout */
-	return(rc);
-}
-
-
-static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state)
-{
-	struct usb_serial *serial = port->serial;
-	int value;
-	if (break_state == -1)
-		value = 1; /* start break */
-	else
-		value = 0; /* clear break */
-	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			4, /* set break */
-			USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
-			value, 0, NULL, 0, 2*HZ);
-	/* there is something funky about this.. the TCSBRK that 'cu' performs
-	   ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
-	   seconds apart, but it feels like the break sent isn't as long as it
-	   is on /dev/ttyS0 */
-}
-
-
-static void keyspan_pda_set_termios (struct usb_serial_port *port, 
-				     struct termios *old_termios)
-{
-	struct usb_serial *serial = port->serial;
-	unsigned int cflag = port->tty->termios->c_cflag;
-
-	/* cflag specifies lots of stuff: number of stop bits, parity, number
-	   of data bits, baud. What can the device actually handle?:
-	   CSTOPB (1 stop bit or 2)
-	   PARENB (parity)
-	   CSIZE (5bit .. 8bit)
-	   There is minimal hw support for parity (a PSW bit seems to hold the
-	   parity of whatever is in the accumulator). The UART either deals
-	   with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
-	   1 special, stop). So, with firmware changes, we could do:
-	   8N1: 10 bit
-	   8N2: 11 bit, extra bit always (mark?)
-	   8[EOMS]1: 11 bit, extra bit is parity
-	   7[EOMS]1: 10 bit, b0/b7 is parity
-	   7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
-
-	   HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
-	   bit.
-
-	   For now, just do baud. */
-
-	switch (cflag & CBAUD) {
-		/* we could support more values here, just need to calculate
-		   the necessary divisors in the firmware. <asm/termbits.h>
-		   has the Bnnn constants. */
-		case B110: keyspan_pda_setbaud(serial, 110); break;
-		case B300: keyspan_pda_setbaud(serial, 300); break;
-		case B1200: keyspan_pda_setbaud(serial, 1200); break;
-		case B2400: keyspan_pda_setbaud(serial, 2400); break;
-		case B4800: keyspan_pda_setbaud(serial, 4800); break;
-		case B9600: keyspan_pda_setbaud(serial, 9600); break;
-		case B19200: keyspan_pda_setbaud(serial, 19200); break;
-		case B38400: keyspan_pda_setbaud(serial, 38400); break;
-		case B57600: keyspan_pda_setbaud(serial, 57600); break;
-		case B115200: keyspan_pda_setbaud(serial, 115200); break;
-		default: dbg("can't handle requested baud rate"); break;
-	}
-}
-
-
-/* modem control pins: DTR and RTS are outputs and can be controlled.
-   DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
-   read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */
-
-static int keyspan_pda_get_modem_info(struct usb_serial *serial,
-				      unsigned char *value)
-{
-	int rc;
-	unsigned char data;
-	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-			     3, /* get pins */
-			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
-			     0, 0, &data, 1, 2*HZ);
-	if (rc > 0)
-		*value = data;
-	return rc;
-}
-
-
-static int keyspan_pda_set_modem_info(struct usb_serial *serial,
-				      unsigned char value)
-{
-	int rc;
-	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			     3, /* set pins */
-			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
-			     value, 0, NULL, 0, 2*HZ);
-	return rc;
-}
-
-
-static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file,
-			     unsigned int cmd, unsigned long arg)
-{
-	struct usb_serial *serial = port->serial;
-	int rc;
-	unsigned int value;
-	unsigned char status, mask;
-
-	switch (cmd) {
-	case TIOCMGET: /* get modem pins state */
-		rc = keyspan_pda_get_modem_info(serial, &status);
-		if (rc < 0)
-			return rc;
-		value =
-			((status & (1<<7)) ? TIOCM_DTR : 0) |
-			((status & (1<<6)) ? TIOCM_CAR : 0) |
-			((status & (1<<5)) ? TIOCM_RNG : 0) |
-			((status & (1<<4)) ? TIOCM_DSR : 0) |
-			((status & (1<<3)) ? TIOCM_CTS : 0) |
-			((status & (1<<2)) ? TIOCM_RTS : 0);
-		if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
-			return -EFAULT;
-		return 0;
-	case TIOCMSET: /* set a state as returned by MGET */
-		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
-			return -EFAULT;
-		status =
-			((value & TIOCM_DTR) ? (1<<7) : 0) |
-			((value & TIOCM_CAR) ? (1<<6) : 0) |
-			((value & TIOCM_RNG) ? (1<<5) : 0) |
-			((value & TIOCM_DSR) ? (1<<4) : 0) |
-			((value & TIOCM_CTS) ? (1<<3) : 0) |
-			((value & TIOCM_RTS) ? (1<<2) : 0);
-		rc = keyspan_pda_set_modem_info(serial, status);
-		if (rc < 0)
-			return rc;
-		return 0;
-	case TIOCMBIS: /* set bits in bitmask <arg> */
-	case TIOCMBIC: /* clear bits from bitmask <arg> */
-		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
-			return -EFAULT;
-		rc = keyspan_pda_get_modem_info(serial, &status);
-		if (rc < 0)
-			return rc;
-		mask =
-			((value & TIOCM_RTS) ? (1<<2) : 0) |
-			((value & TIOCM_DTR) ? (1<<7) : 0);
-		if (cmd == TIOCMBIS)
-			status |= mask;
-		else
-			status &= ~mask;
-		rc = keyspan_pda_set_modem_info(serial, status);
-		if (rc < 0)
-			return rc;
-		return 0;
-	case TIOCMIWAIT:
-		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
-		/* TODO */
-	case TIOCGICOUNT:
-		/* return count of modemline transitions */
-		return 0; /* TODO */
-	}
-	
-	return -ENOIOCTLCMD;
-}
-
-static int keyspan_pda_write(struct usb_serial_port *port, int from_user, 
-			     const unsigned char *buf, int count)
-{
-	struct usb_serial *serial = port->serial;
-	int request_unthrottle = 0;
-	int rc = 0;
-	DECLARE_WAITQUEUE(wait, current);
-
-	/* guess how much room is left in the device's ring buffer, and if we
-	   want to send more than that, check first, updating our notion of
-	   what is left. If our write will result in no room left, ask the
-	   device to give us an interrupt when the room available rises above
-	   a threshold, and hold off all writers (eventually, those using
-	   select() or poll() too) until we receive that unthrottle interrupt.
-	   Block if we can't write anything at all, otherwise write as much as
-	   we can. */
-
-	if (count == 0) {
-		dbg(" write request of 0 bytes");
-		return (0);
-	}
-
-	/* we might block because of:
-	   the TX urb is in-flight (wait until it completes)
-	   the device is full (wait until it says there is room)
-	*/
-	while (port->write_urb->status == -EINPROGRESS) {
-		if (0 /* file->f_flags & O_NONBLOCK */) {
-			rc = -EAGAIN;
-			goto err;
-		}
-		interruptible_sleep_on(&serial->write_wait);
-		if (signal_pending(current)) {
-			rc = -ERESTARTSYS;
-			goto err;
-		}
-	}
-
-	/* at this point the URB is in our control, nobody else can submit it
-	   again (the only sudden transition was the one from EINPROGRESS to
-	   finished) */
-
-	/* the next potential block is that our TX process might be throttled.
-	   The transition from throttled->not happens because of an Rx
-	   interrupt, and the wake_up occurs during the same interrupt, so we
-	   have to be careful to avoid a race that would cause us to sleep
-	   forever. */
-
-	add_wait_queue(&serial->write_wait, &wait);
-	set_current_state(TASK_INTERRUPTIBLE);
-	while (serial->tx_throttled) {
-		/* device can't accomodate any more characters. Sleep until it
-		   can. Woken up by an Rx interrupt message, which clears
-		   tx_throttled first. */
-		dbg(" tx_throttled, going to sleep");
-		if (signal_pending(current)) {
-			current->state = TASK_RUNNING;
-			remove_wait_queue(&serial->write_wait, &wait);
-			dbg(" woke up because of signal");
-			rc = -ERESTARTSYS;
-			goto err;
-		}
-		schedule();
-		dbg(" woke up");
-	}
-	remove_wait_queue(&serial->write_wait, &wait);
-	set_current_state(TASK_RUNNING);
-
-	count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-	if (count > serial->tx_room) {
-		unsigned char room;
-		/* Looks like we might overrun the Tx buffer. Ask the device
-		   how much room it really has */
-		rc = usb_control_msg(serial->dev, 
-				     usb_rcvctrlpipe(serial->dev, 0),
-				     6, /* write_room */
-				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
-				     | USB_DIR_IN,
-				     0, /* value: 0 means "remaining room" */
-				     0, /* index */
-				     &room,
-				     1,
-				     2*HZ);
-		if (rc < 0) {
-			dbg(" roomquery failed");
-			return rc; /* failed */
-		}
-		if (rc == 0) {
-			dbg(" roomquery returned 0 bytes");
-			return -EIO; /* device didn't return any data */
-		}
-		dbg(" roomquery says %d", room);
-		serial->tx_room = room;
-		if (count > serial->tx_room) {
-			/* we're about to completely fill the Tx buffer, so
-			   we'll be throttled afterwards. */
-			count = serial->tx_room;
-			request_unthrottle = 1;
-		}
-	}
-	serial->tx_room -= count;
-
-	if (count) {
-		/* now transfer data */
-		if (from_user) {
-			copy_from_user(port->write_urb->transfer_buffer, buf, count);
-		}
-		else {
-			memcpy (port->write_urb->transfer_buffer, buf, count);
-		}  
-		/* send the data out the bulk port */
-		port->write_urb->transfer_buffer_length = count;
-		
-		if (usb_submit_urb(port->write_urb))
-			dbg(" usb_submit_urb(write bulk) failed");
-	}
-	else {
-		/* There wasn't any room left, so we are throttled until
-		   the buffer empties a bit */
-		request_unthrottle = 1;
-	}
-
-	if (request_unthrottle) {
-		dbg(" request_unthrottle");
-		/* ask the device to tell us when the tx buffer becomes
-		   sufficiently empty */
-		serial->tx_throttled = 1; /* block writers */
-		rc = usb_control_msg(serial->dev, 
-				     usb_sndctrlpipe(serial->dev, 0),
-				     7, /* request_unthrottle */
-				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
-				     | USB_DIR_OUT,
-				     16, /* value: threshold */
-				     0, /* index */
-				     NULL,
-				     0,
-				     2*HZ);
-	}
-
-	return (count);
- err:
-	return (rc);
-}
-
-
-static void keyspan_pda_write_bulk_callback (struct urb *urb)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial;
-       	struct tty_struct *tty;
-
-	if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
-		return;
-	}
-
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
-		return;
-	}
-	
-	wake_up_interruptible(&serial->write_wait);
-
-	tty = port->tty;
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-
-	wake_up_interruptible(&tty->write_wait);
-}
-
-
-static int keyspan_pda_write_room (struct usb_serial_port *port)
-{
-	struct usb_serial *serial = port->serial;
-
-	/* used by n_tty.c for processing of tabs and such. Giving it our
-	   conservative guess is probably good enough, but needs testing by
-	   running a console through the device. */
-
-	return (serial->tx_room);
-}
-
-
-static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
-{
-	struct usb_serial *serial = port->serial;
-	
-	/* when throttled, return at least WAKEUP_CHARS to tell select() (via
-	   n_tty.c:normal_poll() ) that we're not writeable. */
-	if (serial->tx_throttled)
-		return 256;
-	return 0;
-}
-
-
-static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
-{
-	struct usb_serial *serial = port->serial;
-	unsigned char room;
-	int rc;
-
-	if (port->active) {
-		return -EINVAL;
-	}
-	port->active = 1;
- 
-	/* find out how much room is in the Tx ring */
-	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-			     6, /* write_room */
-			     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
-			     | USB_DIR_IN,
-			     0, /* value */
-			     0, /* index */
-			     &room,
-			     1,
-			     2*HZ);
-	if (rc < 0) {
-		dbg(" roomquery failed");
-		return rc; /* failed */
-	}
-	if (rc == 0) {
-		dbg(" roomquery returned 0 bytes");
-		return -EIO; /* device didn't return any data */
-	}
-	serial->tx_room = room;
-	serial->tx_throttled = room ? 0 : 1;
-
-	/* the normal serial device seems to always turn on DTR and RTS here,
-	   so do the same */
-	if (port->tty->termios->c_cflag & CBAUD)
-		keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
-	else
-		keyspan_pda_set_modem_info(serial, 0);
-
-	/*Start reading from the device*/
-	if (usb_submit_urb(port->read_urb))
-		dbg(" usb_submit_urb(read int) failed");
-
-	return (0);
-}
-
-
-static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
-{
-	struct usb_serial *serial = port->serial;
-
-	/* the normal serial device seems to always shut off DTR and RTS now */
-	if (port->tty->termios->c_cflag & HUPCL)
-		keyspan_pda_set_modem_info(serial, 0);
-
-	/* shutdown our bulk reads and writes */
-	usb_unlink_urb (port->write_urb);
-	usb_unlink_urb (port->read_urb);
-	port->active = 0;
-}
-
-
-/* download the firmware to a "fake" device (pre-renumeration) */
-static int keyspan_pda_fake_startup (struct usb_serial *serial)
-{
-	int response;
-	const struct ezusb_hex_record *record;
-
-	/* download the firmware here ... */
-	response = ezusb_set_reset(serial, 1);
-
-	record = &keyspan_pda_firmware[0];
-	while(record->address != 0xffff) {
-		response = ezusb_writememory(serial, record->address,
-					     (unsigned char *)record->data,
-					     record->data_size, 0xa0);
-		if (response < 0) {
-			err("ezusb_writememory failed for Keyspan PDA "
-			    "firmware (%d %04X %p %d)",
-			    response, 
-			    record->address, record->data, record->data_size);
-			break;
-		}
-		record++;
-	}
-	/* bring device out of reset. Renumeration will occur in a moment
-	   and the new device will bind to the real driver */
-	response = ezusb_set_reset(serial, 0);
-
-	/* we want this device to fail to have a driver assigned to it. */
-	return (1);
-}
-
-
-/* do some startup allocations not currently performed by usb_serial_probe() */
-static int keyspan_pda_startup (struct usb_serial *serial)
-{
-	struct usb_endpoint_descriptor *intin;
-	intin = serial->port[0].interrupt_in_endpoint;
-
-	/* set up the receive interrupt urb */
-	FILL_INT_URB(serial->port[0].read_urb, serial->dev,
-		     usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
-		     serial->port[0].interrupt_in_buffer,
-		     intin->wMaxPacketSize,
-		     keyspan_pda_rx_interrupt,
-		     serial,
-		     intin->bInterval);
-
-	init_waitqueue_head(&serial->write_wait);
-	
-	return (0);
-}
-
-#endif	/* CONFIG_USB_SERIAL_KEYSPAN_PDA */
-
-
-/*****************************************************************************
- * generic devices specific driver functions
- *****************************************************************************/
-static int generic_open (struct usb_serial_port *port, struct file *filp)
-{
-	struct usb_serial *serial = port->serial;
-
-	dbg("generic_open port %d", port->number);
-
-	if (port->active) {
-		dbg ("device already open");
-		return -EINVAL;
-	}
-	port->active = 1;
- 
-	/* if we have a bulk interrupt, start reading from it */
-	if (serial->num_bulk_in) {
-		/*Start reading from the device*/
-		if (usb_submit_urb(port->read_urb))
-			dbg("usb_submit_urb(read bulk) failed");
-	}
-
-	return (0);
-}
-
-
-static void generic_close (struct usb_serial_port *port, struct file * filp)
-{
-	struct usb_serial *serial = port->serial;
-
-	dbg("generic_close port %d", port->number);
-	
-	/* shutdown any bulk reads that might be going on */
-	if (serial->num_bulk_out) {
-		usb_unlink_urb (port->write_urb);
-	}
-	if (serial->num_bulk_in) {
-		usb_unlink_urb (port->read_urb);
-	}
-
-	port->active = 0;
-}
-
-
-static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
-{
-	struct usb_serial *serial = port->serial;
-
-	dbg("generic_serial_write port %d", port->number);
-
-	if (count == 0) {
-		dbg("write request of 0 bytes");
-		return (0);
-	}
-
-	/* only do something if we have a bulk out endpoint */
-	if (serial->num_bulk_out) {
-		if (port->write_urb->status == -EINPROGRESS) {
-			dbg ("already writing");
-			return (0);
-		}
-
-		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
-		if (from_user) {
-			copy_from_user(port->write_urb->transfer_buffer, buf, count);
-		}
-		else {
-			memcpy (port->write_urb->transfer_buffer, buf, count);
-		}  
-
-		/* send the data out the bulk port */
-		port->write_urb->transfer_buffer_length = count;
-
-		if (usb_submit_urb(port->write_urb))
-			dbg("usb_submit_urb(write bulk) failed");
-
-		return (count);
-	}
-	
-	/* no bulk out, so return 0 bytes written */
-	return (0);
-} 
-
-
-static int generic_write_room (struct usb_serial_port *port)
-{
-	struct usb_serial *serial = port->serial;
-	int room;
-
-	dbg("generic_write_room port %d", port->number);
-	
-	if (serial->num_bulk_out) {
-		if (port->write_urb->status == -EINPROGRESS)
-			room = 0;
-		else
-			room = port->bulk_out_size;
-		dbg("generic_write_room returns %d", room);
-		return (room);
-	}
-	
-	return (0);
-}
-
-
-static int generic_chars_in_buffer (struct usb_serial_port *port)
-{
-	struct usb_serial *serial = port->serial;
-
-	dbg("generic_chars_in_buffer port %d", port->number);
-	
-	if (serial->num_bulk_out) {
-		if (port->write_urb->status == -EINPROGRESS) {
-			return (port->bulk_out_size);
-		}
-	}
-
-	return (0);
-}
-
-
-static void generic_read_bulk_callback (struct urb *urb)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial;
-       	struct tty_struct *tty;
-       	unsigned char *data = urb->transfer_buffer;
-	int i;
-
-	dbg("generic_read_bulk_callback");
-
-	if (port_paranoia_check (port, "generic_read_bulk_callback")) {
-		return;
-	}
-
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "generic_read_bulk_callback")) {
-		return;
-	}
-	
-	if (urb->status) {
-		dbg("nonzero read bulk status received: %d", urb->status);
-		return;
-	}
-
-#ifdef DEBUG
-	if (urb->actual_length) {
-		printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
-		for (i = 0; i < urb->actual_length; ++i) {
-			printk ("%.2x ", data[i]);
-		}
-		printk ("\n");
-	}
-#endif
-
-	tty = port->tty;
-	if (urb->actual_length) {
-		for (i = 0; i < urb->actual_length ; ++i) {
-			 tty_insert_flip_char(tty, data[i], 0);
-	  	}
-	  	tty_flip_buffer_push(tty);
-	}
-
-	/* Continue trying to always read  */
-	if (usb_submit_urb(urb))
-		dbg("failed resubmitting read urb");
-
-	return;
-}
-
-
-static void generic_write_bulk_callback (struct urb *urb)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial;
-       	struct tty_struct *tty;
-
-	dbg("generic_write_bulk_callback");
-
-	if (port_paranoia_check (port, "generic_write_bulk_callback")) {
-		return;
-	}
-
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "generic_write_bulk_callback")) {
-		return;
-	}
-	
-	if (urb->status) {
-		dbg("nonzero write bulk status received: %d", urb->status);
-		return;
-	}
-
-	tty = port->tty;
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-
-	wake_up_interruptible(&tty->write_wait);
-	
-	return;
-}
-
-
-static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
-{
-	struct usb_serial *serial = NULL;
-	struct usb_serial_port *port;
-	struct usb_interface_descriptor *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
-	struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
-	struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
-	struct usb_serial_device_type *type;
-	int device_num;
-	int minor;
-	int buffer_size;
-	int i;
-	char interrupt_pipe;
-	char bulk_in_pipe;
-	char bulk_out_pipe;
-	int num_interrupt_in = 0;
-	int num_bulk_in = 0;
-	int num_bulk_out = 0;
-	int num_ports;
-	
-	/* loop through our list of known serial converters, and see if this device matches */
-	device_num = 0;
-	while (usb_serial_devices[device_num] != NULL) {
-		type = usb_serial_devices[device_num];
-		dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
-
-		/* look at the device descriptor */
-		if ((dev->descriptor.idVendor == *(type->idVendor)) &&
-		    (dev->descriptor.idProduct == *(type->idProduct))) {
-
-			dbg("descriptor matches...looking at the endpoints");
-
-			/* descriptor matches, let's try to find the endpoints needed */
-			interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
-			
-			/* check out the endpoints */
-			interface = &dev->actconfig->interface[ifnum].altsetting[0];
-			for (i = 0; i < interface->bNumEndpoints; ++i) {
-				endpoint = &interface->endpoint[i];
-		
-				if ((endpoint->bEndpointAddress & 0x80) &&
-				    ((endpoint->bmAttributes & 3) == 0x02)) {
-					/* we found a bulk in endpoint */
-					dbg("found bulk in");
-					bulk_in_pipe = HAS;
-					bulk_in_endpoint[num_bulk_in] = endpoint;
-					++num_bulk_in;
-				}
-
-				if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
-				    ((endpoint->bmAttributes & 3) == 0x02)) {
-					/* we found a bulk out endpoint */
-					dbg("found bulk out");
-					bulk_out_pipe = HAS;
-					bulk_out_endpoint[num_bulk_out] = endpoint;
-					++num_bulk_out;
-				}
-		
-				if ((endpoint->bEndpointAddress & 0x80) &&
-				    ((endpoint->bmAttributes & 3) == 0x03)) {
-					/* we found a interrupt in endpoint */
-					dbg("found interrupt in");
-					interrupt_pipe = HAS;
-					interrupt_in_endpoint[num_interrupt_in] = endpoint;
-					++num_interrupt_in;
-				}
-
-			}
-	
-			/* verify that we found all of the endpoints that we need */
-			if ((interrupt_pipe & type->needs_interrupt_in) &&
-			    (bulk_in_pipe & type->needs_bulk_in) &&
-			    (bulk_out_pipe & type->needs_bulk_out)) {
-				/* found all that we need */
-				info("%s converter detected", type->name);
-
-#ifdef CONFIG_USB_SERIAL_GENERIC
-				if (type == &generic_device)
-					num_ports = num_bulk_out;
-				else
-#endif
-					num_ports = type->num_ports;
-
-				serial = get_free_serial (num_ports, &minor);
-				if (serial == NULL) {
-					err("No more free serial devices");
-					return NULL;
-				}
-	
-			       	serial->dev = dev;
-				serial->type = type;
-				serial->minor = minor;
-				serial->num_ports = num_ports;
-				serial->num_bulk_in = num_bulk_in;
-				serial->num_bulk_out = num_bulk_out;
-				serial->num_interrupt_in = num_interrupt_in;
-
-				/* collect interrupt_in endpoints now, because
-				   the keyspan_pda startup function needs
-				   to know about them */
-				for (i = 0; i < num_interrupt_in; ++i) {
-					port = &serial->port[i];
-					buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
-					port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-					if (!port->interrupt_in_buffer) {
-						err("Couldn't allocate interrupt_in_buffer");
-						goto probe_error;
-					}
-					port->interrupt_in_endpoint = interrupt_in_endpoint[i];
-				}
-
-				/* if this device type has a startup function, call it */
-				if (type->startup) {
-					if (type->startup (serial)) {
-						return_serial (serial);
-						return NULL;
-					}
-				}
-
-				/* set up the endpoint information */
-				for (i = 0; i < num_bulk_in; ++i) {
-					port = &serial->port[i];
-					port->read_urb = usb_alloc_urb (0);
-					if (!port->read_urb) {
-						err("No free urbs available");
-						goto probe_error;
-					}
-					buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
-					port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-					if (!port->bulk_in_buffer) {
-						err("Couldn't allocate bulk_in_buffer");
-						goto probe_error;
-					}
-					if (serial->type->read_bulk_callback) {
-						FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
-								port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port);
-					} else {
-						FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
-								port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port);
-					}
-				}
-
-				for (i = 0; i < num_bulk_out; ++i) {
-					port = &serial->port[i];
-					port->write_urb = usb_alloc_urb(0);
-					if (!port->write_urb) {
-						err("No free urbs available");
-						goto probe_error;
-					}
-					port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
-					port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
-					if (!port->bulk_out_buffer) {
-						err("Couldn't allocate bulk_out_buffer");
-						goto probe_error;
-					}
-					if (serial->type->write_bulk_callback) {
-						FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
-								port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port);
-					} else {
-						FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
-								port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port);
-					}
-				}
-
-#if 0 /* use this code when WhiteHEAT is up and running */
-				for (i = 0; i < num_interrupt_in; ++i) {
-					port = &serial->port[i];
-					port->control_urb = usb_alloc_urb(0);
-					if (!port->control_urb) {
-						err("No free urbs available");
-						goto probe_error;
-					}
-					buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
-					port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-					if (!port->interrupt_in_buffer) {
-						err("Couldn't allocate interrupt_in_buffer");
-						goto probe_error;
-					}
-					FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
-							port->interrupt_in_buffer, buffer_size, serial_control_irq,
-							port, interrupt_in_endpoint[i]->bInterval);
-				}
-#endif
-
-				for (i = 0; i < serial->num_ports; ++i) {
-					info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
-				}
-
-				MOD_INC_USE_COUNT;
-
-				return serial;
-			} else {
-				info("descriptors matched, but endpoints did not");
-			}
-		}
-
-		/* look at the next type in our list */
-		++device_num;
-	}
-
-probe_error:
-	if (serial) {
-		for (i = 0; i < num_bulk_in; ++i) {
-			port = &serial->port[i];
-			if (port->read_urb)
-				usb_free_urb (port->read_urb);
-			if (serial->port[i].bulk_in_buffer[i])
-				kfree (serial->port[i].bulk_in_buffer);
-		}
-		for (i = 0; i < num_bulk_out; ++i) {
-			port = &serial->port[i];
-			if (port->write_urb)
-				usb_free_urb (port->write_urb);
-			if (serial->port[i].bulk_out_buffer)
-				kfree (serial->port[i].bulk_out_buffer);
-		}
-		for (i = 0; i < num_interrupt_in; ++i) {
-			port = &serial->port[i];
-			if (port->control_urb)
-				usb_free_urb (port->control_urb);
-			if (serial->port[i].interrupt_in_buffer)
-				kfree (serial->port[i].interrupt_in_buffer);
-		}
-		
-		/* return the minor range that this device had */
-		return_serial (serial);
-
-		/* free up any memory that we allocated */
-		kfree (serial);
-	}
-	return NULL;
-}
-
-
-static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
-{
-	struct usb_serial *serial = (struct usb_serial *) ptr;
-	struct usb_serial_port *port;
-	int i;
-
-	if (serial) {
-		for (i = 0; i < serial->num_ports; ++i)
-			serial->port[i].active = 0;
-
-		for (i = 0; i < serial->num_bulk_in; ++i) {
-			port = &serial->port[i];
-			if (port->read_urb) {
-				usb_unlink_urb (port->read_urb);
-				usb_free_urb (port->read_urb);
-			}
-			if (port->bulk_in_buffer)
-				kfree (port->bulk_in_buffer);
-		}
-		for (i = 0; i < serial->num_bulk_out; ++i) {
-			port = &serial->port[i];
-			if (port->write_urb) {
-				usb_unlink_urb (port->write_urb);
-				usb_free_urb (port->write_urb);
-			}
-			if (port->bulk_out_buffer)
-				kfree (port->bulk_out_buffer);
-		}
-		for (i = 0; i < serial->num_interrupt_in; ++i) {
-			port = &serial->port[i];
-			if (port->control_urb) {
-				usb_unlink_urb (port->control_urb);
-				usb_free_urb (port->control_urb);
-			}
-			if (port->interrupt_in_buffer)
-				kfree (port->interrupt_in_buffer);
-		}
-
-		for (i = 0; i < serial->num_ports; ++i) {
-			info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
-		}
-
-		/* return the minor range that this device had */
-		return_serial (serial);
-
-		/* free up any memory that we allocated */
-		kfree (serial);
-
-	} else {
-		info("device disconnected");
-	}
-	
-	MOD_DEC_USE_COUNT;
-}
-
-
-static struct tty_driver serial_tty_driver = {
-	magic:			TTY_DRIVER_MAGIC,
-	driver_name:		"usb",
-	name:			"ttyUSB%d",
-	major:			SERIAL_TTY_MAJOR,
-	minor_start:		0,
-	num:			SERIAL_TTY_MINORS,
-	type:			TTY_DRIVER_TYPE_SERIAL,
-	subtype:		SERIAL_TYPE_NORMAL,
-	flags:			TTY_DRIVER_REAL_RAW,
-	refcount:		&serial_refcount,
-	table:			serial_tty,
-	proc_entry:		NULL,
-	other:			NULL,
-	termios:		serial_termios,
-	termios_locked:		serial_termios_locked,
-	
-	open:			serial_open,
-	close:			serial_close,
-	write:			serial_write,
-	put_char:		NULL,
-	flush_chars:		NULL,
-	write_room:		serial_write_room,
-	ioctl:			serial_ioctl,
-	set_termios:		serial_set_termios,
-	set_ldisc:		NULL, 
-	throttle:		serial_throttle,
-	unthrottle:		serial_unthrottle,
-	stop:			NULL,
-	start:			NULL,
-	hangup:			NULL,
-	break_ctl:		serial_break,
-	wait_until_sent:	NULL,
-	send_xchar:		NULL,
-	read_proc:		NULL,
-	chars_in_buffer:	serial_chars_in_buffer,
-	flush_buffer:		NULL
-};
-
-
-int usb_serial_init(void)
-{
-	int i;
-
-	/* Initalize our global data */
-	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
-		serial_table[i] = NULL;
-	}
-
-	/* register the tty driver */
-	serial_tty_driver.init_termios		= tty_std_termios;
-	serial_tty_driver.init_termios.c_cflag	= B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	if (tty_register_driver (&serial_tty_driver)) {
-		err("failed to register tty driver");
-		return -EPERM;
-	}
-	
-	/* register the USB driver */
-	if (usb_register(&usb_serial_driver) < 0) {
-		tty_unregister_driver(&serial_tty_driver);
-		return -1;
-	}
-
-	info("support registered");
-	return 0;
-}
-
-
-void usb_serial_exit(void)
-{
-	tty_unregister_driver(&serial_tty_driver);
-	usb_deregister(&usb_serial_driver);
-}
-
-
-module_init(usb_serial_init);
-module_exit(usb_serial_exit);
-
-
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h
--- v2.3.99-pre3/linux/drivers/usb/serial/usb-serial.h	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/serial/usb-serial.h	Wed Apr  5 16:58:38 2000
@@ -19,47 +19,22 @@
 
 #include <linux/config.h>
 
-/* Module information */
-MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
-MODULE_DESCRIPTION("USB Serial Driver");
-
-#ifdef CONFIG_USB_SERIAL_GENERIC
-static __u16	vendor	= 0x05f9;
-static __u16	product	= 0xffff;
-MODULE_PARM(vendor, "i");
-MODULE_PARM_DESC(vendor, "User specified USB idVendor");
-
-MODULE_PARM(product, "i");
-MODULE_PARM_DESC(product, "User specified USB idProduct");
-#endif
-
-
-/* USB Serial devices vendor ids and device ids that this driver supports */
-#define CONNECT_TECH_VENDOR_ID		0x0710
-#define CONNECT_TECH_FAKE_WHITE_HEAT_ID	0x0001
-#define CONNECT_TECH_WHITE_HEAT_ID	0x8001
-#define HANDSPRING_VENDOR_ID		0x082d
-#define HANDSPRING_VISOR_ID		0x0100
-#define FTDI_VENDOR_ID			0x0403
-#define FTDI_SIO_SERIAL_CONVERTER_ID	0x8372
-#define KEYSPAN_VENDOR_ID		0x06cd
-#define KEYSPAN_PDA_FAKE_ID		0x0103
-#define KEYSPAN_PDA_ID			0x0104 /* no clue */
-
 #define SERIAL_TTY_MAJOR	188	/* Nice legal number now */
 #define SERIAL_TTY_MINORS	16	/* Actually we are allowed 255, but this is good for now */
 
-
-#define MAX_NUM_PORTS	8	/* The maximum number of ports one device can grab at once */
+#define MAX_NUM_PORTS		8	/* The maximum number of ports one device can grab at once */
 
 #define USB_SERIAL_MAGIC	0x6702	/* magic number for usb_serial struct */
 #define USB_SERIAL_PORT_MAGIC	0x7301	/* magic number for usb_serial_port struct */
 
+/* parity check flag */
+#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
 
 struct usb_serial_port {
 	int			magic;
 	struct usb_serial	*serial;	/* pointer back to the owner of this port */
-	struct tty_struct *	tty;		/* the coresponding tty for this device */
+	struct tty_struct *	tty;		/* the coresponding tty for this port */
 	unsigned char		minor;
 	unsigned char		number;
 	char			active;		/* someone has this device open */
@@ -81,8 +56,9 @@
 struct usb_serial {
 	int				magic;
 	struct usb_device *		dev;
-	struct usb_serial_device_type *	type;
-	unsigned char			minor;
+	struct usb_serial_device_type *	type;			/* the type of usb serial device this is */
+	struct tty_driver *		tty_driver;		/* the tty_driver for this device */
+	unsigned char			minor;			/* the starting minor number for this device */
 	unsigned char			num_ports;		/* the number of ports this device has */
 	char				num_interrupt_in;	/* number of interrupt in endpoints we have */
 	char				num_bulk_in;		/* number of bulk in endpoints we have */
@@ -141,299 +117,67 @@
 };
 
 
-/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
-/* need to always compile these in, as some of the other devices use these functions as their own. */
-/* if a driver does not provide a function pointer, the generic function will be called. */
-static int  generic_open		(struct usb_serial_port *port, struct file *filp);
-static void generic_close		(struct usb_serial_port *port, struct file *filp);
-static int  generic_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
-static int  generic_write_room		(struct usb_serial_port *port);
-static int  generic_chars_in_buffer	(struct usb_serial_port *port);
-static void generic_read_bulk_callback	(struct urb *urb);
-static void generic_write_bulk_callback	(struct urb *urb);
-
-
-#ifdef CONFIG_USB_SERIAL_GENERIC
-/* All of the device info needed for the Generic Serial Converter */
-static struct usb_serial_device_type generic_device = {
-	name:			"Generic",
-	idVendor:		&vendor,		/* use the user specified vendor id */
-	idProduct:		&product,		/* use the user specified product id */
-	needs_interrupt_in:	DONT_CARE,		/* don't have to have an interrupt in endpoint */
-	needs_bulk_in:		DONT_CARE,		/* don't have to have a bulk in endpoint */
-	needs_bulk_out:		DONT_CARE,		/* don't have to have a bulk out endpoint */
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-/* function prototypes for the Connect Tech WhiteHEAT serial converter */
-static int  whiteheat_open		(struct usb_serial_port *port, struct file *filp);
-static void whiteheat_close		(struct usb_serial_port *port, struct file *filp);
-static void whiteheat_set_termios	(struct usb_serial_port *port, struct termios * old);
-static void whiteheat_throttle		(struct usb_serial_port *port);
-static void whiteheat_unthrottle	(struct usb_serial_port *port);
-static int  whiteheat_startup		(struct usb_serial *serial);
-
-/* All of the device info needed for the Connect Tech WhiteHEAT */
-static __u16	connecttech_vendor_id			= CONNECT_TECH_VENDOR_ID;
-static __u16	connecttech_whiteheat_fake_product_id	= CONNECT_TECH_FAKE_WHITE_HEAT_ID;
-static __u16	connecttech_whiteheat_product_id	= CONNECT_TECH_WHITE_HEAT_ID;
-static struct usb_serial_device_type whiteheat_fake_device = {
-	name:			"Connect Tech - WhiteHEAT - (prerenumeration)",
-	idVendor:		&connecttech_vendor_id,			/* the Connect Tech vendor id */
-	idProduct:		&connecttech_whiteheat_fake_product_id,	/* the White Heat initial product id */
-	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
-	needs_bulk_in:		DONT_CARE,				/* don't have to have a bulk in endpoint */
-	needs_bulk_out:		DONT_CARE,				/* don't have to have a bulk out endpoint */
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		whiteheat_startup	
-};
-static struct usb_serial_device_type whiteheat_device = {
-	name:			"Connect Tech - WhiteHEAT",
-	idVendor:		&connecttech_vendor_id,			/* the Connect Tech vendor id */
-	idProduct:		&connecttech_whiteheat_product_id,	/* the White Heat real product id */
-	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
-	needs_bulk_in:		DONT_CARE,				/* don't have to have a bulk in endpoint */
-	needs_bulk_out:		DONT_CARE,				/* don't have to have a bulk out endpoint */
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		4,
-	open:			whiteheat_open,
-	close:			whiteheat_close,
-	throttle:		whiteheat_throttle,
-	unthrottle:		whiteheat_unthrottle,
-	set_termios:		whiteheat_set_termios,
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_VISOR
-
-/****************************************************************************
- * Handspring Visor Vendor specific request codes (bRequest values)
- * A big thank you to Handspring for providing the following information.
- * If anyone wants the original file where these values and structures came
- * from, send email to <greg@kroah.com>.
- ****************************************************************************/
-
-/****************************************************************************
- * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that
- * are available to be transfered to the host for the specified endpoint.
- * Currently this is not used, and always returns 0x0001
- ****************************************************************************/
-#define VISOR_REQUEST_BYTES_AVAILABLE		0x01
-
-/****************************************************************************
- * VISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host
- * is now closing the pipe. An empty packet is sent in response.
- ****************************************************************************/
-#define VISOR_CLOSE_NOTIFICATION		0x02
-
-/****************************************************************************
- * VISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to
- * get the endpoints used by the connection.
- ****************************************************************************/
-#define VISOR_GET_CONNECTION_INFORMATION	0x03
-
-
-/****************************************************************************
- * VISOR_GET_CONNECTION_INFORMATION returns data in the following format
- ****************************************************************************/
-struct visor_connection_info {
-	__u16	num_ports;
-	struct {
-		__u8	port_function_id;
-		__u8	port;
-	} connections[2];
-};
-
-
-/* struct visor_connection_info.connection[x].port defines: */
-#define VISOR_ENDPOINT_1		0x01
-#define VISOR_ENDPOINT_2		0x02
-
-/* struct visor_connection_info.connection[x].port_function_id defines: */
-#define VISOR_FUNCTION_GENERIC		0x00
-#define VISOR_FUNCTION_DEBUGGER		0x01
-#define VISOR_FUNCTION_HOTSYNC		0x02
-#define VISOR_FUNCTION_CONSOLE		0x03
-#define VISOR_FUNCTION_REMOTE_FILE_SYS	0x04
-
-
-/* function prototypes for a handspring visor */
-static int  visor_open		(struct usb_serial_port *port, struct file *filp);
-static void visor_close		(struct usb_serial_port *port, struct file *filp);
-static void visor_throttle	(struct usb_serial_port *port);
-static void visor_unthrottle	(struct usb_serial_port *port);
-static int  visor_startup	(struct usb_serial *serial);
-
-/* All of the device info needed for the Handspring Visor */
-static __u16	handspring_vendor_id	= HANDSPRING_VENDOR_ID;
-static __u16	handspring_product_id	= HANDSPRING_VISOR_ID;
-static struct usb_serial_device_type handspring_device = {
-	name:			"Handspring Visor",
-	idVendor:		&handspring_vendor_id,	/* the Handspring vendor ID */
-	idProduct:		&handspring_product_id,	/* the Handspring Visor product id */
-	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
-	num_interrupt_in:	0,
-	num_bulk_in:		2,
-	num_bulk_out:		2,
-	num_ports:		2,
-	open:			visor_open,
-	close:			visor_close,
-	throttle:		visor_throttle,
-	unthrottle:		visor_unthrottle,
-	startup:		visor_startup,
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_FTDI_SIO
-/* function prototypes for a FTDI serial converter */
-static int  ftdi_sio_open		(struct usb_serial_port *port, struct file *filp);
-static void ftdi_sio_close		(struct usb_serial_port *port, struct file *filp);
-static int  ftdi_sio_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
-static void ftdi_sio_read_bulk_callback	(struct urb *urb);
-static void ftdi_sio_set_termios	(struct usb_serial_port *port, struct termios * old);
-static int  ftdi_sio_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-
-/* All of the device info needed for the FTDI SIO serial converter */
-static __u16	ftdi_vendor_id		= FTDI_VENDOR_ID;
-static __u16	ftdi_sio_product_id	= FTDI_SIO_SERIAL_CONVERTER_ID;
-static struct usb_serial_device_type ftdi_sio_device = {
-	name:			"FTDI SIO",
-	idVendor:		&ftdi_vendor_id,	/* the FTDI vendor ID */
-	idProduct:		&ftdi_sio_product_id,	/* the FTDI SIO product id */
-	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
-	num_interrupt_in:	0,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			ftdi_sio_open,
-	close:			ftdi_sio_close,
-	write:			ftdi_sio_write,
-	ioctl:			ftdi_sio_ioctl,
-	read_bulk_callback:	ftdi_sio_read_bulk_callback,
-	set_termios:		ftdi_sio_set_termios
-};
-#endif
 
-
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-/* function prototypes for a Keyspan PDA serial converter */
-static int  keyspan_pda_open		(struct usb_serial_port *port,
-					 struct file *filp);
-static void keyspan_pda_close		(struct usb_serial_port *port,
-					 struct file *filp);
-static int  keyspan_pda_startup		(struct usb_serial *serial);
-static void keyspan_pda_rx_throttle	(struct usb_serial_port *port);
-static void keyspan_pda_rx_unthrottle	(struct usb_serial_port *port);
-static int  keyspan_pda_setbaud		(struct usb_serial *serial, int baud);
-static int  keyspan_pda_write_room	(struct usb_serial_port *port);
-static int  keyspan_pda_write		(struct usb_serial_port *port,
-					 int from_user,
-					 const unsigned char *buf,
-					 int count);
-static void keyspan_pda_write_bulk_callback (struct urb *urb);
-static int  keyspan_pda_chars_in_buffer (struct usb_serial_port *port);
-static int  keyspan_pda_ioctl		(struct usb_serial_port *port,
-					 struct file *file,
-					 unsigned int cmd,
-					 unsigned long arg);
-static void keyspan_pda_set_termios	(struct usb_serial_port *port,
-					 struct termios *old);
-static void keyspan_pda_break_ctl	(struct usb_serial_port *port,
-					 int break_state);
-static int  keyspan_pda_fake_startup	(struct usb_serial *serial);
-
-/* All of the device info needed for the Keyspan PDA serial converter */
-static __u16	keyspan_vendor_id		= KEYSPAN_VENDOR_ID;
-static __u16	keyspan_pda_fake_product_id	= KEYSPAN_PDA_FAKE_ID;
-static __u16	keyspan_pda_product_id		= KEYSPAN_PDA_ID;
-static struct usb_serial_device_type keyspan_pda_fake_device = {
-	name:			"Keyspan PDA - (prerenumeration)",
-	idVendor:		&keyspan_vendor_id,		/* the Keyspan PDA vendor ID */
-	idProduct:		&keyspan_pda_fake_product_id,	/* the Keyspan PDA initial product id */
-	needs_interrupt_in:	DONT_CARE,			/* don't have to have an interrupt in endpoint */
-	needs_bulk_in:		DONT_CARE,			/* don't have to have a bulk in endpoint */
-	needs_bulk_out:		DONT_CARE,			/* don't have to have a bulk out endpoint */
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_pda_fake_startup
-};
-static struct usb_serial_device_type keyspan_pda_device = {
-	name:			"Keyspan PDA",
-	idVendor:		&keyspan_vendor_id,		/* the Keyspan PDA vendor ID */
-	idProduct:		&keyspan_pda_product_id,	/* the Keyspan PDA product id */
-	needs_interrupt_in:	MUST_HAVE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	1,
-	num_bulk_in:		0,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			keyspan_pda_open,
-	close:			keyspan_pda_close,
-	write:			keyspan_pda_write,
-	write_room:		keyspan_pda_write_room,
-	write_bulk_callback: 	keyspan_pda_write_bulk_callback,
-	chars_in_buffer:	keyspan_pda_chars_in_buffer,
-	throttle:		keyspan_pda_rx_throttle,
-	unthrottle:		keyspan_pda_rx_unthrottle,
-	startup:		keyspan_pda_startup,
-	ioctl:			keyspan_pda_ioctl,
-	set_termios:		keyspan_pda_set_termios,
-	break_ctl:		keyspan_pda_break_ctl,
-};
-#endif
-
-
-/* To add support for another serial converter, create a usb_serial_device_type
-   structure for that device, and add it to this list, making sure that the
-   last  entry is NULL. */
-static struct usb_serial_device_type *usb_serial_devices[] = {
-#ifdef CONFIG_USB_SERIAL_GENERIC
-	&generic_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-	&whiteheat_fake_device,
-	&whiteheat_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_VISOR
-	&handspring_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_FTDI_SIO
-	&ftdi_sio_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-	&keyspan_pda_fake_device,
-	&keyspan_pda_device,
-#endif
-	NULL
-};
+extern struct usb_serial_device_type handspring_device;
+extern struct usb_serial_device_type whiteheat_fake_device;
+extern struct usb_serial_device_type whiteheat_device;
+extern struct usb_serial_device_type ftdi_sio_device;
+extern struct usb_serial_device_type keyspan_pda_fake_device;
+extern struct usb_serial_device_type keyspan_pda_device;
 
 
 /* determine if we should include the EzUSB loader functions */
 #if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_WHITEHEAT)
 	#define	USES_EZUSB_FUNCTIONS
+	extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
+	extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
 #else
 	#undef 	USES_EZUSB_FUNCTIONS
 #endif
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int serial_paranoia_check (struct usb_serial *serial, const char *function)
+{
+	if (!serial) {
+		dbg("%s - serial == NULL", function);
+		return -1;
+	}
+	if (serial->magic != USB_SERIAL_MAGIC) {
+		dbg("%s - bad magic number for serial", function);
+		return -1;
+	}
+	if (!serial->type) {
+		dbg("%s - serial->type == NULL!", function);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static inline int port_paranoia_check (struct usb_serial_port *port, const char *function)
+{
+	if (!port) {
+		dbg("%s - port == NULL", function);
+		return -1;
+	}
+	if (port->magic != USB_SERIAL_PORT_MAGIC) {
+		dbg("%s - bad magic number for port", function);
+		return -1;
+	}
+	if (!port->serial) {
+		dbg("%s - port->serial == NULL", function);
+		return -1;
+	}
+	if (!port->tty) {
+		dbg("%s - port->tty == NULL", function);
+		return -1;
+	}
+
+	return 0;
+}
+
 
 #endif	/* ifdef __LINUX_USB_SERIAL_H */
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- v2.3.99-pre3/linux/drivers/usb/serial/usbserial.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/usbserial.c	Wed Apr  5 16:58:38 2000
@@ -0,0 +1,1323 @@
+/*
+ * USB Serial Converter driver
+ *
+ *	(C) Copyright (C) 1999, 2000
+ *	    Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * This driver was originally based on the ACM driver by Armin Fuerst (which was 
+ * based on a driver by Brad Keryan)
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ * 
+ * (04/03/2000) gkh
+ *	Changed the probe process to remove the module unload races.
+ *	Changed where the tty layer gets initialized to have devfs work nicer.
+ *	Added initial devfs support.
+ *
+ * (03/26/2000) gkh
+ *	Split driver up into device specific pieces.
+ * 
+ * (03/19/2000) gkh
+ *	Fixed oops that could happen when device was removed while a program
+ *	was talking to the device.
+ *	Removed the static urbs and now all urbs are created and destroyed
+ *	dynamically.
+ *	Reworked the internal interface. Now everything is based on the 
+ *	usb_serial_port structure instead of the larger usb_serial structure.
+ *	This fixes the bug that a multiport device could not have more than
+ *	one port open at one time.
+ *
+ * (03/17/2000) gkh
+ *	Added config option for debugging messages.
+ *	Added patch for keyspan pda from Brian Warner.
+ *
+ * (03/06/2000) gkh
+ *	Added the keyspan pda code from Brian Warner <warner@lothar.com>
+ *	Moved a bunch of the port specific stuff into its own structure. This
+ *	is in anticipation of the true multiport devices (there's a bug if you
+ *	try to access more than one port of any multiport device right now)
+ *
+ * (02/21/2000) gkh
+ *	Made it so that any serial devices only have to specify which functions
+ *	they want to overload from the generic function calls (great, 
+ *	inheritance in C, in a driver, just what I wanted...)
+ *	Added support for set_termios and ioctl function calls. No drivers take
+ *	advantage of this yet.
+ *	Removed the #ifdef MODULE, now there is no module specific code.
+ *	Cleaned up a few comments in usb-serial.h that were wrong (thanks again
+ *	to Miles Lott).
+ *	Small fix to get_free_serial.
+ *
+ * (02/14/2000) gkh
+ *	Removed the Belkin and Peracom functionality from the driver due to
+ *	the lack of support from the vendor, and me not wanting people to 
+ *	accidenatly buy the device, expecting it to work with Linux.
+ *	Added read_bulk_callback and write_bulk_callback to the type structure
+ *	for the needs of the FTDI and WhiteHEAT driver.
+ *	Changed all reverences to FTDI to FTDI_SIO at the request of Bill
+ *	Ryder.
+ *	Changed the output urb size back to the max endpoint size to make
+ *	the ftdi_sio driver have it easier, and due to the fact that it didn't
+ *	really increase the speed any.
+ *
+ * (02/11/2000) gkh
+ *	Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
+ *	patch from Miles Lott (milos@insync.net).
+ *	Fixed bug with not restoring the minor range that a device grabs, if
+ *	the startup function fails (thanks Miles for finding this).
+ *
+ * (02/05/2000) gkh
+ *	Added initial framework for the Keyspan PDA serial converter so that
+ *	Brian Warner has a place to put his code.
+ *	Made the ezusb specific functions generic enough that different
+ *	devices can use them (whiteheat and keyspan_pda both need them).
+ *	Split out a whole bunch of structure and other stuff to a seperate
+ *	usb-serial.h file.
+ *	Made the Visor connection messages a little more understandable, now
+ *	that Miles Lott (milos@insync.net) has gotten the Generic channel to
+ *	work. Also made them always show up in the log file.
+ * 
+ * (01/25/2000) gkh
+ *	Added initial framework for FTDI serial converter so that Bill Ryder
+ *	has a place to put his code.
+ *	Added the vendor specific info from Handspring. Now we can print out
+ *	informational debug messages as well as understand what is happening.
+ *
+ * (01/23/2000) gkh
+ *	Fixed problem of crash when trying to open a port that didn't have a
+ *	device assigned to it. Made the minor node finding a little smarter,
+ *	now it looks to find a continous space for the new device.
+ *
+ * (01/21/2000) gkh
+ *	Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
+ *	Fixed get_serial_by_minor which was all messed up for multi port 
+ *	devices. Fixed multi port problem for generic devices. Now the number
+ *	of ports is determined by the number of bulk out endpoints for the
+ *	generic device.
+ *
+ * (01/19/2000) gkh
+ *	Removed lots of cruft that was around from the old (pre urb) driver 
+ *	interface.
+ *	Made the serial_table dynamic. This should save lots of memory when
+ *	the number of minor nodes goes up to 256.
+ *	Added initial support for devices that have more than one port. 
+ *	Added more debugging comments for the Visor, and added a needed 
+ *	set_configuration call.
+ *
+ * (01/17/2000) gkh
+ *	Fixed the WhiteHEAT firmware (my processing tool had a bug)
+ *	and added new debug loader firmware for it.
+ *	Removed the put_char function as it isn't really needed.
+ *	Added visor startup commands as found by the Win98 dump.
+ * 
+ * (01/13/2000) gkh
+ *	Fixed the vendor id for the generic driver to the one I meant it to be.
+ *
+ * (01/12/2000) gkh
+ *	Forget the version numbering...that's pretty useless...
+ *	Made the driver able to be compiled so that the user can select which
+ *	converter they want to use. This allows people who only want the Visor
+ *	support to not pay the memory size price of the WhiteHEAT.
+ *	Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
+ *	grabbed the root hub. Not good.
+ * 
+ * version 0.4.0 (01/10/2000) gkh
+ *	Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
+ *	device. Added startup function to allow firmware to be downloaded to
+ *	a device if it needs to be.
+ *	Added firmware download logic to the WhiteHEAT device.
+ *	Started to add #defines to split up the different drivers for potential
+ *	configuration option.
+ *	
+ * version 0.3.1 (12/30/99) gkh
+ *      Fixed problems with urb for bulk out.
+ *      Added initial support for multiple sets of endpoints. This enables
+ *      the Handspring Visor to be attached successfully. Only the first
+ *      bulk in / bulk out endpoint pair is being used right now.
+ *
+ * version 0.3.0 (12/27/99) gkh
+ *	Added initial support for the Handspring Visor based on a patch from
+ *	Miles Lott (milos@sneety.insync.net)
+ *	Cleaned up the code a bunch and converted over to using urbs only.
+ *
+ * version 0.2.3 (12/21/99) gkh
+ *	Added initial support for the Connect Tech WhiteHEAT converter.
+ *	Incremented the number of ports in expectation of getting the
+ *	WhiteHEAT to work properly (4 ports per connection).
+ *	Added notification on insertion and removal of what port the
+ *	device is/was connected to (and what kind of device it was).
+ *
+ * version 0.2.2 (12/16/99) gkh
+ *	Changed major number to the new allocated number. We're legal now!
+ *
+ * version 0.2.1 (12/14/99) gkh
+ *	Fixed bug that happens when device node is opened when there isn't a
+ *	device attached to it. Thanks to marek@webdesign.no for noticing this.
+ *
+ * version 0.2.0 (11/10/99) gkh
+ *	Split up internals to make it easier to add different types of serial 
+ *	converters to the code.
+ *	Added a "generic" driver that gets it's vendor and product id
+ *	from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
+ *	for the idea and sample code (from the usb scanner driver.)
+ *	Cleared up any licensing questions by releasing it under the GNU GPL.
+ *
+ * version 0.1.2 (10/25/99) gkh
+ * 	Fixed bug in detecting device.
+ *
+ * version 0.1.1 (10/05/99) gkh
+ * 	Changed the major number to not conflict with anything else.
+ *
+ * version 0.1 (09/28/99) gkh
+ * 	Can recognize the two different devices and start up a read from
+ *	device when asked to. Writes also work. No control signals yet, this
+ *	all is vendor specific data (i.e. no spec), also no control for
+ *	different baud rates or other bit settings.
+ *	Currently we are using the same devid as the acm driver. This needs
+ *	to change.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+/* Module information */
+MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
+MODULE_DESCRIPTION("USB Serial Driver");
+
+#include "usb-serial.h"
+
+
+/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
+/* need to always compile these in, as some of the other devices use these functions as their own. */
+/* if a driver does not provide a function pointer, the generic function will be called. */
+static int  generic_open		(struct usb_serial_port *port, struct file *filp);
+static void generic_close		(struct usb_serial_port *port, struct file *filp);
+static int  generic_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  generic_write_room		(struct usb_serial_port *port);
+static int  generic_chars_in_buffer	(struct usb_serial_port *port);
+static void generic_read_bulk_callback	(struct urb *urb);
+static void generic_write_bulk_callback	(struct urb *urb);
+
+
+#ifdef CONFIG_USB_SERIAL_GENERIC
+static __u16	vendor	= 0x05f9;
+static __u16	product	= 0xffff;
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+/* All of the device info needed for the Generic Serial Converter */
+static struct usb_serial_device_type generic_device = {
+	name:			"Generic",
+	idVendor:		&vendor,		/* use the user specified vendor id */
+	idProduct:		&product,		/* use the user specified product id */
+	needs_interrupt_in:	DONT_CARE,		/* don't have to have an interrupt in endpoint */
+	needs_bulk_in:		DONT_CARE,		/* don't have to have a bulk in endpoint */
+	needs_bulk_out:		DONT_CARE,		/* don't have to have a bulk out endpoint */
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+};
+#endif
+
+
+/* To add support for another serial converter, create a usb_serial_device_type
+   structure for that device, and add it to this list, making sure that the
+   last  entry is NULL. */
+static struct usb_serial_device_type *usb_serial_devices[] = {
+#ifdef CONFIG_USB_SERIAL_GENERIC
+	&generic_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_WHITEHEAT
+	&whiteheat_fake_device,
+	&whiteheat_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_VISOR
+	&handspring_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_FTDI_SIO
+	&ftdi_sio_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
+	&keyspan_pda_fake_device,
+	&keyspan_pda_device,
+#endif
+	NULL
+};
+
+
+/* variables needed for the tty_driver structure */
+static char *driver_name	= "usb";
+static char *tty_driver_name	= "usb/tty/%d";
+
+
+/* local function prototypes */
+static int  serial_open (struct tty_struct *tty, struct file * filp);
+static void serial_close (struct tty_struct *tty, struct file * filp);
+static int  serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
+static int  serial_write_room (struct tty_struct *tty);
+static int  serial_chars_in_buffer (struct tty_struct *tty);
+static void serial_throttle (struct tty_struct * tty);
+static void serial_unthrottle (struct tty_struct * tty);
+static int  serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
+static void serial_set_termios (struct tty_struct *tty, struct termios * old);
+
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
+static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_driver usb_serial_driver = {
+	name:		"serial",
+	probe:		usb_serial_probe,
+	disconnect:	usb_serial_disconnect,
+};
+
+static int			serial_refcount;
+static struct tty_struct *	serial_tty[SERIAL_TTY_MINORS];
+static struct termios *		serial_termios[SERIAL_TTY_MINORS];
+static struct termios *		serial_termios_locked[SERIAL_TTY_MINORS];
+static struct usb_serial	*serial_table[SERIAL_TTY_MINORS] = {NULL, };
+
+
+
+static struct usb_serial *get_serial_by_minor (int minor)
+{
+	return serial_table[minor];
+}
+
+
+static struct usb_serial *get_free_serial (int num_ports, int *minor)
+{
+	struct usb_serial *serial = NULL;
+	int i, j;
+	int good_spot;
+
+	dbg("get_free_serial %d", num_ports);
+
+	*minor = 0;
+	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+		if (serial_table[i])
+			continue;
+
+		good_spot = 1;
+		for (j = 1; j <= num_ports-1; ++j)
+			if (serial_table[i+j])
+				good_spot = 0;
+		if (good_spot == 0)
+			continue;
+			
+		if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
+			err("Out of memory");
+			return NULL;
+		}
+		memset(serial, 0, sizeof(struct usb_serial));
+		serial->magic = USB_SERIAL_MAGIC;
+		serial_table[i] = serial;
+		*minor = i;
+		dbg("minor base = %d", *minor);
+		for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
+			serial_table[i] = serial;
+		return serial;
+		}
+	return NULL;
+}
+
+
+static void return_serial (struct usb_serial *serial)
+{
+	int i;
+
+	dbg("return_serial");
+
+	if (serial == NULL)
+		return;
+
+	for (i = 0; i < serial->num_ports; ++i) {
+		serial_table[serial->minor + i] = NULL;
+	}
+
+	return;
+}
+
+
+#ifdef USES_EZUSB_FUNCTIONS
+/* EZ-USB Control and Status Register.  Bit 0 controls 8051 reset */
+#define CPUCS_REG    0x7F92
+
+int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest)
+{
+	int result;
+	unsigned char *transfer_buffer =  kmalloc (length, GFP_KERNEL);
+
+//	dbg("ezusb_writememory %x, %d", address, length);
+
+	if (!transfer_buffer) {
+		err("ezusb_writememory: kmalloc(%d) failed.", length);
+		return -ENOMEM;
+	}
+	memcpy (transfer_buffer, data, length);
+	result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
+	kfree (transfer_buffer);
+	return result;
+}
+
+
+int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
+{
+	int	response;
+	dbg("ezusb_set_reset: %d", reset_bit);
+	response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
+	if (response < 0) {
+		err("ezusb_set_reset %d failed", reset_bit);
+	}
+	return response;
+}
+
+#endif	/* USES_EZUSB_FUNCTIONS */
+
+
+/*****************************************************************************
+ * Driver tty interface functions
+ *****************************************************************************/
+static int serial_open (struct tty_struct *tty, struct file * filp)
+{
+	struct usb_serial *serial;
+	struct usb_serial_port *port;
+	int portNumber;
+	
+	dbg("serial_open");
+
+	/* initialize the pointer incase something fails */
+	tty->driver_data = NULL;
+
+	/* get the serial object associated with this tty pointer */
+	serial = get_serial_by_minor (MINOR(tty->device));
+
+	if (serial_paranoia_check (serial, "serial_open")) {
+		return -ENODEV;
+	}
+
+	/* set up our port structure */
+	portNumber = MINOR(tty->device) - serial->minor;
+	port = &serial->port[portNumber];
+	port->number = portNumber;
+	port->serial = serial;
+	port->magic = USB_SERIAL_PORT_MAGIC;
+	
+	/* make the tty driver remember our port object, and us it */
+	tty->driver_data = port;
+	port->tty = tty;
+	 
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->open) {
+		return (serial->type->open(port, filp));
+	} else {
+		return (generic_open(port, filp));
+	}
+}
+
+
+static void serial_close(struct tty_struct *tty, struct file * filp)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial;
+
+	dbg("serial_close");
+
+	if (port_paranoia_check (port, "serial_close")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "serial_close")) {
+		return;
+	}
+
+	dbg("serial_close port %d", port->number);
+	
+	if (!port->active) {
+		dbg ("port not opened");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->close) {
+		serial->type->close(port, filp);
+	} else {
+		generic_close(port, filp);
+	}
+}	
+
+
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial;
+	
+	dbg("serial_write");
+	
+	if (port_paranoia_check (port, "serial_write")) {
+		return -ENODEV;
+	}
+	
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "serial_write")) {
+		return -ENODEV;
+	}
+	
+	dbg("serial_write port %d, %d byte(s)", port->number, count);
+
+	if (!port->active) {
+		dbg ("port not opened");
+		return -EINVAL;
+	}
+	
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->write) {
+		return (serial->type->write(port, from_user, buf, count));
+	} else {
+		return (generic_write(port, from_user, buf, count));
+	}
+}
+
+
+static int serial_write_room (struct tty_struct *tty) 
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial;
+	
+	dbg("serial_write_room");
+	
+	if (port_paranoia_check (port, "serial_write")) {
+		return -ENODEV;
+	}
+	
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "serial_write")) {
+		return -ENODEV;
+	}
+	
+	dbg("serial_write_room port %d", port->number);
+	
+	if (!port->active) {
+		dbg ("port not open");
+		return -EINVAL;
+	}
+	
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->write_room) {
+		return (serial->type->write_room(port));
+	} else {
+		return (generic_write_room(port));
+	}
+}
+
+
+static int serial_chars_in_buffer (struct tty_struct *tty) 
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial;
+	
+	dbg("serial_chars_in_buffer");
+	
+	if (port_paranoia_check (port, "serial_chars_in_buffer")) {
+		return -ENODEV;
+	}
+	
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
+		return -ENODEV;
+	}
+	
+	if (!port->active) {
+		dbg ("port not open");
+		return -EINVAL;
+	}
+	
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->chars_in_buffer) {
+		return (serial->type->chars_in_buffer(port));
+	} else {
+		return (generic_chars_in_buffer(port));
+	}
+}
+
+
+static void serial_throttle (struct tty_struct * tty)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial;
+	
+	dbg("serial_throttle");
+	
+	if (port_paranoia_check (port, "serial_throttle")) {
+		return;
+	}
+	
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "serial_throttle")) {
+		return;
+	}
+	
+	dbg("serial_throttle port %d", port->number);
+	
+	if (!port->active) {
+		dbg ("port not open");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function */
+	if (serial->type->throttle) {
+		serial->type->throttle(port);
+	}
+
+	return;
+}
+
+
+static void serial_unthrottle (struct tty_struct * tty)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial;
+	
+	dbg("serial_unthrottle");
+	
+	if (port_paranoia_check (port, "serial_unthrottle")) {
+		return;
+	}
+	
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "serial_unthrottle")) {
+		return;
+	}
+	
+	dbg("serial_unthrottle port %d", port->number);
+	
+	if (!port->active) {
+		dbg ("port not open");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function */
+	if (serial->type->unthrottle) {
+		serial->type->unthrottle(port);
+	}
+
+	return;
+}
+
+
+static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial;
+	
+	dbg("serial_ioctl");
+	
+	if (port_paranoia_check (port, "serial_ioctl")) {
+		return -ENODEV;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "serial_ioctl")) {
+		return -ENODEV;
+	}
+	
+	dbg("serial_ioctl port %d", port->number);
+	
+	if (!port->active) {
+		dbg ("port not open");
+		return -ENODEV;
+	}
+
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->ioctl) {
+		return (serial->type->ioctl(port, file, cmd, arg));
+	} else {
+		return -ENOIOCTLCMD;
+	}
+}
+
+
+static void serial_set_termios (struct tty_struct *tty, struct termios * old)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial;
+	
+	dbg("serial_set_termios");
+	
+	if (port_paranoia_check (port, "serial_set_termios")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "serial_set_termios")) {
+		return;
+	}
+
+	dbg("serial_set_termios port %d", port->number);
+
+	if (!port->active) {
+		dbg ("port not open");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->set_termios) {
+		serial->type->set_termios(port, old);
+	}
+	
+	return;
+}
+
+
+static void serial_break (struct tty_struct *tty, int break_state)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial;
+	
+	dbg("serial_break");
+	
+	if (port_paranoia_check (port, "serial_break")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "serial_break")) {
+		return;
+	}
+
+	dbg("serial_break port %d", port->number);
+
+	if (!port->active) {
+		dbg ("port not open");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function if it is
+           available */
+	if (serial->type->break_ctl) {
+		serial->type->break_ctl(port, break_state);
+	}
+}
+
+
+
+/*****************************************************************************
+ * generic devices specific driver functions
+ *****************************************************************************/
+static int generic_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+
+	dbg("generic_open port %d", port->number);
+
+	if (port->active) {
+		dbg ("device already open");
+		return -EINVAL;
+	}
+	port->active = 1;
+ 
+	/* if we have a bulk interrupt, start reading from it */
+	if (serial->num_bulk_in) {
+		/*Start reading from the device*/
+		if (usb_submit_urb(port->read_urb))
+			dbg("usb_submit_urb(read bulk) failed");
+	}
+
+	return (0);
+}
+
+
+static void generic_close (struct usb_serial_port *port, struct file * filp)
+{
+	struct usb_serial *serial = port->serial;
+
+	dbg("generic_close port %d", port->number);
+	
+	/* shutdown any bulk reads that might be going on */
+	if (serial->num_bulk_out) {
+		usb_unlink_urb (port->write_urb);
+	}
+	if (serial->num_bulk_in) {
+		usb_unlink_urb (port->read_urb);
+	}
+
+	port->active = 0;
+}
+
+
+static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = port->serial;
+
+	dbg("generic_serial_write port %d", port->number);
+
+	if (count == 0) {
+		dbg("write request of 0 bytes");
+		return (0);
+	}
+
+	/* only do something if we have a bulk out endpoint */
+	if (serial->num_bulk_out) {
+		if (port->write_urb->status == -EINPROGRESS) {
+			dbg ("already writing");
+			return (0);
+		}
+
+		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+		if (from_user) {
+			copy_from_user(port->write_urb->transfer_buffer, buf, count);
+		}
+		else {
+			memcpy (port->write_urb->transfer_buffer, buf, count);
+		}  
+
+		/* send the data out the bulk port */
+		port->write_urb->transfer_buffer_length = count;
+
+		if (usb_submit_urb(port->write_urb))
+			dbg("usb_submit_urb(write bulk) failed");
+
+		return (count);
+	}
+	
+	/* no bulk out, so return 0 bytes written */
+	return (0);
+} 
+
+
+static int generic_write_room (struct usb_serial_port *port)
+{
+	struct usb_serial *serial = port->serial;
+	int room;
+
+	dbg("generic_write_room port %d", port->number);
+	
+	if (serial->num_bulk_out) {
+		if (port->write_urb->status == -EINPROGRESS)
+			room = 0;
+		else
+			room = port->bulk_out_size;
+		dbg("generic_write_room returns %d", room);
+		return (room);
+	}
+	
+	return (0);
+}
+
+
+static int generic_chars_in_buffer (struct usb_serial_port *port)
+{
+	struct usb_serial *serial = port->serial;
+
+	dbg("generic_chars_in_buffer port %d", port->number);
+	
+	if (serial->num_bulk_out) {
+		if (port->write_urb->status == -EINPROGRESS) {
+			return (port->bulk_out_size);
+		}
+	}
+
+	return (0);
+}
+
+
+static void generic_read_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+       	struct tty_struct *tty;
+       	unsigned char *data = urb->transfer_buffer;
+	int i;
+
+	dbg("generic_read_bulk_callback");
+
+	if (port_paranoia_check (port, "generic_read_bulk_callback")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "generic_read_bulk_callback")) {
+		return;
+	}
+	
+	if (urb->status) {
+		dbg("nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+#ifdef DEBUG
+	if (urb->actual_length) {
+		printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+		for (i = 0; i < urb->actual_length; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+
+	tty = port->tty;
+	if (urb->actual_length) {
+		for (i = 0; i < urb->actual_length ; ++i) {
+			 tty_insert_flip_char(tty, data[i], 0);
+	  	}
+	  	tty_flip_buffer_push(tty);
+	}
+
+	/* Continue trying to always read  */
+	if (usb_submit_urb(urb))
+		dbg("failed resubmitting read urb");
+
+	return;
+}
+
+
+static void generic_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+       	struct tty_struct *tty;
+
+	dbg("generic_write_bulk_callback");
+
+	if (port_paranoia_check (port, "generic_write_bulk_callback")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "generic_write_bulk_callback")) {
+		return;
+	}
+	
+	if (urb->status) {
+		dbg("nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	tty = port->tty;
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+	
+	return;
+}
+
+
+static struct tty_driver * usb_serial_tty_driver_init (struct usb_serial *serial)
+{
+	struct tty_driver *serial_tty_driver;
+
+	if (!(serial_tty_driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL))) {
+		err("Out of memory");
+		return NULL;
+	}
+
+	memset (serial_tty_driver, 0x00, sizeof(struct tty_driver));
+
+	/* initialize the entries that we don't want to be NULL */
+	serial_tty_driver->magic		= TTY_DRIVER_MAGIC;
+	serial_tty_driver->driver_name		= driver_name;
+	serial_tty_driver->name			= tty_driver_name;
+	serial_tty_driver->major		= SERIAL_TTY_MAJOR;
+	serial_tty_driver->minor_start		= serial->minor;
+	serial_tty_driver->num			= serial->num_ports;
+	serial_tty_driver->type			= TTY_DRIVER_TYPE_SERIAL;
+	serial_tty_driver->subtype		= SERIAL_TYPE_NORMAL;
+	serial_tty_driver->flags		= TTY_DRIVER_REAL_RAW;
+	serial_tty_driver->refcount		= &serial_refcount;
+	serial_tty_driver->table		= serial_tty;
+	serial_tty_driver->termios		= serial_termios;
+	serial_tty_driver->termios_locked	= serial_termios_locked;
+	serial_tty_driver->open			= serial_open;
+	serial_tty_driver->close		= serial_close;
+	serial_tty_driver->write		= serial_write;
+	serial_tty_driver->write_room		= serial_write_room;
+	serial_tty_driver->ioctl		= serial_ioctl;
+	serial_tty_driver->set_termios		= serial_set_termios;
+	serial_tty_driver->throttle		= serial_throttle;
+	serial_tty_driver->unthrottle		= serial_unthrottle;
+	serial_tty_driver->break_ctl		= serial_break;
+	serial_tty_driver->chars_in_buffer	= serial_chars_in_buffer;
+	serial_tty_driver->init_termios		= tty_std_termios;
+	serial_tty_driver->init_termios.c_cflag	= B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+	return serial_tty_driver;
+}
+
+
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_serial *serial = NULL;
+	struct usb_serial_port *port;
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
+	struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
+	struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
+	struct usb_serial_device_type *type;
+	int device_num;
+	int minor;
+	int buffer_size;
+	int i;
+	char interrupt_pipe;
+	char bulk_in_pipe;
+	char bulk_out_pipe;
+	int num_interrupt_in = 0;
+	int num_bulk_in = 0;
+	int num_bulk_out = 0;
+	int num_ports;
+	
+	/* loop through our list of known serial converters, and see if this device matches */
+	device_num = 0;
+	while (usb_serial_devices[device_num] != NULL) {
+		type = usb_serial_devices[device_num];
+		dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
+
+		/* look at the device descriptor */
+		if ((dev->descriptor.idVendor == *(type->idVendor)) &&
+		    (dev->descriptor.idProduct == *(type->idProduct))) {
+
+			dbg("descriptor matches...looking at the endpoints");
+
+			/* descriptor matches, let's try to find the endpoints needed */
+			interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
+			
+			/* check out the endpoints */
+			interface = &dev->actconfig->interface[ifnum].altsetting[0];
+			for (i = 0; i < interface->bNumEndpoints; ++i) {
+				endpoint = &interface->endpoint[i];
+		
+				if ((endpoint->bEndpointAddress & 0x80) &&
+				    ((endpoint->bmAttributes & 3) == 0x02)) {
+					/* we found a bulk in endpoint */
+					dbg("found bulk in");
+					bulk_in_pipe = HAS;
+					bulk_in_endpoint[num_bulk_in] = endpoint;
+					++num_bulk_in;
+				}
+
+				if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+				    ((endpoint->bmAttributes & 3) == 0x02)) {
+					/* we found a bulk out endpoint */
+					dbg("found bulk out");
+					bulk_out_pipe = HAS;
+					bulk_out_endpoint[num_bulk_out] = endpoint;
+					++num_bulk_out;
+				}
+		
+				if ((endpoint->bEndpointAddress & 0x80) &&
+				    ((endpoint->bmAttributes & 3) == 0x03)) {
+					/* we found a interrupt in endpoint */
+					dbg("found interrupt in");
+					interrupt_pipe = HAS;
+					interrupt_in_endpoint[num_interrupt_in] = endpoint;
+					++num_interrupt_in;
+				}
+
+			}
+	
+			/* verify that we found all of the endpoints that we need */
+			if ((interrupt_pipe & type->needs_interrupt_in) &&
+			    (bulk_in_pipe & type->needs_bulk_in) &&
+			    (bulk_out_pipe & type->needs_bulk_out)) {
+				/* found all that we need */
+				MOD_INC_USE_COUNT;
+				info("%s converter detected", type->name);
+
+#ifdef CONFIG_USB_SERIAL_GENERIC
+				if (type == &generic_device)
+					num_ports = num_bulk_out;
+				else
+#endif
+					num_ports = type->num_ports;
+
+				serial = get_free_serial (num_ports, &minor);
+				if (serial == NULL) {
+					err("No more free serial devices");
+					MOD_DEC_USE_COUNT;
+					return NULL;
+				}
+	
+			       	serial->dev = dev;
+				serial->type = type;
+				serial->minor = minor;
+				serial->num_ports = num_ports;
+				serial->num_bulk_in = num_bulk_in;
+				serial->num_bulk_out = num_bulk_out;
+				serial->num_interrupt_in = num_interrupt_in;
+
+				/* initialize a tty_driver for this device */
+				serial->tty_driver = usb_serial_tty_driver_init (serial);
+				if (serial->tty_driver == NULL) {
+					err("Can't create a tty_serial_driver");
+					goto probe_error;
+				}
+
+				if (tty_register_driver (serial->tty_driver)) {
+					err("failed to register tty driver");
+					goto probe_error;
+				}
+
+				/* collect interrupt_in endpoints now, because
+				   the keyspan_pda startup function needs
+				   to know about them */
+				for (i = 0; i < num_interrupt_in; ++i) {
+					port = &serial->port[i];
+					buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
+					port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+					if (!port->interrupt_in_buffer) {
+						err("Couldn't allocate interrupt_in_buffer");
+						goto probe_error;
+					}
+					port->interrupt_in_endpoint = interrupt_in_endpoint[i];
+				}
+
+				/* if this device type has a startup function, call it */
+				if (type->startup) {
+					if (type->startup (serial)) {
+						goto probe_error;
+					}
+				}
+
+				/* set up the endpoint information */
+				for (i = 0; i < num_bulk_in; ++i) {
+					port = &serial->port[i];
+					port->read_urb = usb_alloc_urb (0);
+					if (!port->read_urb) {
+						err("No free urbs available");
+						goto probe_error;
+					}
+					buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
+					port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+					if (!port->bulk_in_buffer) {
+						err("Couldn't allocate bulk_in_buffer");
+						goto probe_error;
+					}
+					if (serial->type->read_bulk_callback) {
+						FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+								port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port);
+					} else {
+						FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+								port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port);
+					}
+				}
+
+				for (i = 0; i < num_bulk_out; ++i) {
+					port = &serial->port[i];
+					port->write_urb = usb_alloc_urb(0);
+					if (!port->write_urb) {
+						err("No free urbs available");
+						goto probe_error;
+					}
+					port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
+					port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
+					if (!port->bulk_out_buffer) {
+						err("Couldn't allocate bulk_out_buffer");
+						goto probe_error;
+					}
+					if (serial->type->write_bulk_callback) {
+						FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+								port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port);
+					} else {
+						FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+								port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port);
+					}
+				}
+
+#if 0 /* use this code when WhiteHEAT is up and running */
+				for (i = 0; i < num_interrupt_in; ++i) {
+					port = &serial->port[i];
+					port->control_urb = usb_alloc_urb(0);
+					if (!port->control_urb) {
+						err("No free urbs available");
+						goto probe_error;
+					}
+					buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
+					port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+					if (!port->interrupt_in_buffer) {
+						err("Couldn't allocate interrupt_in_buffer");
+						goto probe_error;
+					}
+					FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
+							port->interrupt_in_buffer, buffer_size, serial_control_irq,
+							port, interrupt_in_endpoint[i]->bInterval);
+				}
+#endif
+
+				for (i = 0; i < serial->num_ports; ++i) {
+					info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
+				}
+
+				return serial;
+			} else {
+				info("descriptors matched, but endpoints did not");
+			}
+		}
+
+		/* look at the next type in our list */
+		++device_num;
+	}
+
+probe_error:
+	if (serial) {
+		for (i = 0; i < num_bulk_in; ++i) {
+			port = &serial->port[i];
+			if (port->read_urb)
+				usb_free_urb (port->read_urb);
+			if (serial->port[i].bulk_in_buffer[i])
+				kfree (serial->port[i].bulk_in_buffer);
+		}
+		for (i = 0; i < num_bulk_out; ++i) {
+			port = &serial->port[i];
+			if (port->write_urb)
+				usb_free_urb (port->write_urb);
+			if (serial->port[i].bulk_out_buffer)
+				kfree (serial->port[i].bulk_out_buffer);
+		}
+		for (i = 0; i < num_interrupt_in; ++i) {
+			port = &serial->port[i];
+			if (port->control_urb)
+				usb_free_urb (port->control_urb);
+			if (serial->port[i].interrupt_in_buffer)
+				kfree (serial->port[i].interrupt_in_buffer);
+		}
+		
+		/* return the minor range that this device had */
+		return_serial (serial);
+
+		/* if this device has a tty_driver, then unregister it and free it */
+		if (serial->tty_driver) {
+			tty_unregister_driver (serial->tty_driver);
+			kfree (serial->tty_driver);
+			serial->tty_driver = NULL;
+		}
+
+		/* free up any memory that we allocated */
+		kfree (serial);
+		MOD_DEC_USE_COUNT;
+	}
+	return NULL;
+}
+
+
+static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_serial *serial = (struct usb_serial *) ptr;
+	struct usb_serial_port *port;
+	int i;
+
+	if (serial) {
+		for (i = 0; i < serial->num_ports; ++i)
+			serial->port[i].active = 0;
+
+		for (i = 0; i < serial->num_bulk_in; ++i) {
+			port = &serial->port[i];
+			if (port->read_urb) {
+				usb_unlink_urb (port->read_urb);
+				usb_free_urb (port->read_urb);
+			}
+			if (port->bulk_in_buffer)
+				kfree (port->bulk_in_buffer);
+		}
+		for (i = 0; i < serial->num_bulk_out; ++i) {
+			port = &serial->port[i];
+			if (port->write_urb) {
+				usb_unlink_urb (port->write_urb);
+				usb_free_urb (port->write_urb);
+			}
+			if (port->bulk_out_buffer)
+				kfree (port->bulk_out_buffer);
+		}
+		for (i = 0; i < serial->num_interrupt_in; ++i) {
+			port = &serial->port[i];
+			if (port->control_urb) {
+				usb_unlink_urb (port->control_urb);
+				usb_free_urb (port->control_urb);
+			}
+			if (port->interrupt_in_buffer)
+				kfree (port->interrupt_in_buffer);
+		}
+
+		for (i = 0; i < serial->num_ports; ++i) {
+			info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
+		}
+
+		/* return the minor range that this device had */
+		return_serial (serial);
+
+		/* if this device has a tty_driver, then unregister it and free it */
+		if (serial->tty_driver) {
+			tty_unregister_driver (serial->tty_driver);
+			kfree (serial->tty_driver);
+			serial->tty_driver = NULL;
+		}
+		/* free up any memory that we allocated */
+		kfree (serial);
+
+	} else {
+		info("device disconnected");
+	}
+	
+	MOD_DEC_USE_COUNT;
+}
+
+
+int usb_serial_init(void)
+{
+	int i;
+
+	/* Initalize our global data */
+	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+		serial_table[i] = NULL;
+	}
+
+	/* register the USB driver */
+	if (usb_register(&usb_serial_driver) < 0) {
+		return -1;
+	}
+
+	info("support registered");
+	return 0;
+}
+
+
+void usb_serial_exit(void)
+{
+	usb_deregister(&usb_serial_driver);
+}
+
+
+module_init(usb_serial_init);
+module_exit(usb_serial_exit);
+
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- v2.3.99-pre3/linux/drivers/usb/serial/visor.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/visor.c	Mon Mar 27 14:25:28 2000
@@ -0,0 +1,209 @@
+/*
+ * USB HandSpring Visor driver
+ *
+ *	(C) Copyright (C) 1999, 2000
+ *	    Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ * 
+ * (03/26/2000) gkh
+ *	Split driver up into device specific pieces.
+ * 
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_VISOR
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#include "visor.h"
+
+
+/* function prototypes for a handspring visor */
+static int  visor_open		(struct usb_serial_port *port, struct file *filp);
+static void visor_close		(struct usb_serial_port *port, struct file *filp);
+static void visor_throttle	(struct usb_serial_port *port);
+static void visor_unthrottle	(struct usb_serial_port *port);
+static int  visor_startup	(struct usb_serial *serial);
+
+/* All of the device info needed for the Handspring Visor */
+static __u16	handspring_vendor_id	= HANDSPRING_VENDOR_ID;
+static __u16	handspring_product_id	= HANDSPRING_VISOR_ID;
+struct usb_serial_device_type handspring_device = {
+	name:			"Handspring Visor",
+	idVendor:		&handspring_vendor_id,	/* the Handspring vendor ID */
+	idProduct:		&handspring_product_id,	/* the Handspring Visor product id */
+	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
+	num_interrupt_in:	0,
+	num_bulk_in:		2,
+	num_bulk_out:		2,
+	num_ports:		2,
+	open:			visor_open,
+	close:			visor_close,
+	throttle:		visor_throttle,
+	unthrottle:		visor_unthrottle,
+	startup:		visor_startup,
+};
+
+
+/******************************************************************************
+ * Handspring Visor specific driver functions
+ ******************************************************************************/
+static int visor_open (struct usb_serial_port *port, struct file *filp)
+{
+	dbg("visor_open port %d", port->number);
+
+	if (port->active) {
+		dbg ("device already open");
+		return -EINVAL;
+	}
+
+	port->active = 1;
+
+	/*Start reading from the device*/
+	if (usb_submit_urb(port->read_urb))
+		dbg("usb_submit_urb(read bulk) failed");
+
+	return (0);
+}
+
+
+static void visor_close (struct usb_serial_port *port, struct file * filp)
+{
+	struct usb_serial *serial = port->serial;
+	unsigned char *transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
+	
+	dbg("visor_close port %d", port->number);
+			 
+	if (!transfer_buffer) {
+		err("visor_close: kmalloc(%d) failed.", 0x12);
+	} else {
+		/* send a shutdown message to the device */
+		usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
+				0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+	}
+
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+	port->active = 0;
+}
+
+
+static void visor_throttle (struct usb_serial_port *port)
+{
+	dbg("visor_throttle port %d", port->number);
+
+	usb_unlink_urb (port->read_urb);
+
+	return;
+}
+
+
+static void visor_unthrottle (struct usb_serial_port *port)
+{
+	dbg("visor_unthrottle port %d", port->number);
+
+	if (usb_unlink_urb (port->read_urb))
+		dbg("usb_submit_urb(read bulk) failed");
+
+	return;
+}
+
+
+static int  visor_startup (struct usb_serial *serial)
+{
+	int response;
+	int i;
+	unsigned char *transfer_buffer =  kmalloc (256, GFP_KERNEL);
+
+	if (!transfer_buffer) {
+		err("visor_startup: kmalloc(%d) failed.", 256);
+		return -ENOMEM;
+	}
+
+	dbg("visor_startup");
+
+	dbg("visor_setup: Set config to 1");
+	usb_set_configuration (serial->dev, 1);
+
+	/* send a get connection info request */
+	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
+					0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+	if (response < 0) {
+		err("visor_startup: error getting connection information");
+	} else {
+		struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
+		char *string;
+		info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
+		for (i = 0; i < connection_info->num_ports; ++i) {
+			switch (connection_info->connections[i].port_function_id) {
+				case VISOR_FUNCTION_GENERIC:
+					string = "Generic";
+					break;
+				case VISOR_FUNCTION_DEBUGGER:
+					string = "Debugger";
+					break;
+				case VISOR_FUNCTION_HOTSYNC:
+					string = "HotSync";
+					break;
+				case VISOR_FUNCTION_CONSOLE:
+					string = "Console";
+					break;
+				case VISOR_FUNCTION_REMOTE_FILE_SYS:
+					string = "Remote File System";
+					break;
+				default:
+					string = "unknown";
+					break;	
+			}
+			info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name, connection_info->connections[i].port, string, serial->minor + i);
+		}
+	}
+
+	/* ask for the number of bytes available, but ignore the response as it is broken */
+	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
+					0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
+	if (response < 0) {
+		err("visor_startup: error getting bytes available request");
+	}
+
+	kfree (transfer_buffer);
+
+	/* continue on with initialization */
+	return (0);
+}
+
+
+#endif	/* CONFIG_USB_SERIAL_VISOR*/
+
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/visor.h linux/drivers/usb/serial/visor.h
--- v2.3.99-pre3/linux/drivers/usb/serial/visor.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/visor.h	Mon Mar 27 14:25:28 2000
@@ -0,0 +1,74 @@
+/*
+ * USB HandSpring Visor driver
+ *
+ *	(C) Copyright (C) 1999, 2000
+ *	    Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ * 
+ */
+
+#ifndef __LINUX_USB_SERIAL_VISOR_H
+#define __LINUX_USB_SERIAL_VISOR_H
+
+
+#define HANDSPRING_VENDOR_ID		0x082d
+#define HANDSPRING_VISOR_ID		0x0100
+
+/****************************************************************************
+ * Handspring Visor Vendor specific request codes (bRequest values)
+ * A big thank you to Handspring for providing the following information.
+ * If anyone wants the original file where these values and structures came
+ * from, send email to <greg@kroah.com>.
+ ****************************************************************************/
+
+/****************************************************************************
+ * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that
+ * are available to be transfered to the host for the specified endpoint.
+ * Currently this is not used, and always returns 0x0001
+ ****************************************************************************/
+#define VISOR_REQUEST_BYTES_AVAILABLE		0x01
+
+/****************************************************************************
+ * VISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host
+ * is now closing the pipe. An empty packet is sent in response.
+ ****************************************************************************/
+#define VISOR_CLOSE_NOTIFICATION		0x02
+
+/****************************************************************************
+ * VISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to
+ * get the endpoints used by the connection.
+ ****************************************************************************/
+#define VISOR_GET_CONNECTION_INFORMATION	0x03
+
+
+/****************************************************************************
+ * VISOR_GET_CONNECTION_INFORMATION returns data in the following format
+ ****************************************************************************/
+struct visor_connection_info {
+	__u16	num_ports;
+	struct {
+		__u8	port_function_id;
+		__u8	port;
+	} connections[2];
+};
+
+
+/* struct visor_connection_info.connection[x].port defines: */
+#define VISOR_ENDPOINT_1		0x01
+#define VISOR_ENDPOINT_2		0x02
+
+/* struct visor_connection_info.connection[x].port_function_id defines: */
+#define VISOR_FUNCTION_GENERIC		0x00
+#define VISOR_FUNCTION_DEBUGGER		0x01
+#define VISOR_FUNCTION_HOTSYNC		0x02
+#define VISOR_FUNCTION_CONSOLE		0x03
+#define VISOR_FUNCTION_REMOTE_FILE_SYS	0x04
+
+#endif
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c
--- v2.3.99-pre3/linux/drivers/usb/serial/whiteheat.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/whiteheat.c	Mon Apr 10 22:54:09 2000
@@ -0,0 +1,251 @@
+/*
+ * USB ConnectTech WhiteHEAT driver
+ *
+ *	(C) Copyright (C) 1999, 2000
+ *	    Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ * 
+ * (03/26/2000) gkh
+ *	Split driver up into device specific pieces.
+ * 
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_WHITEHEAT
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#include "whiteheat_fw.h"		/* firmware for the ConnectTech WhiteHEAT device */
+
+
+#define CONNECT_TECH_VENDOR_ID		0x0710
+#define CONNECT_TECH_FAKE_WHITE_HEAT_ID	0x0001
+#define CONNECT_TECH_WHITE_HEAT_ID	0x8001
+
+/* function prototypes for the Connect Tech WhiteHEAT serial converter */
+static int  whiteheat_open		(struct usb_serial_port *port, struct file *filp);
+static void whiteheat_close		(struct usb_serial_port *port, struct file *filp);
+static void whiteheat_set_termios	(struct usb_serial_port *port, struct termios * old);
+static void whiteheat_throttle		(struct usb_serial_port *port);
+static void whiteheat_unthrottle	(struct usb_serial_port *port);
+static int  whiteheat_startup		(struct usb_serial *serial);
+
+/* All of the device info needed for the Connect Tech WhiteHEAT */
+static __u16	connecttech_vendor_id			= CONNECT_TECH_VENDOR_ID;
+static __u16	connecttech_whiteheat_fake_product_id	= CONNECT_TECH_FAKE_WHITE_HEAT_ID;
+static __u16	connecttech_whiteheat_product_id	= CONNECT_TECH_WHITE_HEAT_ID;
+struct usb_serial_device_type whiteheat_fake_device = {
+	name:			"Connect Tech - WhiteHEAT - (prerenumeration)",
+	idVendor:		&connecttech_vendor_id,			/* the Connect Tech vendor id */
+	idProduct:		&connecttech_whiteheat_fake_product_id,	/* the White Heat initial product id */
+	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
+	needs_bulk_in:		DONT_CARE,				/* don't have to have a bulk in endpoint */
+	needs_bulk_out:		DONT_CARE,				/* don't have to have a bulk out endpoint */
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	startup:		whiteheat_startup	
+};
+struct usb_serial_device_type whiteheat_device = {
+	name:			"Connect Tech - WhiteHEAT",
+	idVendor:		&connecttech_vendor_id,			/* the Connect Tech vendor id */
+	idProduct:		&connecttech_whiteheat_product_id,	/* the White Heat real product id */
+	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
+	needs_bulk_in:		DONT_CARE,				/* don't have to have a bulk in endpoint */
+	needs_bulk_out:		DONT_CARE,				/* don't have to have a bulk out endpoint */
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		4,
+	open:			whiteheat_open,
+	close:			whiteheat_close,
+	throttle:		whiteheat_throttle,
+	unthrottle:		whiteheat_unthrottle,
+	set_termios:		whiteheat_set_termios,
+};
+
+
+/*****************************************************************************
+ * Connect Tech's White Heat specific driver functions
+ *****************************************************************************/
+static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
+{
+	dbg("whiteheat_open port %d", port->number);
+
+	if (port->active) {
+		dbg ("device already open");
+		return -EINVAL;
+	}
+	port->active = 1;
+ 
+	/*Start reading from the device*/
+	if (usb_submit_urb(port->read_urb))
+		dbg("usb_submit_urb(read bulk) failed");
+
+	/* Need to do device specific setup here (control lines, baud rate, etc.) */
+	/* FIXME!!! */
+
+	return (0);
+}
+
+
+static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
+{
+	dbg("whiteheat_close port %d", port->number);
+	
+	/* Need to change the control lines here */
+	/* FIXME */
+	
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+	port->active = 0;
+}
+
+
+static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+	unsigned int cflag = port->tty->termios->c_cflag;
+
+	dbg("whiteheat_set_termios port %d", port->number);
+
+	/* check that they really want us to change something */
+	if (old_termios) {
+		if ((cflag == old_termios->c_cflag) &&
+		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+			dbg("nothing to change...");
+			return;
+		}
+	}
+
+	/* do the parsing of the cflag to see what to set the line to */
+	/* FIXME!! */
+
+	return;
+}
+
+static void whiteheat_throttle (struct usb_serial_port *port)
+{
+	dbg("whiteheat_throttle port %d", port->number);
+
+	/* Change the control signals */
+	/* FIXME!!! */
+
+	return;
+}
+
+
+static void whiteheat_unthrottle (struct usb_serial_port *port)
+{
+	dbg("whiteheat_unthrottle port %d", port->number);
+
+	/* Change the control signals */
+	/* FIXME!!! */
+
+	return;
+}
+
+
+/* steps to download the firmware to the WhiteHEAT device:
+ - hold the reset (by writing to the reset bit of the CPUCS register)
+ - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
+ - release the reset (by writing to the CPUCS register)
+ - download the WH.HEX file for all addresses greater than 0x1b3f using
+   VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
+ - hold the reset
+ - download the WH.HEX file for all addresses less than 0x1b40 using
+   VENDOR_REQUEST_ANCHOR_LOAD
+ - release the reset
+ - device renumerated itself and comes up as new device id with all
+   firmware download completed.
+*/
+static int  whiteheat_startup (struct usb_serial *serial)
+{
+	int response;
+	const struct whiteheat_hex_record *record;
+	
+	dbg("whiteheat_startup");
+	
+	response = ezusb_set_reset (serial, 1);
+
+	record = &whiteheat_loader[0];
+	while (record->address != 0xffff) {
+		response = ezusb_writememory (serial, record->address, 
+				(unsigned char *)record->data, record->data_size, 0xa0);
+		if (response < 0) {
+			err("ezusb_writememory failed for loader (%d %04X %p %d)", 
+				response, record->address, record->data, record->data_size);
+			break;
+		}
+		++record;
+	}
+
+	response = ezusb_set_reset (serial, 0);
+
+	record = &whiteheat_firmware[0];
+	while (record->address < 0x1b40) {
+		++record;
+	}
+	while (record->address != 0xffff) {
+		response = ezusb_writememory (serial, record->address, 
+				(unsigned char *)record->data, record->data_size, 0xa3);
+		if (response < 0) {
+			err("ezusb_writememory failed for first firmware step (%d %04X %p %d)", 
+				response, record->address, record->data, record->data_size);
+			break;
+		}
+		++record;
+	}
+	
+	response = ezusb_set_reset (serial, 1);
+
+	record = &whiteheat_firmware[0];
+	while (record->address < 0x1b40) {
+		response = ezusb_writememory (serial, record->address, 
+				(unsigned char *)record->data, record->data_size, 0xa0);
+		if (response < 0) {
+			err("ezusb_writememory failed for second firmware step (%d %04X %p %d)", 
+				response, record->address, record->data, record->data_size);
+			break;
+		}
+		++record;
+	}
+
+	response = ezusb_set_reset (serial, 0);
+
+	/* we want this device to fail to have a driver assigned to it. */
+	return (1);
+}
+
+#endif	/* CONFIG_USB_SERIAL_WHITEHEAT */
+
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/whiteheat.h linux/drivers/usb/serial/whiteheat.h
--- v2.3.99-pre3/linux/drivers/usb/serial/whiteheat.h	Fri Mar 10 16:40:45 2000
+++ linux/drivers/usb/serial/whiteheat.h	Wed Dec 31 16:00:00 1969
@@ -1,1542 +0,0 @@
-/*****************************************************************************
- *
- *      whiteheat.h  --  ConnectTech WhiteHEAT Firmware.
- *
- *      Copyright (C) 2000  ConnectTech Inc (http://www.connecttech.com/)
- *
- *      This program is free software; you can redistribute it and/or modify
- *      it under the terms of the GNU General Public License as published by
- *      the Free Software Foundation; either version 2 of the License, or
- *      (at your option) any later version.
- *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * (01/16/2000) gkh
- *	Fixed my intel hex processing tool, so now the firmware actually
- *	matches the original file (this was causing a few problems...)
- *
- * (01/15/2000) gkh
- *	Added debug loader firmware if DEBUG is #defined:
- *		Port 1 LED flashes when the vend_ax program is running
- *		Port 2 LED flashes when any SETUP command arrives
- *		Port 3 LED flashes when any valid VENDOR request occurs
- *		Port 4 LED flashes when the EXTERNAL RAM DOWNLOAD request occurs
- *
- * version 1.0 (01/09/2000) gkh
- *	Original firmware from ConnectTech massaged a little to be program
- *	readable.
- *
- *****************************************************************************/
-
-#define whiteheat_DATE "20000106"
-
-struct whiteheat_hex_record {
-	__u16	address;
-	__u8	data_size;
-	__u8	data[16];
-};
-
-static const struct whiteheat_hex_record whiteheat_firmware[] = {
-{ 0x0000,	3,	{0x02, 0x91, 0xc9} },
-{ 0x0003,	3,	{0x02, 0x13, 0x12} },
-{ 0x000b,	3,	{0x02, 0x0a, 0x8d} },
-{ 0x0033,	3,	{0x02, 0x07, 0x84} },
-{ 0x0043,	3,	{0x02, 0x09, 0x00} },
-{ 0x0053,	3,	{0x02, 0x0f, 0x6e} },
-{ 0x005b,	3,	{0x02, 0x11, 0xb9} },
-{ 0x0300,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x03, 0x14, 0x70, 0x03, 0x02, 0x04, 0x77, 0x24} },
-{ 0x0310,	16,	{0xfe, 0x70, 0x03, 0x02, 0x04, 0xca, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x03, 0xf4, 0x14, 0x70, 0x03} },
-{ 0x0320,	16,	{0x02, 0x03, 0xe2, 0x14, 0x70, 0x03, 0x02, 0x03, 0xca, 0x14, 0x70, 0x03, 0x02, 0x03, 0xd9, 0x24} },
-{ 0x0330,	16,	{0x05, 0x60, 0x03, 0x02, 0x05, 0x19, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60} },
-{ 0x0340,	16,	{0x36, 0x24, 0x02, 0x70, 0x7b, 0x74, 0x12, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
-{ 0x0350,	16,	{0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x58, 0xea, 0x49, 0x60, 0x0d} },
-{ 0x0360,	16,	{0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4} },
-{ 0x0370,	16,	{0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x08, 0xa9, 0xea} },
-{ 0x0380,	16,	{0x49, 0x60, 0x33, 0x12, 0x9a, 0x48, 0xf5, 0x5e, 0x90, 0x7f, 0xee, 0xe0, 0xff, 0xe5, 0x5e, 0xd3} },
-{ 0x0390,	16,	{0x9f, 0x40, 0x03, 0xe0, 0xf5, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x40, 0x40, 0x03, 0x75, 0x5e, 0x40} },
-{ 0x03a0,	16,	{0xae, 0x02, 0xaf, 0x01, 0x7c, 0x7f, 0x7d, 0x00, 0xab, 0x5e, 0x12, 0x1b, 0x0c, 0x90, 0x7f, 0xb5} },
-{ 0x03b0,	16,	{0xe5, 0x5e, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20} },
-{ 0x03c0,	16,	{0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0x00, 0xe5, 0x21, 0xf0} },
-{ 0x03d0,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x21, 0x02} },
-{ 0x03e0,	16,	{0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x31, 0xd2, 0x02, 0x43, 0x88, 0x10, 0xd2, 0xeb, 0xd2} },
-{ 0x03f0,	16,	{0xa8, 0x02, 0x05, 0x20, 0x90, 0x7f, 0x00, 0xe5, 0x31, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0} },
-{ 0x0400,	16,	{0x02, 0x05, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02} },
-{ 0x0410,	16,	{0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x05, 0xe4, 0x33, 0x4f, 0x90} },
-{ 0x0420,	16,	{0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0xe4} },
-{ 0x0430,	16,	{0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0x90} },
-{ 0x0440,	16,	{0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25} },
-{ 0x0450,	16,	{0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0x01, 0x90, 0x7f, 0x00} },
-{ 0x0460,	16,	{0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4} },
-{ 0x0470,	16,	{0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24} },
-{ 0x0480,	16,	{0x02, 0x60, 0x03, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02} },
-{ 0x0490,	16,	{0x05, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0} },
-{ 0x04a0,	16,	{0x70, 0x1f, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54} },
-{ 0x04b0,	16,	{0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x80} },
-{ 0x04c0,	16,	{0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe} },
-{ 0x04d0,	16,	{0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x00, 0x80} },
-{ 0x04e0,	16,	{0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20} },
-{ 0x04f0,	16,	{0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f} },
-{ 0x0500,	16,	{0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10} },
-{ 0x0510,	16,	{0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0520,	7,	{0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
-{ 0x0527,	1,	{0x22} },
-{ 0x0528,	16,	{0x75, 0x5a, 0xff, 0x75, 0x59, 0xff, 0x75, 0x58, 0x0f, 0x75, 0x57, 0x00, 0xd2, 0x03, 0xc2, 0x06} },
-{ 0x0538,	16,	{0xc2, 0x02, 0xc2, 0x00, 0xc2, 0x05, 0xc2, 0x01, 0x90, 0x02, 0x9e, 0x74, 0x19, 0xf0, 0xe4, 0x90} },
-{ 0x0548,	16,	{0x01, 0x5b, 0xf0, 0xc2, 0x04, 0x90, 0x01, 0x5e, 0xf0, 0xa3, 0xf0, 0xc2, 0xaf, 0xc2, 0xa8, 0x12} },
-{ 0x0558,	16,	{0x0a, 0xfa, 0xe4, 0x90, 0x02, 0x4d, 0xf0, 0x90, 0x01, 0x00, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x0568,	16,	{0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0x7e} },
-{ 0x0578,	16,	{0x01, 0x7f, 0x00, 0x12, 0x19, 0xc1, 0x75, 0x5c, 0x12, 0x75, 0x5d, 0x0a, 0x90, 0x01, 0x0b, 0xe0} },
-{ 0x0588,	16,	{0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
-{ 0x0598,	16,	{0xef, 0xf0, 0x90, 0x01, 0x0c, 0xe0, 0x44, 0x80, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70} },
-{ 0x05a8,	16,	{0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0d, 0xe0, 0xff, 0x05} },
-{ 0x05b8,	16,	{0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
-{ 0x05c8,	16,	{0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14} },
-{ 0x05d8,	16,	{0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x12, 0x0a, 0xe4, 0x93, 0xff, 0x74, 0x01, 0x93, 0x90} },
-{ 0x05e8,	16,	{0x01, 0x1c, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0xff, 0xa3, 0xe0, 0xfe, 0xef} },
-{ 0x05f8,	16,	{0x6e, 0xff, 0x90, 0x01, 0x1c, 0xf0, 0xa3, 0xe0, 0x6f, 0xff, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0x6f} },
-{ 0x0608,	16,	{0xf0, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xe4, 0xfc, 0xfd, 0x75, 0x62, 0x10, 0x75, 0x63, 0x02, 0x75} },
-{ 0x0618,	16,	{0x64, 0x12, 0x75, 0x65, 0xac, 0x12, 0x8e, 0x35, 0x75, 0x5c, 0x12, 0x75, 0x5d, 0xb2, 0x90, 0x01} },
-{ 0x0628,	16,	{0x0d, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82} },
-{ 0x0638,	16,	{0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70} },
-{ 0x0648,	16,	{0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4} },
-{ 0x0658,	16,	{0x54, 0x0f, 0x24, 0x41, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14} },
-{ 0x0668,	16,	{0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x05, 0x5d, 0xe5, 0x5d, 0xae, 0x5c, 0x70, 0x02, 0x05, 0x5c} },
-{ 0x0678,	16,	{0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x75, 0x82, 0x10, 0x75, 0x83, 0x01, 0xe0, 0xfc, 0xa3} },
-{ 0x0688,	16,	{0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x90, 0x01, 0x18, 0x12, 0x9b, 0xfb, 0x7e, 0x01} },
-{ 0x0698,	16,	{0x7f, 0x18, 0x12, 0x84, 0x61, 0x90, 0x01, 0x18, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
-{ 0x06a8,	16,	{0xa3, 0xe0, 0xff, 0x75, 0x62, 0x0a, 0x75, 0x63, 0x06, 0x75, 0x64, 0x12, 0x75, 0x65, 0xb8, 0x12} },
-{ 0x06b8,	16,	{0x8e, 0x35, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x53, 0x91, 0xef} },
-{ 0x06c8,	16,	{0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x1f, 0xf0, 0xd2, 0xaf} },
-{ 0x06d8,	16,	{0x20, 0x01, 0x2e, 0x20, 0x01, 0x2b, 0xa2, 0x03, 0x92, 0x07, 0x12, 0x09, 0xa7, 0x75, 0x56, 0x50} },
-{ 0x06e8,	16,	{0x75, 0x55, 0x6d, 0x75, 0x54, 0x33, 0x75, 0x53, 0x00, 0x20, 0x01, 0xe4, 0x7f, 0xff, 0x7e, 0xff} },
-{ 0x06f8,	16,	{0x7d, 0xff, 0x7c, 0xff, 0x78, 0x53, 0x12, 0x9b, 0xe4, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0xd1, 0x80} },
-{ 0x0708,	16,	{0xe8, 0x30, 0x01, 0x05, 0x12, 0x03, 0x00, 0xc2, 0x01, 0x30, 0x06, 0x0d, 0x12, 0x08, 0xfb, 0x50} },
-{ 0x0718,	16,	{0x06, 0x12, 0x0a, 0x00, 0x12, 0x09, 0xf4, 0xc2, 0x06, 0x12, 0x90, 0x58, 0x12, 0x98, 0x7d, 0xe4} },
-{ 0x0728,	16,	{0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x90, 0x01, 0x5b} },
-{ 0x0738,	16,	{0xe0, 0x5e, 0x60, 0x14, 0x74, 0x27, 0x2f, 0xf8, 0xe6, 0xd3, 0x94, 0x0a, 0x40, 0x04, 0x7e, 0x01} },
-{ 0x0748,	16,	{0x80, 0x02, 0x7e, 0x00, 0x8e, 0x5b, 0x80, 0x03, 0x75, 0x5b, 0x01, 0x74, 0x68, 0x2f, 0xf5, 0x82} },
-{ 0x0758,	16,	{0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe5, 0x5b, 0xf0, 0x0f, 0xbf, 0x04, 0xc5, 0xe5, 0x2b, 0xd3, 0x94} },
-{ 0x0768,	16,	{0x0a, 0x40, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x20, 0x6c, 0xef, 0xf0, 0x90, 0x02} },
-{ 0x0778,	11,	{0x4d, 0xe0, 0x64, 0x0f, 0x70, 0x8b, 0x12, 0x93, 0x50, 0x80, 0x86} },
-{ 0x0783,	1,	{0x22} },
-{ 0x0784,	4,	{0x53, 0xd8, 0xef, 0x32} },
-{ 0x0788,	16,	{0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0x74, 0x89} },
-{ 0x0798,	16,	{0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x08, 0x92, 0x90, 0x7f} },
-{ 0x07a8,	16,	{0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x02, 0x7d, 0xff} },
-{ 0x07b8,	16,	{0x12, 0x11, 0x4b, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02} },
-{ 0x07c8,	16,	{0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0} },
-{ 0x07d8,	16,	{0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf} },
-{ 0x07e8,	16,	{0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f} },
-{ 0x07f8,	7,	{0x32, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x22} },
-{ 0x07ff,	16,	{0x90, 0x7f, 0x96, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x80, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12} },
-{ 0x080f,	16,	{0x08, 0x92, 0x7f, 0x02, 0xe4, 0xfd, 0x12, 0x11, 0x4b, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92} },
-{ 0x081f,	16,	{0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f} },
-{ 0x082f,	16,	{0x96, 0xe0, 0x44, 0x04, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0} },
-{ 0x083f,	16,	{0x54, 0xf7, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x01} },
-{ 0x084f,	12,	{0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x12, 0x0a, 0x00, 0x22} },
-{ 0x085b,	16,	{0x90, 0x11, 0xef, 0xe4, 0x93, 0x70, 0x2f, 0x90, 0x7f, 0x93, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x94} },
-{ 0x086b,	16,	{0x74, 0x3c, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc6, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x7f} },
-{ 0x087b,	16,	{0x9d, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0xe2, 0x74, 0x12, 0xf0, 0x12, 0x07, 0x88, 0x75, 0x82, 0xef} },
-{ 0x088b,	7,	{0x75, 0x83, 0x11, 0x74, 0xff, 0xf0, 0x22} },
-{ 0x0892,	16,	{0x8e, 0x6d, 0x8f, 0x6e, 0xe5, 0x6e, 0x15, 0x6e, 0xae, 0x6d, 0x70, 0x02, 0x15, 0x6d, 0x4e, 0x60} },
-{ 0x08a2,	7,	{0x05, 0x12, 0x08, 0xea, 0x80, 0xee, 0x22} },
-{ 0x08a9,	2,	{0x8f, 0x5f} },
-{ 0x08ab,	16,	{0xe4, 0xf5, 0x60, 0x75, 0x61, 0xff, 0x75, 0x62, 0x12, 0x75, 0x63, 0x6a, 0xab, 0x61, 0xaa, 0x62} },
-{ 0x08bb,	16,	{0xa9, 0x63, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0xb4, 0x03, 0x1d, 0xaf, 0x60, 0x05, 0x60, 0xef} },
-{ 0x08cb,	16,	{0xb5, 0x5f, 0x01, 0x22, 0x12, 0x9a, 0x48, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
-{ 0x08db,	14,	{0x61, 0xff, 0xf5, 0x62, 0x89, 0x63, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
-{ 0x08e9,	1,	{0x22} },
-{ 0x08ea,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
-{ 0x08fa,	1,	{0x22} },
-{ 0x08fb,	5,	{0x12, 0x07, 0xff, 0xd3, 0x22} },
-{ 0x0900,	16,	{0x02, 0x0b, 0x17, 0x00, 0x02, 0x0b, 0x4a, 0x00, 0x02, 0x0b, 0x2f, 0x00, 0x02, 0x0b, 0x89, 0x00} },
-{ 0x0910,	16,	{0x02, 0x0b, 0x73, 0x00, 0x02, 0x09, 0xf9, 0x00, 0x02, 0x09, 0xfa, 0x00, 0x02, 0x09, 0xfb, 0x00} },
-{ 0x0920,	16,	{0x02, 0x0b, 0xa4, 0x00, 0x02, 0x0c, 0x78, 0x00, 0x02, 0x0b, 0xd9, 0x00, 0x02, 0x0c, 0xc5, 0x00} },
-{ 0x0930,	16,	{0x02, 0x0c, 0x0e, 0x00, 0x02, 0x0d, 0x12, 0x00, 0x02, 0x0c, 0x43, 0x00, 0x02, 0x0d, 0x5f, 0x00} },
-{ 0x0940,	16,	{0x02, 0x09, 0xfc, 0x00, 0x02, 0x09, 0xfe, 0x00, 0x02, 0x09, 0xfd, 0x00, 0x02, 0x09, 0xff, 0x00} },
-{ 0x0950,	8,	{0x02, 0x0d, 0xac, 0x00, 0x02, 0x0d, 0xc2, 0x00} },
-{ 0x0958,	16,	{0xe4, 0xfe, 0x75, 0x61, 0xff, 0x75, 0x62, 0x12, 0x75, 0x63, 0x12, 0xab, 0x61, 0xaa, 0x62, 0xa9} },
-{ 0x0968,	16,	{0x63, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
-{ 0x0978,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x9a, 0xba, 0x85, 0xf0, 0x5f, 0xf5, 0x60, 0x62, 0x5f} },
-{ 0x0988,	16,	{0xe5, 0x5f, 0x62, 0x60, 0xe5, 0x60, 0x62, 0x5f, 0x29, 0xfd, 0xe5, 0x5f, 0x3a, 0xa9, 0x05, 0x75} },
-{ 0x0998,	14,	{0x61, 0xff, 0xf5, 0x62, 0x89, 0x63, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
-{ 0x09a6,	1,	{0x22} },
-{ 0x09a7,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x07, 0x04, 0xe0, 0x44} },
-{ 0x09b7,	16,	{0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x08, 0x92, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
-{ 0x09c7,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
-{ 0x09cc,	16,	{0x53, 0x8e, 0xf7, 0xe5, 0x89, 0x54, 0xf1, 0x44, 0x01, 0xf5, 0x89, 0x75, 0x8c, 0xb1, 0xd2, 0xa9} },
-{ 0x09dc,	16,	{0x75, 0x98, 0x40, 0x75, 0xcb, 0xff, 0x75, 0xca, 0xf3, 0x75, 0xc8, 0x34, 0xe4, 0xff, 0x7f, 0x05} },
-{ 0x09ec,	7,	{0x78, 0x27, 0xe4, 0xf6, 0x08, 0xdf, 0xfc} },
-{ 0x09f3,	1,	{0x22} },
-{ 0x09f4,	5,	{0x12, 0x07, 0x88, 0xd3, 0x22} },
-{ 0x09f9,	1,	{0x32} },
-{ 0x09fa,	1,	{0x32} },
-{ 0x09fb,	1,	{0x32} },
-{ 0x09fc,	1,	{0x32} },
-{ 0x09fd,	1,	{0x32} },
-{ 0x09fe,	1,	{0x32} },
-{ 0x09ff,	1,	{0x32} },
-{ 0x0a00,	9,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
-{ 0x0a7d,	16,	{0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
-{ 0x0a8d,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x06, 0xc0} },
-{ 0x0a9d,	1,	{0x07} },
-{ 0x0a9e,	16,	{0x30, 0x04, 0x16, 0x75, 0x8c, 0xf8, 0x75, 0x8a, 0x30, 0x7f, 0x2f, 0xae, 0x07, 0x1f, 0xee, 0x60} },
-{ 0x0aae,	16,	{0x3c, 0x90, 0x20, 0x00, 0x74, 0x55, 0xf0, 0x80, 0xf2, 0x75, 0x8c, 0xb1, 0x7f, 0x27, 0xef, 0xd3} },
-{ 0x0abe,	16,	{0x94, 0x2b, 0x50, 0x09, 0xa8, 0x07, 0xe6, 0x60, 0x01, 0x16, 0x0f, 0x80, 0xf1, 0x90, 0x02, 0x9e} },
-{ 0x0ace,	16,	{0xe0, 0x60, 0x02, 0x14, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x0e, 0x90} },
-{ 0x0ade,	13,	{0x01, 0x5f, 0xe0, 0x24, 0xff, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x34, 0xff, 0xf0} },
-{ 0x0aeb,	15,	{0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0afa,	16,	{0xd2, 0x00, 0x75, 0x8e, 0x10, 0xe4, 0x90, 0x7f, 0x92, 0xf0, 0x12, 0x0f, 0x72, 0x12, 0x08, 0x5b} },
-{ 0x0b0a,	13,	{0x12, 0x0e, 0x0f, 0x12, 0x8f, 0x06, 0x12, 0x11, 0x9c, 0x12, 0x09, 0xcc, 0x22} },
-{ 0x0b17,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
-{ 0x0b27,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b2f,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
-{ 0x0b3f,	11,	{0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b4a,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0x90} },
-{ 0x0b5a,	16,	{0x7f, 0xd8, 0xe0, 0x70, 0x0d, 0x90, 0x7f, 0xd9, 0xe0, 0x70, 0x07, 0xe5, 0x2b, 0x70, 0x03, 0x75} },
-{ 0x0b6a,	9,	{0x2b, 0x14, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b73,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
-{ 0x0b83,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b89,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x30, 0x02, 0x02, 0xd2, 0x06, 0x53, 0x91, 0xef, 0x90, 0x7f} },
-{ 0x0b99,	11,	{0xab, 0x74, 0x08, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0ba4,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x02, 0xf0, 0xe5} },
-{ 0x0bb4,	16,	{0x30, 0x30, 0xe0, 0x13, 0xe5, 0x3b, 0x30, 0xe0, 0x07, 0x90, 0x20, 0x04, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0bc4,	16,	{0x90, 0x20, 0x01, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0bd4,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0bd9,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x04, 0xf0, 0xe5} },
-{ 0x0be9,	16,	{0x30, 0x30, 0xe1, 0x13, 0xe5, 0x3b, 0x30, 0xe1, 0x07, 0x90, 0x20, 0x0c, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0bf9,	16,	{0x90, 0x20, 0x09, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0c09,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0c0e,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x08, 0xf0, 0xe5} },
-{ 0x0c1e,	16,	{0x30, 0x30, 0xe2, 0x13, 0xe5, 0x3b, 0x30, 0xe2, 0x07, 0x90, 0x20, 0x14, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0c2e,	16,	{0x90, 0x20, 0x11, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0c3e,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0c43,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x10, 0xf0, 0xe5} },
-{ 0x0c53,	16,	{0x30, 0x30, 0xe3, 0x13, 0xe5, 0x3b, 0x30, 0xe3, 0x07, 0x90, 0x20, 0x1c, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0c63,	16,	{0x90, 0x20, 0x19, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0c73,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0c78,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0c88,	16,	{0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x20, 0xe0, 0x06, 0x90, 0x7f, 0xc7} },
-{ 0x0c98,	16,	{0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x90, 0x7f, 0xc7, 0xe0, 0x90, 0x02, 0x96, 0xf0} },
-{ 0x0ca8,	16,	{0x80, 0x07, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0cb8,	13,	{0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0cc5,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0cd5,	16,	{0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x20, 0xe1, 0x06, 0x90, 0x7f, 0xc9} },
-{ 0x0ce5,	16,	{0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x90, 0x7f, 0xc9, 0xe0, 0x90, 0x02, 0x97, 0xf0} },
-{ 0x0cf5,	16,	{0x80, 0x07, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0d05,	13,	{0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0d12,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0d22,	16,	{0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x20, 0xe2, 0x06, 0x90, 0x7f, 0xcb} },
-{ 0x0d32,	16,	{0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0x90, 0x02, 0x98, 0xf0} },
-{ 0x0d42,	16,	{0x80, 0x07, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0d52,	13,	{0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0d5f,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0d6f,	16,	{0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x20, 0xe3, 0x06, 0x90, 0x7f, 0xcd} },
-{ 0x0d7f,	16,	{0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x90, 0x02, 0x99, 0xf0} },
-{ 0x0d8f,	16,	{0x80, 0x07, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0d9f,	13,	{0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0dac,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x80, 0xf0, 0xd0} },
-{ 0x0dbc,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0dc2,	16,	{0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0} },
-{ 0x0dd2,	16,	{0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0x53, 0x91, 0xef} },
-{ 0x0de2,	16,	{0x90, 0x7f, 0xaa, 0x74, 0x80, 0xf0, 0x7e, 0x7b, 0x7f, 0x40, 0x12, 0x8c, 0xfb, 0x90, 0x7f, 0xd3} },
-{ 0x0df2,	16,	{0xe4, 0xf0, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01} },
-{ 0x0e02,	13,	{0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32} },
-{ 0x0e0f,	16,	{0x90, 0x01, 0x20, 0x12, 0x9c, 0x07, 0x00, 0x00, 0x25, 0x80, 0x90, 0x01, 0x24, 0x74, 0x08, 0xf0} },
-{ 0x0e1f,	16,	{0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x6e, 0xf0, 0xa3, 0xf0, 0xe4, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x0e2f,	16,	{0xf0, 0xa3, 0xf0, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50} },
-{ 0x0e3f,	16,	{0x13, 0xef, 0x04, 0xa3, 0xf0, 0x7e, 0x01, 0x7f, 0x1f, 0x12, 0x84, 0xf4, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0e4f,	16,	{0x04, 0xf0, 0x80, 0xe3, 0xe4, 0xf5, 0x26, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff} },
-{ 0x0e5f,	16,	{0xc3, 0x94, 0x04, 0x50, 0x1a, 0x74, 0x96, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4} },
-{ 0x0e6f,	16,	{0xf0, 0x74, 0x22, 0x2f, 0xf8, 0xe4, 0xf6, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xdc, 0xe4} },
-{ 0x0e7f,	16,	{0xf5, 0x30, 0xe5, 0xc0, 0x60, 0x2f, 0x90, 0x01, 0x1e, 0x74, 0x01, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0e8f,	16,	{0xff, 0xd3, 0x94, 0x04, 0x50, 0x1f, 0xef, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02} },
-{ 0x0e9f,	16,	{0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x30, 0x7e, 0x01, 0x7f, 0x1e, 0x12, 0x82, 0xea, 0x90, 0x01, 0x1e} },
-{ 0x0eaf,	16,	{0xe0, 0x04, 0xf0, 0x80, 0xd7, 0xe4, 0xf5, 0x3a, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0ebf,	16,	{0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54} },
-{ 0x0ecf,	16,	{0xf0, 0xfe, 0x74, 0x63, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xee, 0xf0, 0x74, 0x36} },
-{ 0x0edf,	16,	{0x2f, 0xf8, 0xa6, 0x06, 0x74, 0x32, 0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0x2c, 0x2f, 0xf8, 0xe4, 0xf6} },
-{ 0x0eef,	16,	{0x74, 0x9a, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0eff,	16,	{0x04, 0xf0, 0xe0, 0xb4, 0x04, 0xb6, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xf5, 0x5e, 0x60, 0x5e} },
-{ 0x0f0f,	16,	{0xe4, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50, 0xe7, 0x74} },
-{ 0x0f1f,	16,	{0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x55, 0x5e, 0x60, 0x38, 0x90, 0x01} },
-{ 0x0f2f,	1,	{0x1e} },
-{ 0x0f30,	16,	{0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0} },
-{ 0x0f40,	16,	{0xfe, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0} },
-{ 0x0f50,	16,	{0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0xfe} },
-{ 0x0f60,	14,	{0x7d, 0x06, 0x12, 0x82, 0x60, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xa7, 0x22} },
-{ 0x0f6e,	4,	{0x53, 0x91, 0xbf, 0x32} },
-{ 0x0f72,	16,	{0x7b, 0xff, 0x7a, 0x12, 0x79, 0x1b, 0x90, 0x00, 0x04, 0x12, 0x9a, 0x61, 0xfd, 0x8b, 0x60, 0x75} },
-{ 0x0f82,	16,	{0x61, 0x12, 0x75, 0x62, 0x24, 0xe4, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x7f, 0xe0, 0xf0, 0xf5, 0x5e} },
-{ 0x0f92,	16,	{0xf5, 0x5f, 0x90, 0x02, 0x4c, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f} },
-{ 0x0fa2,	16,	{0xa9, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0xe4, 0xfc, 0xec, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
-{ 0x0fb2,	16,	{0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x0c, 0xbc, 0x10, 0xee, 0xe4, 0x90, 0x7f, 0xdd} },
-{ 0x0fc2,	16,	{0xf0, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03, 0x02, 0x11, 0x38, 0xab, 0x60, 0xaa, 0x61, 0xa9, 0x62} },
-{ 0x0fd2,	16,	{0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0x64, 0x05, 0x60, 0x03, 0x02, 0x11, 0x27, 0x90, 0x00, 0x03} },
-{ 0x0fe2,	16,	{0x12, 0x9a, 0x61, 0x64, 0x01, 0x60, 0x03, 0x02, 0x10, 0xae, 0x90, 0x00, 0x02, 0x12, 0x9a, 0x61} },
-{ 0x0ff2,	16,	{0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x10, 0x88, 0xec, 0xc3, 0x94, 0x10} },
-{ 0x1002,	16,	{0x40, 0x03, 0x02, 0x10, 0x88, 0xef, 0x30, 0xe7, 0x42, 0xe5, 0x5f, 0xae, 0x5e, 0x78, 0x02, 0xce} },
-{ 0x1012,	16,	{0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xf0, 0x2c, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5} },
-{ 0x1022,	16,	{0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe0, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01, 0xa8, 0x06} },
-{ 0x1032,	16,	{0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe0, 0xf0, 0x90, 0x02, 0x4c, 0xe0} },
-{ 0x1042,	16,	{0x04, 0xf0, 0x90, 0x7f, 0xdd, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x3e, 0xe5, 0x5f, 0xae, 0x5e, 0x78} },
-{ 0x1052,	16,	{0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xe8, 0x2c, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x1062,	16,	{0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe1, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01} },
-{ 0x1072,	16,	{0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x02} },
-{ 0x1082,	16,	{0x4c, 0xe0, 0x04, 0xf0, 0x80, 0x03, 0x7f, 0xff, 0x22, 0x90, 0x00, 0x04, 0x12, 0x9a, 0x61, 0x25} },
-{ 0x1092,	16,	{0x5f, 0xf5, 0x5f, 0xe4, 0x35, 0x5e, 0xf5, 0x5e, 0x90, 0x00, 0x05, 0x12, 0x9a, 0x61, 0xfe, 0xe4} },
-{ 0x10a2,	16,	{0x25, 0x5f, 0xf5, 0x5f, 0xee, 0x35, 0x5e, 0xf5, 0x5e, 0x02, 0x11, 0x2a, 0xab, 0x60, 0xaa, 0x61} },
-{ 0x10b2,	16,	{0xa9, 0x62, 0x90, 0x00, 0x03, 0x12, 0x9a, 0x61, 0xff, 0x64, 0x02, 0x60, 0x05, 0xef, 0x64, 0x03} },
-{ 0x10c2,	16,	{0x70, 0x60, 0x90, 0x00, 0x02, 0x12, 0x9a, 0x61, 0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50} },
-{ 0x10d2,	16,	{0x4e, 0xef, 0x30, 0xe7, 0x1e, 0x90, 0x7f, 0xde, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80} },
-{ 0x10e2,	16,	{0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x4e} },
-{ 0x10f2,	16,	{0xf0, 0x80, 0x35, 0x90, 0x7f, 0xdf, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80, 0x02, 0xc3} },
-{ 0x1102,	16,	{0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xad, 0xe0, 0x4e, 0xf0, 0xec} },
-{ 0x1112,	16,	{0x25, 0xe0, 0x24, 0xc5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x80, 0x09, 0x7f} },
-{ 0x1122,	16,	{0xff, 0x22, 0x7f, 0xff, 0x22, 0x7f, 0xff, 0x22, 0x74, 0x07, 0x25, 0x62, 0xf5, 0x62, 0xe4, 0x35} },
-{ 0x1132,	16,	{0x61, 0xf5, 0x61, 0x02, 0x0f, 0xc3, 0x20, 0x03, 0x0d, 0x90, 0x02, 0x4c, 0xe0, 0x60, 0x07, 0x90} },
-{ 0x1142,	8,	{0x7f, 0xae, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0x00} },
-{ 0x114a,	1,	{0x22} },
-{ 0x114b,	2,	{0xae, 0x07} },
-{ 0x114d,	16,	{0x7c, 0x02, 0xec, 0x14, 0x60, 0x15, 0x14, 0x70, 0x1e, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0} },
-{ 0x115d,	16,	{0xee, 0x25, 0xe0, 0x44, 0x40, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xa6, 0xed, 0xf0} },
-{ 0x116d,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xfb, 0x30, 0xe0, 0xf8, 0xbc} },
-{ 0x117d,	16,	{0x02, 0x0a, 0x20, 0xe1, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22, 0xeb, 0x30, 0xe2, 0x0a} },
-{ 0x118d,	14,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xdc, 0xb6, 0x7f, 0x08} },
-{ 0x119b,	1,	{0x22} },
-{ 0x119c,	16,	{0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x02, 0x7d, 0xff, 0x12, 0x11, 0x4b, 0x7f, 0x05} },
-{ 0x11ac,	13,	{0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x03, 0x7d, 0xff, 0x12, 0x11, 0x4b, 0x22} },
-{ 0x11b9,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc2, 0xa9, 0x90, 0x02, 0x9e, 0x74, 0x19, 0xf0, 0xd2, 0xa9} },
-{ 0x11c9,	15,	{0x53, 0x91, 0x7f, 0x90, 0x01, 0x62, 0xe4, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x11d8,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33} },
-{ 0x11e8,	7,	{0xd8, 0xfc, 0x42, 0x3a, 0x7f, 0x00, 0x22} },
-{ 0x11ef,	3,	{0x00, 0x02, 0x28} },
-{ 0x1200,	16,	{0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40, 0x10, 0x07, 0x01, 0x80, 0x42, 0x00, 0x01, 0x02} },
-{ 0x1210,	16,	{0x03, 0x01, 0x09, 0x02, 0x58, 0x00, 0x01, 0x01, 0x04, 0x80, 0x3c, 0x09, 0x04, 0x00, 0x00, 0x0a} },
-{ 0x1220,	16,	{0xff, 0xff, 0xff, 0x05, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40} },
-{ 0x1230,	16,	{0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00} },
-{ 0x1240,	16,	{0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
-{ 0x1250,	16,	{0x84, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x87, 0x02} },
-{ 0x1260,	16,	{0x40, 0x00, 0x00, 0x07, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x24, 0x03} },
-{ 0x1270,	16,	{0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x20, 0x00} },
-{ 0x1280,	16,	{0x54, 0x00, 0x65, 0x00, 0x63, 0x00, 0x68, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
-{ 0x1290,	16,	{0x2e, 0x00, 0x18, 0x03, 0x57, 0x00, 0x68, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, 0x00, 0x48, 0x00} },
-{ 0x12a0,	16,	{0x45, 0x00, 0x41, 0x00, 0x54, 0x00, 0x2d, 0x00, 0x34, 0x00, 0x1a, 0x03, 0x58, 0x00, 0x58, 0x00} },
-{ 0x12b0,	16,	{0x2d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x2d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00} },
-{ 0x12c0,	16,	{0x58, 0x00, 0x58, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
-{ 0x12d0,	16,	{0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
-{ 0x12e0,	16,	{0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
-{ 0x12f0,	16,	{0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
-{ 0x1300,	16,	{0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
-{ 0x1310,	2,	{0x00, 0x00} },
-{ 0x1312,	16,	{0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0xc0, 0xd0} },
-{ 0x1322,	16,	{0x75, 0x86, 0x00, 0x75, 0xd0, 0x18, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xf5, 0xf0, 0x70, 0x11} },
-{ 0x1332,	16,	{0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0} },
-{ 0x1342,	16,	{0x32, 0x75, 0x86, 0x00, 0x10, 0xf0, 0x0b, 0x10, 0xf1, 0x12, 0x10, 0xf2, 0x19, 0x10, 0xf3, 0x20} },
-{ 0x1352,	16,	{0x80, 0xd4, 0xe5, 0x27, 0x70, 0x03, 0x75, 0x27, 0x14, 0x02, 0x13, 0x7c, 0xe5, 0x28, 0x70, 0x03} },
-{ 0x1362,	16,	{0x75, 0x28, 0x14, 0x02, 0x15, 0x0d, 0xe5, 0x29, 0x70, 0x03, 0x75, 0x29, 0x14, 0x02, 0x16, 0x9e} },
-{ 0x1372,	16,	{0xe5, 0x2a, 0x70, 0x03, 0x75, 0x2a, 0x14, 0x02, 0x18, 0x2f, 0x90, 0x20, 0x02, 0xe0, 0x54, 0x3f} },
-{ 0x1382,	16,	{0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14, 0x60, 0x09, 0x02, 0x13} },
-{ 0x1392,	16,	{0x43, 0x02, 0x14, 0x65, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5, 0x36, 0x02, 0x13, 0x43} },
-{ 0x13a2,	16,	{0x43, 0x82, 0x04, 0xe0, 0x43, 0x2c, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x05} },
-{ 0x13b2,	16,	{0xe0, 0x42, 0x32, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13, 0x43, 0x30, 0xe1, 0x02} },
-{ 0x13c2,	16,	{0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x04, 0xe0} },
-{ 0x13d2,	16,	{0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74, 0x00, 0xf0, 0x90, 0x20} },
-{ 0x13e2,	16,	{0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86} },
-{ 0x13f2,	16,	{0x90, 0x7e, 0x80, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f} },
-{ 0x1402,	16,	{0xe5, 0xe5, 0x3c, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0} },
-{ 0x1412,	16,	{0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x90} },
-{ 0x1422,	16,	{0x7f, 0xb7, 0xed, 0xf0, 0x90, 0x20, 0x01, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x7f, 0x40} },
-{ 0x1432,	16,	{0x90, 0x7e, 0x80, 0x05, 0x86, 0x90, 0x20, 0x00, 0xe5, 0x84, 0xfe, 0x24, 0x05, 0xfd, 0x8d, 0x84} },
-{ 0x1442,	16,	{0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xef, 0x05} },
-{ 0x1452,	16,	{0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xb7, 0xf0, 0x05, 0x86, 0xa3, 0xe0, 0x54, 0xfe, 0xf0} },
-{ 0x1462,	16,	{0x02, 0x13, 0x43, 0x53, 0x2c, 0xfa, 0xe5, 0x22, 0x60, 0x08, 0x75, 0x22, 0x00, 0xd2, 0xe7, 0xfe} },
-{ 0x1472,	16,	{0x80, 0x0a, 0x90, 0x7f, 0xc7, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x14, 0xff, 0x90, 0x20, 0x50, 0x74} },
-{ 0x1482,	16,	{0x00, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
-{ 0x1492,	16,	{0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7e, 0x40, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0} },
-{ 0x14a2,	16,	{0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0, 0x24, 0x38, 0xf0, 0x05} },
-{ 0x14b2,	16,	{0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60, 0x30, 0x03, 0x03, 0x03} },
-{ 0x14c2,	16,	{0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0} },
-{ 0x14d2,	16,	{0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11, 0x8b, 0x22, 0x90, 0x7f} },
-{ 0x14e2,	16,	{0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80, 0x1b, 0xe0, 0xde, 0xfd} },
-{ 0x14f2,	16,	{0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x90, 0x20, 0x01} },
-{ 0x1502,	16,	{0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xc7, 0xf0, 0x02, 0x13, 0x43, 0x90, 0x20, 0x0a, 0xe0, 0x54} },
-{ 0x1512,	16,	{0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14, 0x60, 0x09, 0x02} },
-{ 0x1522,	16,	{0x13, 0x43, 0x02, 0x15, 0xf6, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5, 0x37, 0x02, 0x13} },
-{ 0x1532,	16,	{0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2d, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82, 0xf8, 0x43, 0x82} },
-{ 0x1542,	16,	{0x05, 0xe0, 0x42, 0x33, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13, 0x43, 0x30, 0xe1} },
-{ 0x1552,	16,	{0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x04} },
-{ 0x1562,	16,	{0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74, 0x01, 0xf0, 0x90} },
-{ 0x1572,	16,	{0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05} },
-{ 0x1582,	16,	{0x86, 0x90, 0x7e, 0x00, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90} },
-{ 0x1592,	16,	{0x7f, 0xe5, 0xe5, 0x3d, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0} },
-{ 0x15a2,	16,	{0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
-{ 0x15b2,	16,	{0x90, 0x7f, 0xb9, 0xed, 0xf0, 0x90, 0x20, 0x09, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x7f} },
-{ 0x15c2,	16,	{0x40, 0x90, 0x7e, 0x00, 0x05, 0x86, 0x90, 0x20, 0x08, 0xe5, 0x84, 0xfe, 0x24, 0x05, 0xfd, 0x8d} },
-{ 0x15d2,	16,	{0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xef} },
-{ 0x15e2,	16,	{0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xb9, 0xf0, 0x05, 0x86, 0xa3, 0xe0, 0x54, 0xfe} },
-{ 0x15f2,	16,	{0xf0, 0x02, 0x13, 0x43, 0x53, 0x2d, 0xfa, 0xe5, 0x23, 0x60, 0x08, 0x75, 0x23, 0x00, 0xd2, 0xe7} },
-{ 0x1602,	16,	{0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xc9, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x16, 0x90, 0x90, 0x20, 0x50} },
-{ 0x1612,	16,	{0x74, 0x01, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0} },
-{ 0x1622,	16,	{0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0xc0, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84} },
-{ 0x1632,	16,	{0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0, 0x24, 0x38, 0xf0} },
-{ 0x1642,	16,	{0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60, 0x30, 0x03, 0x03} },
-{ 0x1652,	16,	{0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0} },
-{ 0x1662,	16,	{0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11, 0x8b, 0x23, 0x90} },
-{ 0x1672,	16,	{0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80, 0x1b, 0xe0, 0xde} },
-{ 0x1682,	14,	{0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
-{ 0x1690,	16,	{0x90, 0x20, 0x09, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x02, 0x13, 0x43, 0x90, 0x20} },
-{ 0x16a0,	16,	{0x12, 0xe0, 0x54, 0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14} },
-{ 0x16b0,	16,	{0x60, 0x09, 0x02, 0x13, 0x43, 0x02, 0x17, 0x87, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5} },
-{ 0x16c0,	16,	{0x38, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2e, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82} },
-{ 0x16d0,	16,	{0xf8, 0x43, 0x82, 0x05, 0xe0, 0x42, 0x34, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13} },
-{ 0x16e0,	16,	{0x43, 0x30, 0xe1, 0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x53, 0x82, 0xf8} },
-{ 0x16f0,	16,	{0x43, 0x82, 0x04, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74} },
-{ 0x1700,	16,	{0x02, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
-{ 0x1710,	16,	{0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x80, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0} },
-{ 0x1720,	16,	{0x05, 0x86, 0x90, 0x7f, 0xe5, 0xe5, 0x3e, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0} },
-{ 0x1730,	16,	{0xf0, 0xf0, 0xf0, 0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58} },
-{ 0x1740,	16,	{0x74, 0x00, 0xf0, 0x90, 0x7f, 0xbb, 0xed, 0xf0, 0x90, 0x20, 0x11, 0xe0, 0x54, 0xfe, 0xf0, 0x02} },
-{ 0x1750,	16,	{0x13, 0x43, 0x7f, 0x40, 0x90, 0x7d, 0x80, 0x05, 0x86, 0x90, 0x20, 0x10, 0xe5, 0x84, 0xfe, 0x24} },
-{ 0x1760,	16,	{0x05, 0xfd, 0x8d, 0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05} },
-{ 0x1770,	16,	{0x86, 0xdf, 0xef, 0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xbb, 0xf0, 0x05, 0x86, 0xa3} },
-{ 0x1780,	16,	{0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x53, 0x2e, 0xfa, 0xe5, 0x24, 0x60, 0x08, 0x75, 0x24} },
-{ 0x1790,	16,	{0x00, 0xd2, 0xe7, 0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x18, 0x21} },
-{ 0x17a0,	16,	{0x90, 0x20, 0x50, 0x74, 0x02, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0} },
-{ 0x17b0,	16,	{0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x40, 0x05, 0x86, 0xe5, 0x85, 0xf0} },
-{ 0x17c0,	16,	{0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0} },
-{ 0x17d0,	16,	{0x24, 0x38, 0xf0, 0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60} },
-{ 0x17e0,	16,	{0x30, 0x03, 0x03, 0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0} },
-{ 0x17f0,	16,	{0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11} },
-{ 0x1800,	16,	{0x8b, 0x24, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80} },
-{ 0x1810,	16,	{0x1b, 0xe0, 0xde, 0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00} },
-{ 0x1820,	16,	{0xf0, 0x90, 0x20, 0x11, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xcb, 0xf0, 0x02, 0x13, 0x43, 0x90} },
-{ 0x1830,	16,	{0x20, 0x1a, 0xe0, 0x54, 0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5} },
-{ 0x1840,	16,	{0x14, 0x60, 0x09, 0x02, 0x13, 0x43, 0x02, 0x19, 0x18, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0} },
-{ 0x1850,	16,	{0xf5, 0x39, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2f, 0x01, 0x02, 0x13, 0x43, 0x53} },
-{ 0x1860,	16,	{0x82, 0xf8, 0x43, 0x82, 0x05, 0xe0, 0x42, 0x35, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02} },
-{ 0x1870,	16,	{0x13, 0x43, 0x30, 0xe1, 0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x53, 0x82} },
-{ 0x1880,	16,	{0xf8, 0x43, 0x82, 0x04, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50} },
-{ 0x1890,	16,	{0x74, 0x03, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0} },
-{ 0x18a0,	16,	{0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x00, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84} },
-{ 0x18b0,	16,	{0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xe5, 0x3f, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0} },
-{ 0x18c0,	16,	{0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20} },
-{ 0x18d0,	16,	{0x58, 0x74, 0x00, 0xf0, 0x90, 0x7f, 0xbd, 0xed, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x54, 0xfe, 0xf0} },
-{ 0x18e0,	16,	{0x02, 0x13, 0x43, 0x7f, 0x40, 0x90, 0x7d, 0x00, 0x05, 0x86, 0x90, 0x20, 0x18, 0xe5, 0x84, 0xfe} },
-{ 0x18f0,	16,	{0x24, 0x05, 0xfd, 0x8d, 0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3} },
-{ 0x1900,	16,	{0x05, 0x86, 0xdf, 0xef, 0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xbd, 0xf0, 0x05, 0x86} },
-{ 0x1910,	16,	{0xa3, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x53, 0x2f, 0xfa, 0xe5, 0x25, 0x60, 0x08, 0x75} },
-{ 0x1920,	16,	{0x25, 0x00, 0xd2, 0xe7, 0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x19} },
-{ 0x1930,	16,	{0xb2, 0x90, 0x20, 0x50, 0x74, 0x03, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2} },
-{ 0x1940,	16,	{0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7c, 0xc0, 0x05, 0x86, 0xe5, 0x85} },
-{ 0x1950,	16,	{0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86} },
-{ 0x1960,	16,	{0xe0, 0x24, 0x38, 0xf0, 0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78} },
-{ 0x1970,	16,	{0x60, 0x30, 0x03, 0x03, 0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0} },
-{ 0x1980,	16,	{0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70} },
-{ 0x1990,	16,	{0x11, 0x8b, 0x25, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
-{ 0x19a0,	16,	{0x80, 0x1b, 0xe0, 0xde, 0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74} },
-{ 0x19b0,	16,	{0x00, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xcd, 0xf0, 0x02, 0x13, 0x43} },
-{ 0x19c0,	1,	{0x32} },
-{ 0x19c1,	4,	{0xad, 0x07, 0xac, 0x06} },
-{ 0x19c5,	16,	{0x79, 0x06, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb} },
-{ 0x19d5,	16,	{0x4a, 0x70, 0x03, 0x02, 0x1b, 0x09, 0xe9, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x1a, 0xdb, 0x90} },
-{ 0x19e5,	16,	{0x19, 0xeb, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x1a, 0xb9, 0x02, 0x1a, 0x71, 0x02, 0x1a, 0x5a, 0x02} },
-{ 0x19f5,	16,	{0x1a, 0x40, 0x02, 0x1a, 0x2f, 0x02, 0x1a, 0x1a, 0x02, 0x1a, 0x00, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
-{ 0x1a05,	16,	{0x80, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6} },
-{ 0x1a15,	16,	{0xf0, 0x19, 0x02, 0x1a, 0xdb, 0x19, 0x8d, 0x82, 0x8c, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x0a} },
-{ 0x1a25,	16,	{0xa3, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x02, 0x1a, 0xdb, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
-{ 0x1a35,	16,	{0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x19, 0x02, 0x1a, 0xdb, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
-{ 0x1a45,	16,	{0x80, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa1, 0x90, 0x7f, 0xa6} },
-{ 0x1a55,	16,	{0xf0, 0x19, 0x02, 0x1a, 0xdb, 0xeb, 0x64, 0x01, 0x4a, 0x70, 0x08, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
-{ 0x1a65,	16,	{0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xf5, 0x69, 0x19, 0x80, 0x6a, 0xed, 0x24, 0x04, 0xf5} },
-{ 0x1a75,	16,	{0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0x64, 0x02, 0x4e, 0x70, 0x08, 0x90, 0x7f} },
-{ 0x1a85,	16,	{0xa5, 0xe0, 0x44, 0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xff, 0xed, 0x24, 0x06, 0xf5, 0x82} },
-{ 0x1a95,	16,	{0xe4, 0x3c, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
-{ 0x1aa5,	16,	{0xef, 0xf0, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12} },
-{ 0x1ab5,	16,	{0x9a, 0x8e, 0x80, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xff} },
-{ 0x1ac5,	16,	{0xed, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfa, 0xa3, 0xe0, 0xf5, 0x82, 0x8a} },
-{ 0x1ad5,	16,	{0x83, 0xef, 0xf0, 0x7f, 0x08, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x69, 0x30, 0xe0, 0xf7, 0x30} },
-{ 0x1ae5,	16,	{0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xe9, 0xd3, 0x94, 0x02, 0x50, 0x03, 0x02} },
-{ 0x1af5,	16,	{0x19, 0xc7, 0xe5, 0x69, 0x30, 0xe1, 0x03, 0x02, 0x19, 0xc7, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40} },
-{ 0x1b05,	6,	{0xf0, 0x7f, 0x07, 0x22, 0x7f, 0x08} },
-{ 0x1b0b,	1,	{0x22} },
-{ 0x1b0c,	16,	{0x8e, 0x5f, 0x8f, 0x60, 0x8c, 0x61, 0x8d, 0x62, 0xaf, 0x03, 0x1b, 0xef, 0x60, 0x24, 0x05, 0x60} },
-{ 0x1b1c,	16,	{0xe5, 0x60, 0xae, 0x5f, 0x70, 0x02, 0x05, 0x5f, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05} },
-{ 0x1b2c,	16,	{0x62, 0xe5, 0x62, 0xac, 0x61, 0x70, 0x02, 0x05, 0x61, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
-{ 0x1b3c,	3,	{0x80, 0xd6, 0x22} },
-{ 0x8000,	4,	{0x8e, 0x69, 0x8f, 0x6a} },
-{ 0x8004,	16,	{0x75, 0x6b, 0x03, 0xe5, 0x6a, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x69, 0xf5, 0x83, 0xe0, 0xfe} },
-{ 0x8014,	16,	{0xa3, 0xe0, 0x4e, 0x70, 0x03, 0x02, 0x81, 0x0e, 0xe5, 0x6b, 0x60, 0x4e, 0x14, 0x60, 0x38, 0x14} },
-{ 0x8024,	16,	{0x60, 0x20, 0x14, 0x60, 0x03, 0x02, 0x80, 0xb2, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
-{ 0x8034,	16,	{0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6, 0xf0} },
-{ 0x8044,	16,	{0x80, 0x6c, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x09, 0xa3, 0xa3} },
-{ 0x8054,	16,	{0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x57, 0x15, 0x6b, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3} },
-{ 0x8064,	16,	{0xa3, 0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x44, 0xe5, 0x6a, 0x24, 0x06, 0xf5, 0x82} },
-{ 0x8074,	16,	{0xe4, 0x35, 0x69, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5} },
-{ 0x8084,	16,	{0x83, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe5, 0x6a, 0x24} },
-{ 0x8094,	16,	{0x04, 0xf5, 0x82, 0xe4, 0x35, 0x69, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12, 0x9a, 0x8e, 0x85} },
-{ 0x80a4,	16,	{0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xa3, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0x8e, 0x90, 0x7f} },
-{ 0x80b4,	16,	{0xa5, 0xe0, 0xf5, 0x6c, 0x30, 0xe0, 0xf7, 0x30, 0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06} },
-{ 0x80c4,	16,	{0x22, 0xe5, 0x6c, 0x20, 0xe1, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22} },
-{ 0x80d4,	16,	{0xe5, 0x6b, 0x70, 0x31, 0x7f, 0x01, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
-{ 0x80e4,	16,	{0x80, 0xf0, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90} },
-{ 0x80f4,	16,	{0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x6c, 0x30, 0xe0, 0xf7, 0x30, 0xe1, 0xd5, 0x75} },
-{ 0x8104,	12,	{0x6b, 0x03, 0x02, 0x80, 0x07, 0x15, 0x6b, 0x02, 0x80, 0x07, 0x7f, 0x08} },
-{ 0x8110,	1,	{0x22} },
-{ 0x8111,	2,	{0xac, 0x07} },
-{ 0x8113,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xec, 0x25, 0xe0, 0x44, 0x41, 0x90, 0x7f, 0xa6, 0xf0} },
-{ 0x8123,	16,	{0x7b, 0x3c, 0xaf, 0x03, 0x1b, 0xef, 0x70, 0x16, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
-{ 0x8133,	16,	{0x7f, 0xa6, 0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x60, 0xd4, 0x80, 0xf8, 0x90, 0x7f} },
-{ 0x8143,	16,	{0xa5, 0xe0, 0xfd, 0x30, 0xe0, 0xdc, 0x20, 0xe1, 0x09, 0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f} },
-{ 0x8153,	16,	{0xf9, 0x22, 0xed, 0x30, 0xe2, 0x0c, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f} },
-{ 0x8163,	16,	{0xfa, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0x7b, 0x1e} },
-{ 0x8173,	16,	{0xaf, 0x03, 0x1b, 0xef, 0x70, 0x16, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6} },
-{ 0x8183,	16,	{0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x60, 0x86, 0x80, 0xf8, 0x90, 0x7f, 0xa5, 0xe0} },
-{ 0x8193,	16,	{0xfd, 0x20, 0xe0, 0xdc, 0x7b, 0x3c, 0xaf, 0x03, 0x1b, 0xef, 0x70, 0x19, 0x90, 0x7f, 0xa5, 0xe0} },
-{ 0x81a3,	16,	{0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03} },
-{ 0x81b3,	16,	{0x02, 0x81, 0x13, 0x80, 0xf5, 0x90, 0x7f, 0xa5, 0xe0, 0xfd, 0x30, 0xe0, 0xd9, 0x30, 0xe2, 0x09} },
-{ 0x81c3,	16,	{0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f, 0xfa, 0x22, 0xc2, 0xaf, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
-{ 0x81d3,	12,	{0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0xd2, 0xaf, 0xff, 0x7e, 0x00} },
-{ 0x81df,	1,	{0x22} },
-{ 0x81e0,	16,	{0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xf5} },
-{ 0x81f0,	16,	{0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf9, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0} },
-{ 0x8200,	16,	{0x44, 0x10, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83} },
-{ 0x8210,	16,	{0xa3, 0xf0, 0xed, 0x60, 0x29, 0x74, 0x01, 0x7e, 0x00, 0xa8, 0x07, 0x08, 0x80, 0x05, 0xc3, 0x33} },
-{ 0x8220,	16,	{0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0xe4, 0xef, 0x55, 0x3b, 0x60, 0x0a, 0x8b, 0x82, 0x8a, 0x83} },
-{ 0x8230,	16,	{0xa3, 0x74, 0x01, 0xf0, 0x80, 0x08, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0x74, 0xad, 0xf0, 0x8b, 0x82} },
-{ 0x8240,	16,	{0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x54} },
-{ 0x8250,	15,	{0xef, 0xf0, 0xae, 0x02, 0xaf, 0x03, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe9, 0xf0} },
-{ 0x825f,	1,	{0x22} },
-{ 0x8260,	4,	{0x8f, 0x68, 0x8d, 0x69} },
-{ 0x8264,	16,	{0xe4, 0xf5, 0x6a, 0x74, 0x3c, 0x2f, 0xf8, 0x76, 0x08, 0xe5, 0x68, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
-{ 0x8274,	16,	{0xa0, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
-{ 0x8284,	16,	{0xa3, 0xe0, 0xff, 0x7b, 0x80, 0x7a, 0x25, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x50} },
-{ 0x8294,	16,	{0x3c, 0xe5, 0x68, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0xa0, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
-{ 0x82a4,	16,	{0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x96, 0x78} },
-{ 0x82b4,	16,	{0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x40, 0x0c, 0x75, 0x6a, 0x40, 0x74, 0x3c, 0x25, 0x68, 0xf8, 0x76} },
-{ 0x82c4,	16,	{0x10, 0x80, 0x0a, 0x75, 0x6a, 0x80, 0x74, 0x3c, 0x25, 0x68, 0xf8, 0x76, 0x38, 0xe5, 0x6a, 0x45} },
-{ 0x82d4,	16,	{0x69, 0x44, 0x01, 0xff, 0xe5, 0x68, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x82e4,	5,	{0x20, 0xf5, 0x83, 0xef, 0xf0} },
-{ 0x82e9,	1,	{0x22} },
-{ 0x82ea,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x5f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
-{ 0x82fa,	16,	{0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xf5, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5} },
-{ 0x830a,	16,	{0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x44, 0x03, 0xf0, 0xaf, 0x5f, 0x7d, 0x06, 0x12, 0x82} },
-{ 0x831a,	16,	{0x60, 0xaf, 0x5f, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0x85, 0x62, 0x82, 0x85, 0x61, 0x83, 0xa3, 0xa3} },
-{ 0x832a,	16,	{0xe0, 0x20, 0xe0, 0x28, 0xe0, 0xf5, 0x60, 0xe5, 0x62, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x61} },
-{ 0x833a,	16,	{0xf5, 0x83, 0xe0, 0xf5, 0x60, 0xe5, 0x62, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83} },
-{ 0x834a,	16,	{0xe0, 0xf5, 0x60, 0xaf, 0x5f, 0x7d, 0x06, 0x12, 0x82, 0x60, 0x80, 0xcc, 0x74, 0x96, 0x25, 0x5f} },
-{ 0x835a,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x5f, 0x25, 0xe0, 0xff, 0xc3, 0x74} },
-{ 0x836a,	16,	{0x0c, 0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82} },
-{ 0x837a,	16,	{0xfe, 0xe5, 0x5f, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xee, 0xf0} },
-{ 0x838a,	16,	{0xa3, 0xef, 0xf0, 0xaf, 0x5f, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc} },
-{ 0x839a,	4,	{0x42, 0x30, 0x7f, 0x00} },
-{ 0x839e,	1,	{0x22} },
-{ 0x839f,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x47, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
-{ 0x83af,	16,	{0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x49, 0x8f, 0x4a, 0x74, 0x96, 0x25, 0x47, 0xf5, 0x82, 0xe4} },
-{ 0x83bf,	16,	{0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x4a, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x49, 0xf5} },
-{ 0x83cf,	16,	{0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf, 0x47, 0xe4, 0xfd, 0x12, 0x81, 0xe0, 0xaf, 0x47, 0x7d, 0x06} },
-{ 0x83df,	16,	{0x12, 0x82, 0x60, 0xe5, 0x4a, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x49, 0xf5, 0x83, 0xe0, 0x30} },
-{ 0x83ef,	16,	{0xe0, 0x0b, 0x85, 0x4a, 0x82, 0x85, 0x49, 0x83, 0xe0, 0xf5, 0x48, 0x80, 0xe6, 0xaf, 0x47, 0x74} },
-{ 0x83ff,	16,	{0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x30, 0xe5, 0x47, 0x25} },
-{ 0x840f,	13,	{0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0xff} },
-{ 0x841c,	1,	{0x22} },
-{ 0x841d,	4,	{0x8e, 0x47, 0x8f, 0x48} },
-{ 0x8421,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x49, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82} },
-{ 0x8431,	16,	{0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x70, 0x23, 0x85, 0x48, 0x82, 0x8e, 0x83, 0xa3} },
-{ 0x8441,	16,	{0xe0, 0x30, 0xe0, 0x07, 0xaf, 0x49, 0x7d, 0x02, 0x12, 0x82, 0x60, 0x85, 0x48, 0x82, 0x85, 0x47} },
-{ 0x8451,	15,	{0x83, 0xa3, 0xe0, 0x30, 0xe1, 0x07, 0xaf, 0x49, 0x7d, 0x04, 0x12, 0x82, 0x60, 0x7f, 0x00} },
-{ 0x8460,	1,	{0x22} },
-{ 0x8461,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0xa3, 0xa3, 0xa3, 0xe0, 0xfc, 0xed} },
-{ 0x8471,	16,	{0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xc0, 0x83, 0xc0} },
-{ 0x8481,	16,	{0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0} },
-{ 0x8491,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0xe0, 0xfd, 0xec, 0x6d, 0xd0} },
-{ 0x84a1,	16,	{0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f} },
-{ 0x84b1,	16,	{0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82} },
-{ 0x84c1,	16,	{0x8e, 0x83, 0xa3, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0} },
-{ 0x84d1,	16,	{0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0} },
-{ 0x84e1,	16,	{0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xff, 0xed, 0x6f, 0xd0, 0x82, 0xd0} },
-{ 0x84f1,	3,	{0x83, 0xf0, 0x22} },
-{ 0x84f4,	4,	{0x8e, 0x5f, 0x8f, 0x60} },
-{ 0x84f8,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x8508,	16,	{0x1f, 0xad, 0x82, 0xf5, 0x66, 0x8d, 0x67, 0xaa, 0x5f, 0xa9, 0x60, 0x7b, 0x01, 0xc0, 0x03, 0xc0} },
-{ 0x8518,	16,	{0x01, 0xef, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x92, 0xf9, 0x74, 0x02, 0x35, 0xf0, 0xa8, 0x01, 0xfc} },
-{ 0x8528,	16,	{0xad, 0x03, 0xd0, 0x01, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x0d, 0x12, 0x9a, 0x1f, 0x85, 0x60, 0x82} },
-{ 0x8538,	16,	{0x85, 0x5f, 0x83, 0xa3, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb, 0x7f} },
-{ 0x8548,	16,	{0x00, 0x7e, 0x08, 0x7d, 0x07, 0x7c, 0x00, 0x12, 0x9b, 0x2e, 0x8f, 0x64, 0x8e, 0x63, 0x8d, 0x62} },
-{ 0x8558,	16,	{0x8c, 0x61, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x70, 0x09} },
-{ 0x8568,	16,	{0x75, 0x64, 0x01, 0xf5, 0x63, 0xf5, 0x62, 0xf5, 0x61, 0x7f, 0xff, 0x7e, 0xff, 0x7d, 0x00, 0x7c} },
-{ 0x8578,	16,	{0x00, 0xab, 0x64, 0xaa, 0x63, 0xa9, 0x62, 0xa8, 0x61, 0xd3, 0x12, 0x9b, 0xc0, 0x40, 0x0c, 0x75} },
-{ 0x8588,	16,	{0x64, 0xff, 0x75, 0x63, 0xff, 0x75, 0x62, 0x00, 0x75, 0x61, 0x00, 0x85, 0x67, 0x82, 0x85, 0x66} },
-{ 0x8598,	16,	{0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xe5, 0x64} },
-{ 0x85a8,	16,	{0xf0, 0xaf, 0x64, 0xae, 0x63, 0xad, 0x62, 0xac, 0x61, 0x78, 0x08, 0x12, 0x9b, 0xd1, 0x85, 0x67} },
-{ 0x85b8,	16,	{0x82, 0x85, 0x66, 0x83, 0xa3, 0xef, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3} },
-{ 0x85c8,	16,	{0xe0, 0x54, 0x7f, 0xf0, 0xe4, 0xf5, 0x65, 0xe5, 0x60, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x5f} },
-{ 0x85d8,	16,	{0xf5, 0x83, 0xe0, 0xff, 0xb4, 0x62, 0x05, 0x43, 0x65, 0x0a, 0x80, 0x10, 0xef, 0xb4, 0x72, 0x05} },
-{ 0x85e8,	16,	{0x43, 0x65, 0x08, 0x80, 0x07, 0xef, 0xb4, 0x74, 0x03, 0x43, 0x65, 0x02, 0xe5, 0x60, 0x24, 0x0b} },
-{ 0x85f8,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0x30, 0xe3, 0x03, 0x43, 0x65, 0x80, 0xef} },
-{ 0x8608,	16,	{0x30, 0xe7, 0x12, 0x43, 0x65, 0x40, 0xe5, 0x67, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5} },
-{ 0x8618,	16,	{0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x60, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83} },
-{ 0x8628,	16,	{0xe0, 0xff, 0x20, 0xe1, 0x03, 0x30, 0xe4, 0x27, 0x85, 0x60, 0x82, 0x85, 0x5f, 0x83, 0xe0, 0x14} },
-{ 0x8638,	16,	{0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x3b, 0xe5, 0x67} },
-{ 0x8648,	16,	{0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x17, 0x85} },
-{ 0x8658,	16,	{0x60, 0x82, 0x85, 0x5f, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3} },
-{ 0x8668,	16,	{0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x3b, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3, 0x74} },
-{ 0x8678,	16,	{0xbf, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x65, 0xf0, 0xe5} },
-{ 0x8688,	16,	{0x60, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x04} },
-{ 0x8698,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24, 0x0a, 0xf5, 0x82, 0xe4} },
-{ 0x86a8,	16,	{0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5} },
-{ 0x86b8,	16,	{0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff} },
-{ 0x86c8,	16,	{0xe5, 0x67, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24} },
-{ 0x86d8,	16,	{0x09, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x07, 0xf5, 0x82} },
-{ 0x86e8,	16,	{0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3} },
-{ 0x86f8,	16,	{0xe4, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xf0, 0x85, 0x60, 0x82, 0x85, 0x5f} },
-{ 0x8708,	16,	{0x83, 0xe0, 0x14, 0xff, 0x7d, 0x06, 0x12, 0x82, 0x60, 0x75, 0x65, 0x08, 0xe5, 0x60, 0x24, 0x0c} },
-{ 0x8718,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x43, 0x65, 0x10, 0xe5, 0x67, 0x24} },
-{ 0x8728,	16,	{0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x45, 0x65, 0xf0, 0xe5, 0x60} },
-{ 0x8738,	16,	{0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x14, 0xff, 0x25, 0xe0, 0x25, 0xe0} },
-{ 0x8748,	16,	{0xff, 0xe5, 0x60, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x24, 0xfb, 0x4f} },
-{ 0x8758,	16,	{0xf5, 0x65, 0xe5, 0x60, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x24, 0xd0} },
-{ 0x8768,	16,	{0x60, 0x15, 0x14, 0x60, 0x17, 0x24, 0xc2, 0x60, 0x09, 0x24, 0x0a, 0x70, 0x12, 0x43, 0x65, 0x18} },
-{ 0x8778,	16,	{0x80, 0x0d, 0x43, 0x65, 0x08, 0x80, 0x08, 0x43, 0x65, 0x38, 0x80, 0x03, 0x43, 0x65, 0x28, 0x85} },
-{ 0x8788,	13,	{0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x65, 0xf0, 0x7f, 0x00} },
-{ 0x8795,	1,	{0x22} },
-{ 0x8796,	4,	{0x8e, 0x47, 0x8f, 0x48} },
-{ 0x879a,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x4a, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
-{ 0x87aa,	16,	{0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x4d, 0x8f, 0x4e, 0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01} },
-{ 0x87ba,	16,	{0xf5, 0x4c, 0xe4, 0x3e, 0xf5, 0x4b, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x08, 0xf0, 0xe5, 0x4a, 0x04} },
-{ 0x87ca,	16,	{0x85, 0x4c, 0x82, 0x85, 0x4b, 0x83, 0xf0, 0xa3, 0xe4, 0xf0, 0xe5, 0x4e, 0x24, 0x06, 0xf5, 0x82} },
-{ 0x87da,	16,	{0xe4, 0x35, 0x4d, 0xf5, 0x83, 0xe0, 0x85, 0x4c, 0x82, 0x85, 0x4b, 0x83, 0xa3, 0xa3, 0xf0, 0xe5} },
-{ 0x87ea,	16,	{0x4e, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4d, 0xf5, 0x83, 0xe0, 0x54, 0x1e, 0x85, 0x4c, 0x82} },
-{ 0x87fa,	16,	{0x85, 0x4b, 0x83, 0xa3, 0xa3, 0xa3, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x2b} },
-{ 0x880a,	16,	{0xf8, 0xe6, 0xff, 0xe5, 0x4c, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x4b, 0xf5, 0x83, 0xef, 0xf0} },
-{ 0x881a,	16,	{0xaf, 0x4a, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x49, 0x7f} },
-{ 0x882a,	16,	{0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xe5, 0x49, 0x5f, 0xff} },
-{ 0x883a,	16,	{0xe5, 0x4c, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4b, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xc3} },
-{ 0x884a,	5,	{0x74, 0x07, 0xf0, 0x7f, 0x00} },
-{ 0x884f,	1,	{0x22} },
-{ 0x8850,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x8860,	16,	{0xaf, 0x82, 0xf5, 0x47, 0x8f, 0x48, 0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xfd, 0xe4, 0x3e} },
-{ 0x8870,	16,	{0xfc, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x0a, 0xf0, 0xe5, 0x48, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35} },
-{ 0x8880,	16,	{0x47, 0xf5, 0x83, 0xe0, 0x8d, 0x82, 0x8c, 0x83, 0xf0, 0x90, 0x7f, 0xc3, 0x74, 0x02, 0xf0, 0x7f} },
-{ 0x8890,	1,	{0x00} },
-{ 0x8891,	1,	{0x22} },
-{ 0x8892,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x88a2,	16,	{0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
-{ 0x88b2,	16,	{0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
-{ 0x88c2,	11,	{0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0x7f, 0x00} },
-{ 0x88cd,	1,	{0x22} },
-{ 0x88ce,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x88de,	16,	{0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
-{ 0x88ee,	16,	{0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
-{ 0x88fe,	11,	{0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x00} },
-{ 0x8909,	1,	{0x22} },
-{ 0x890a,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x891a,	16,	{0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0d, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3} },
-{ 0x892a,	16,	{0xe0, 0x44, 0x40, 0xf0, 0x80, 0x0f, 0xae, 0x04, 0xaf, 0x05, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3} },
-{ 0x893a,	7,	{0xa3, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x00} },
-{ 0x8941,	1,	{0x22} },
-{ 0x8942,	4,	{0x8e, 0x47, 0x8f, 0x48} },
-{ 0x8946,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0, 0xf5, 0x4b, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x24, 0xfe, 0x60} },
-{ 0x8956,	16,	{0x16, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x28, 0x24, 0x03, 0x70, 0x2e, 0x7e, 0x7e, 0x7f, 0x80, 0x75} },
-{ 0x8966,	16,	{0x49, 0x7e, 0x75, 0x4a, 0x80, 0x80, 0x22, 0x7e, 0x7e, 0x7f, 0x00, 0x75, 0x49, 0x7e, 0x75, 0x4a} },
-{ 0x8976,	16,	{0x00, 0x80, 0x16, 0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x49, 0x7d, 0x75, 0x4a, 0x80, 0x80, 0x0a, 0x7e} },
-{ 0x8986,	16,	{0x7d, 0x7f, 0x00, 0x75, 0x49, 0x7d, 0x75, 0x4a, 0x00, 0xe5, 0x4b, 0x70, 0x20, 0x85, 0x4a, 0x82} },
-{ 0x8996,	16,	{0x85, 0x49, 0x83, 0x74, 0xff, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
-{ 0x89a6,	16,	{0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x3a, 0xe5, 0x48, 0x24} },
-{ 0x89b6,	16,	{0x02, 0xff, 0xe4, 0x35, 0x47, 0xfe, 0xe5, 0x4b, 0x60, 0x10, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x85} },
-{ 0x89c6,	16,	{0x4a, 0x82, 0x85, 0x49, 0x83, 0xf0, 0x15, 0x4b, 0x80, 0xec, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83} },
-{ 0x89d6,	16,	{0xa3, 0xe0, 0xff, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x25, 0xe0, 0x24, 0xb5, 0xf5, 0x82} },
-{ 0x89e6,	9,	{0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x7f, 0x00} },
-{ 0x89ef,	1,	{0x22} },
-{ 0x89f0,	16,	{0xef, 0x24, 0x01, 0xf5, 0x48, 0xe4, 0x3e, 0xf5, 0x47, 0x7c, 0x7b, 0x7d, 0x80, 0x7e, 0x7b, 0x7f} },
-{ 0x8a00,	16,	{0x80, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x07, 0xf0, 0xef, 0x24, 0x01, 0xff, 0xe4, 0x3e, 0x90, 0x01} },
-{ 0x8a10,	16,	{0x31, 0xf0, 0xa3, 0xef, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xfe} },
-{ 0x8a20,	16,	{0xa3, 0xe0, 0x8e, 0x49, 0xf5, 0x4a, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x9e, 0x60} },
-{ 0x8a30,	16,	{0x61, 0x24, 0xf9, 0x60, 0x0e, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8a, 0xdd, 0x24, 0x14, 0x60, 0x03} },
-{ 0x8a40,	16,	{0x02, 0x8b, 0x30, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3} },
-{ 0x8a50,	16,	{0xe4, 0x9f, 0xf5, 0x4c, 0x74, 0x01, 0x9e, 0xf5, 0x4b, 0xd3, 0xe5, 0x4c, 0x94, 0x40, 0xe5, 0x4b} },
-{ 0x8a60,	16,	{0x94, 0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5, 0x4a, 0x95, 0x4c, 0xe5} },
-{ 0x8a70,	16,	{0x49, 0x95, 0x4b, 0x50, 0x03, 0x02, 0x8b, 0x30, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82, 0x85} },
-{ 0x8a80,	16,	{0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a, 0x02} },
-{ 0x8a90,	16,	{0x8b, 0x30, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x74} },
-{ 0x8aa0,	16,	{0x30, 0x9f, 0xf5, 0x4c, 0xe4, 0x9e, 0xf5, 0x4b, 0xd3, 0xe5, 0x4c, 0x94, 0x40, 0xe5, 0x4b, 0x94} },
-{ 0x8ab0,	16,	{0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5, 0x4a, 0x95, 0x4c, 0xe5, 0x49} },
-{ 0x8ac0,	16,	{0x95, 0x4b, 0x40, 0x6c, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3} },
-{ 0x8ad0,	16,	{0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a, 0x80, 0x53, 0x85, 0x48, 0x82} },
-{ 0x8ae0,	16,	{0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f, 0xf5, 0x4c, 0xe4, 0x9e} },
-{ 0x8af0,	16,	{0xf5, 0x4b, 0x45, 0x4c, 0x70, 0x07, 0xf5, 0x4b, 0x75, 0x4c, 0x40, 0x80, 0x11, 0xd3, 0xe5, 0x4c} },
-{ 0x8b00,	16,	{0x94, 0x40, 0xe5, 0x4b, 0x94, 0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5} },
-{ 0x8b10,	16,	{0x4a, 0x95, 0x4c, 0xe5, 0x49, 0x95, 0x4b, 0x40, 0x17, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82} },
-{ 0x8b20,	16,	{0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a} },
-{ 0x8b30,	16,	{0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x9e, 0x70, 0x03, 0x02, 0x8b, 0xf0, 0x24, 0xf9} },
-{ 0x8b40,	16,	{0x60, 0x58, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8c, 0x40, 0x24, 0x14, 0x60, 0x03, 0x02, 0x8c, 0x84} },
-{ 0x8b50,	16,	{0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xd3, 0x94, 0xff, 0xee} },
-{ 0x8b60,	16,	{0x94, 0x00, 0x40, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2c, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a} },
-{ 0x8b70,	16,	{0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x70, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2c, 0xe0} },
-{ 0x8b80,	16,	{0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a} },
-{ 0x8b90,	16,	{0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83} },
-{ 0x8ba0,	16,	{0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x80, 0xee, 0x94, 0x00, 0x50, 0x03, 0x02, 0x8c} },
-{ 0x8bb0,	16,	{0x84, 0xd3, 0xef, 0x94, 0xff, 0xee, 0x94, 0x00, 0x40, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2d} },
-{ 0x8bc0,	16,	{0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x70, 0x03, 0x02} },
-{ 0x8bd0,	16,	{0x8c, 0x84, 0x90, 0x01, 0x2d, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31} },
-{ 0x8be0,	16,	{0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2} },
-{ 0x8bf0,	16,	{0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x20, 0xee} },
-{ 0x8c00,	16,	{0x94, 0x00, 0x50, 0x03, 0x02, 0x8c, 0x84, 0xd3, 0xef, 0x94, 0x2f, 0xee, 0x94, 0x00, 0x50, 0x74} },
-{ 0x8c10,	16,	{0x90, 0x01, 0x2e, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e} },
-{ 0x8c20,	16,	{0x60, 0x62, 0x90, 0x01, 0x2e, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31} },
-{ 0x8c30,	16,	{0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd5} },
-{ 0x8c40,	16,	{0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0x01, 0x2f, 0xcf, 0xf0} },
-{ 0x8c50,	16,	{0xa3, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x60, 0x24} },
-{ 0x8c60,	16,	{0x90, 0x01, 0x2f, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0} },
-{ 0x8c70,	16,	{0xff, 0x90, 0x01, 0x31, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
-{ 0x8c80,	16,	{0xef, 0xf0, 0x80, 0xcf, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xa3, 0xe0} },
-{ 0x8c90,	6,	{0x90, 0x7f, 0xc3, 0xf0, 0x7f, 0x00} },
-{ 0x8c96,	1,	{0x22} },
-{ 0x8c97,	16,	{0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xfd, 0xe4, 0x3e, 0xfc, 0x8f, 0x82, 0x8e, 0x83, 0x74} },
-{ 0x8ca7,	16,	{0x0b, 0xf0, 0x90, 0x20, 0x70, 0xe0, 0x54, 0xf0, 0xff, 0xc4, 0x54, 0x0f, 0x8d, 0x82, 0x8c, 0x83} },
-{ 0x8cb7,	16,	{0xf0, 0x90, 0x11, 0xf0, 0xe4, 0x93, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xf0, 0x90, 0x11, 0xf1, 0xe4} },
-{ 0x8cc7,	16,	{0x93, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xf0, 0xe4, 0x90, 0x01, 0x33, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x8cd7,	16,	{0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xed, 0x24, 0x03, 0xfe, 0xe4, 0x3c, 0xa3} },
-{ 0x8ce7,	16,	{0xf0, 0xa3, 0xce, 0xf0, 0x7e, 0x01, 0x7f, 0x33, 0x12, 0x19, 0xc1, 0x90, 0x7f, 0xc3, 0x74, 0x14} },
-{ 0x8cf7,	3,	{0xf0, 0x7f, 0x00} },
-{ 0x8cfa,	1,	{0x22} },
-{ 0x8cfb,	4,	{0x8e, 0x40, 0x8f, 0x41} },
-{ 0x8cff,	16,	{0x85, 0x40, 0x43, 0x85, 0x41, 0x44, 0x85, 0x44, 0x82, 0x85, 0x43, 0x83, 0xe0, 0x14, 0xb4, 0x0f} },
-{ 0x8d0f,	16,	{0x00, 0x40, 0x03, 0x02, 0x8e, 0x32, 0x90, 0x8d, 0x1c, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x8d, 0x49} },
-{ 0x8d1f,	16,	{0x02, 0x8d, 0x5a, 0x02, 0x8d, 0x6b, 0x02, 0x8d, 0x8e, 0x02, 0x8d, 0x9f, 0x02, 0x8d, 0xb0, 0x02} },
-{ 0x8d2f,	16,	{0x8d, 0xc0, 0x02, 0x8d, 0xcb, 0x02, 0x8d, 0xdb, 0x02, 0x8d, 0xeb, 0x02, 0x8d, 0xfb, 0x02, 0x8e} },
-{ 0x8d3f,	16,	{0x02, 0x02, 0x8e, 0x32, 0x02, 0x8e, 0x12, 0x02, 0x8e, 0x22, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4} },
-{ 0x8d4f,	16,	{0x35, 0x43, 0xfe, 0x12, 0x82, 0xea, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5, 0x44, 0x24, 0x01, 0xff} },
-{ 0x8d5f,	16,	{0xe4, 0x35, 0x43, 0xfe, 0x12, 0x83, 0x9f, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8d6f,	16,	{0xf5, 0x46, 0xe4, 0x35, 0x43, 0xf5, 0x45, 0xe5, 0x46, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x45, 0xfe} },
-{ 0x8d7f,	16,	{0x12, 0x84, 0x61, 0xaf, 0x46, 0xae, 0x45, 0x12, 0x84, 0xf4, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5} },
-{ 0x8d8f,	16,	{0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0x92, 0x8f, 0x42, 0x02, 0x8e, 0x32} },
-{ 0x8d9f,	16,	{0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0xce, 0x8f, 0x42, 0x02, 0x8e} },
-{ 0x8daf,	16,	{0x32, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x89, 0x0a, 0x8f, 0x42, 0x80} },
-{ 0x8dbf,	16,	{0x72, 0xaf, 0x41, 0xae, 0x40, 0x12, 0x89, 0xf0, 0x8f, 0x42, 0x80, 0x67, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8dcf,	16,	{0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x87, 0x96, 0x8f, 0x42, 0x80, 0x57, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8ddf,	16,	{0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x84, 0x1d, 0x8f, 0x42, 0x80, 0x47, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8def,	16,	{0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0x50, 0x8f, 0x42, 0x80, 0x37, 0x12, 0x8c, 0x97, 0x8f} },
-{ 0x8dff,	16,	{0x42, 0x80, 0x30, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x11, 0xd8, 0x8f} },
-{ 0x8e0f,	16,	{0x42, 0x80, 0x20, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x89, 0x42, 0x8f} },
-{ 0x8e1f,	16,	{0x42, 0x80, 0x10, 0xaf, 0x41, 0xae, 0x40, 0x7c, 0x02, 0x7d, 0x4d, 0x7b, 0x40, 0x12, 0x1b, 0x0c} },
-{ 0x8e2f,	5,	{0xe4, 0xf5, 0x42, 0xaf, 0x42} },
-{ 0x8e34,	1,	{0x22} },
-{ 0x8e35,	8,	{0x8f, 0x61, 0x8e, 0x60, 0x8d, 0x5f, 0x8c, 0x5e} },
-{ 0x8e3d,	16,	{0x75, 0x68, 0x01, 0x75, 0x69, 0x3b, 0xe4, 0xf5, 0x67, 0xaf, 0x63, 0x15, 0x63, 0xef, 0x70, 0x03} },
-{ 0x8e4d,	16,	{0x02, 0x8e, 0xd3, 0xaf, 0x62, 0xe4, 0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xaf, 0x61} },
-{ 0x8e5d,	16,	{0xae, 0x60, 0xad, 0x5f, 0xac, 0x5e, 0x12, 0x9b, 0x2e, 0xaf, 0x03, 0x8f, 0x66, 0xaf, 0x61, 0xae} },
-{ 0x8e6d,	16,	{0x60, 0xad, 0x5f, 0xac, 0x5e, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xaf, 0x62, 0xe4} },
-{ 0x8e7d,	16,	{0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04} },
-{ 0x8e8d,	16,	{0x12, 0x9b, 0x2e, 0x8f, 0x61, 0x8e, 0x60, 0x8d, 0x5f, 0x8c, 0x5e, 0xe5, 0x66, 0x24, 0x30, 0xf5} },
-{ 0x8e9d,	16,	{0x66, 0xd3, 0x94, 0x39, 0x40, 0x06, 0x74, 0x07, 0x25, 0x66, 0xf5, 0x66, 0x05, 0x69, 0xe5, 0x69} },
-{ 0x8ead,	16,	{0xae, 0x68, 0x70, 0x02, 0x05, 0x68, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x05, 0x69, 0xe5} },
-{ 0x8ebd,	16,	{0x69, 0xae, 0x68, 0x70, 0x02, 0x05, 0x68, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x66, 0xf0, 0x05} },
-{ 0x8ecd,	16,	{0x67, 0x05, 0x67, 0x02, 0x8e, 0x46, 0xe5, 0x69, 0x15, 0x69, 0x70, 0x02, 0x15, 0x68, 0xaf, 0x67} },
-{ 0x8edd,	16,	{0x15, 0x67, 0xef, 0x60, 0x23, 0xe5, 0x69, 0x15, 0x69, 0xae, 0x68, 0x70, 0x02, 0x15, 0x68, 0xf5} },
-{ 0x8eed,	16,	{0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05, 0x65, 0xe5, 0x65, 0xac, 0x64, 0x70, 0x02, 0x05, 0x64, 0x14} },
-{ 0x8efd,	8,	{0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x80, 0xd6} },
-{ 0x8f05,	1,	{0x22} },
-{ 0x8f06,	16,	{0xe4, 0x90, 0x01, 0x67, 0xf0, 0x7e, 0x01, 0x7f, 0x68, 0x90, 0x01, 0x5c, 0xee, 0xf0, 0xa3, 0xef} },
-{ 0x8f16,	10,	{0xf0, 0x90, 0x01, 0x60, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
-{ 0x8f20,	16,	{0xaa, 0x07, 0xa9, 0x05, 0x90, 0x01, 0x67, 0xe0, 0xc3, 0x94, 0x40, 0x50, 0x61, 0xac, 0x02, 0x74} },
-{ 0x8f30,	16,	{0x01, 0x7e, 0x00, 0xa8, 0x04, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff} },
-{ 0x8f40,	16,	{0xe4, 0xef, 0x55, 0x30, 0x60, 0x45, 0xea, 0x04, 0xff, 0x90, 0x01, 0x60, 0xe0, 0xfc, 0xa3, 0xe0} },
-{ 0x8f50,	16,	{0xfd, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0xa3, 0xe9, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
-{ 0x8f60,	16,	{0xeb, 0xf0, 0x90, 0x01, 0x60, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9a, 0x8e, 0xfc, 0xd3, 0xe5, 0xf0} },
-{ 0x8f70,	16,	{0x94, 0x25, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0x60, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x68} },
-{ 0x8f80,	16,	{0xf0, 0xc2, 0xaf, 0x90, 0x01, 0x67, 0xe0, 0x04, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
-{ 0x8f90,	1,	{0x22} },
-{ 0x8f91,	16,	{0x90, 0x01, 0x67, 0xe0, 0xd3, 0x94, 0x00, 0x40, 0x55, 0x90, 0x01, 0x5c, 0xe0, 0xfc, 0xa3, 0xe0} },
-{ 0x8fa1,	16,	{0xaa, 0x04, 0xf9, 0x7b, 0x01, 0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0xaa, 0x06, 0xa9, 0x07, 0xa8} },
-{ 0x8fb1,	16,	{0x01, 0xac, 0x02, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x03, 0x12} },
-{ 0x8fc1,	16,	{0x9a, 0x1f, 0x90, 0x01, 0x5c, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9a, 0x8e, 0xfc, 0xd3, 0xe5, 0xf0} },
-{ 0x8fd1,	16,	{0x94, 0x25, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0x5c, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x68} },
-{ 0x8fe1,	16,	{0xf0, 0xc2, 0xaf, 0x90, 0x01, 0x67, 0xe0, 0x14, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
-{ 0x8ff1,	1,	{0x22} },
-{ 0x8ff2,	16,	{0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x5e, 0x7e, 0x7b, 0x7f, 0x80, 0x75, 0x63, 0x7b, 0x75, 0x64} },
-{ 0x9002,	16,	{0x80, 0xe5, 0x64, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x63, 0xa9, 0x07, 0x7b, 0x01, 0x8b, 0x65, 0xf5} },
-{ 0x9012,	16,	{0x66, 0x89, 0x67, 0xfe, 0x12, 0x8f, 0x91, 0xef, 0x60, 0x3b, 0xab, 0x65, 0xaa, 0x66, 0xa9, 0x67} },
-{ 0x9022,	16,	{0x12, 0x9a, 0x48, 0x14, 0xff, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0xb4, 0x02, 0x16, 0xc2, 0xaf} },
-{ 0x9032,	16,	{0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x44} },
-{ 0x9042,	16,	{0x04, 0xf0, 0xd2, 0xaf, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0xc3} },
-{ 0x9052,	5,	{0x74, 0x04, 0xf0, 0xd2, 0xaf} },
-{ 0x9057,	1,	{0x22} },
-{ 0x9058,	16,	{0x12, 0x8f, 0xf2, 0xe4, 0xf5, 0x5e, 0x74, 0x36, 0x25, 0x5e, 0xf8, 0xe6, 0x54, 0xf0, 0xf5, 0x5f} },
-{ 0x9068,	16,	{0x74, 0x63, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xe0, 0x65, 0x5f, 0xff, 0xc4} },
-{ 0x9078,	16,	{0x54, 0x0f, 0xf5, 0x60, 0x60, 0x22, 0x74, 0x63, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5} },
-{ 0x9088,	16,	{0x83, 0xe5, 0x5f, 0xf0, 0xaf, 0x5e, 0x7d, 0x01, 0xe5, 0x5f, 0x45, 0x60, 0xfb, 0x12, 0x8f, 0x20} },
-{ 0x9098,	16,	{0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2, 0x80, 0xec, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40} },
-{ 0x90a8,	16,	{0xb5, 0x12, 0x8f, 0xf2, 0xe5, 0x3a, 0x60, 0x48, 0xe4, 0xf5, 0x5e, 0xaf, 0x5e, 0x74, 0x01, 0xa8} },
-{ 0x90b8,	16,	{0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x55, 0x3a, 0x60, 0x29, 0xe5, 0x5e} },
-{ 0x90c8,	16,	{0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x30, 0xe6} },
-{ 0x90d8,	16,	{0x16, 0xaf, 0x5e, 0x7d, 0x04, 0x7b, 0x80, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2} },
-{ 0x90e8,	16,	{0x80, 0xef, 0xe5, 0x5f, 0xf4, 0x52, 0x3a, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0xbb} },
-{ 0x90f8,	16,	{0x90, 0x02, 0x9e, 0xe0, 0x60, 0x03, 0x02, 0x91, 0xc5, 0x74, 0x19, 0xf0, 0x7f, 0x02, 0x12, 0x81} },
-{ 0x9108,	16,	{0x11, 0x8e, 0x61, 0x8f, 0x62, 0xc3, 0xe5, 0x61, 0x64, 0x80, 0x94, 0x80, 0x40, 0xee, 0x90, 0x01} },
-{ 0x9118,	16,	{0x5b, 0xe0, 0x65, 0x62, 0xf0, 0x60, 0x37, 0xe4, 0xf5, 0x5e, 0xaf, 0x5e, 0x74, 0x01, 0xa8, 0x07} },
-{ 0x9128,	16,	{0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x90, 0x01, 0x5b, 0xe0, 0x55, 0x5f, 0x60} },
-{ 0x9138,	16,	{0x14, 0xaf, 0x5e, 0x7d, 0x08, 0xe5, 0x5f, 0x55, 0x62, 0xfb, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05} },
-{ 0x9148,	16,	{0x12, 0x8f, 0xf2, 0x80, 0xec, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0xcc, 0x90, 0x01} },
-{ 0x9158,	16,	{0x5b, 0xe5, 0x62, 0xf0, 0xe4, 0xf5, 0x5e, 0xc2, 0xaf, 0x74, 0x32, 0x25, 0x5e, 0xf8, 0xe6, 0xf5} },
-{ 0x9168,	16,	{0x5f, 0xe4, 0xf6, 0xd2, 0xaf, 0x53, 0x5f, 0x1e, 0xe5, 0x5f, 0x60, 0x11, 0xaf, 0x5e, 0x7d, 0x02} },
-{ 0x9178,	16,	{0xab, 0x5f, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2, 0x80, 0xef, 0x74, 0x2c, 0x25} },
-{ 0x9188,	16,	{0x5e, 0xf8, 0xe6, 0xf5, 0x5f, 0x74, 0x9a, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
-{ 0x9198,	16,	{0xe0, 0x65, 0x5f, 0x60, 0x11, 0xaf, 0x5e, 0x7d, 0x04, 0xab, 0x5f, 0x12, 0x8f, 0x20, 0xef, 0x70} },
-{ 0x91a8,	16,	{0x05, 0x12, 0x8f, 0xf2, 0x80, 0xef, 0x74, 0x9a, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
-{ 0x91b8,	16,	{0x83, 0xe5, 0x5f, 0xf0, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0x9a, 0x12, 0x8f, 0xf2} },
-{ 0x91c8,	1,	{0x22} },
-{ 0x91c9,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x6e, 0x02, 0x92, 0x10} },
-{ 0x91d5,	16,	{0x02, 0x05, 0x28, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
-{ 0x91e5,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
-{ 0x91f5,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
-{ 0x9205,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x92, 0x55, 0xe4, 0x7e} },
-{ 0x9215,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
-{ 0x9225,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
-{ 0x9235,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
-{ 0x9245,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
-{ 0x9255,	16,	{0x60, 0x24, 0x02, 0x28, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x81, 0x82, 0x84, 0x88} },
-{ 0x9265,	16,	{0x90, 0xa0, 0xc0, 0xc1, 0xc2, 0xc4, 0xc8, 0xd0, 0xe0, 0xe1, 0xe2, 0xe4, 0xe8, 0xf0, 0xf1, 0xf2} },
-{ 0x9275,	8,	{0xf4, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xfe, 0xff} },
-{ 0x927d,	1,	{0x00} },
-{ 0x927e,	11,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18} },
-{ 0x9289,	16,	{0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xfe, 0x30, 0xe0, 0x05, 0x90, 0x20, 0x02, 0xe0, 0xff, 0xee} },
-{ 0x9299,	16,	{0x30, 0xe1, 0x05, 0x90, 0x20, 0x0a, 0xe0, 0xff, 0xee, 0x30, 0xe2, 0x05, 0x90, 0x20, 0x12, 0xe0} },
-{ 0x92a9,	16,	{0xff, 0xee, 0x30, 0xe3, 0x05, 0x90, 0x20, 0x1a, 0xe0, 0xff, 0x90, 0x01, 0x62, 0xe0, 0xb5, 0x1e} },
-{ 0x92b9,	10,	{0x04, 0xe4, 0xf0, 0x80, 0x05, 0x90, 0x01, 0x62, 0xee, 0xf0} },
-{ 0x92c3,	9,	{0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x92cc,	2,	{0xa9, 0x03} },
-{ 0x92ce,	16,	{0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xe5} },
-{ 0x92de,	16,	{0x6c, 0x45, 0x6d, 0xf5, 0x6e, 0xe9, 0x60, 0x14, 0x8a, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82} },
-{ 0x92ee,	16,	{0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x4d, 0xf0, 0xe4, 0xfe, 0x80, 0x13, 0xeb, 0x24, 0x04, 0xf5} },
-{ 0x92fe,	16,	{0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0xff, 0xed, 0xf4, 0xfc, 0xef, 0x5c, 0xf0, 0xae, 0x6e, 0xeb} },
-{ 0x930e,	16,	{0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0x55, 0x6e, 0xfc, 0xb5, 0x06, 0x03, 0xaf} },
-{ 0x931e,	16,	{0x05, 0x22, 0xe5, 0x6c, 0x5c, 0xfe, 0xe5, 0x6d, 0x5c, 0xfd, 0xe9, 0x60, 0x16, 0xee, 0x70, 0x04} },
-{ 0x932e,	16,	{0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xae, 0x07, 0xed, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f} },
-{ 0x933e,	16,	{0x00, 0xad, 0x07, 0xee, 0x60, 0x03, 0xaf, 0x6c, 0x22, 0xed, 0x60, 0x03, 0xaf, 0x6d, 0x22, 0x7f} },
-{ 0x934e,	1,	{0x00} },
-{ 0x934f,	1,	{0x22} },
-{ 0x9350,	16,	{0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xf5, 0x66, 0xe4, 0x3e, 0xf5, 0x65, 0x75, 0x63, 0x02} },
-{ 0x9360,	16,	{0x75, 0x64, 0x4e, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x0f, 0xf0, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83} },
-{ 0x9370,	16,	{0xe0, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xf0, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83, 0xa3, 0xe0} },
-{ 0x9380,	16,	{0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xf0, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3} },
-{ 0x9390,	16,	{0x74, 0xff, 0xf0, 0xe5, 0x66, 0x24, 0x03, 0xf5, 0x68, 0xe4, 0x35, 0x65, 0xf5, 0x67, 0x85, 0x64} },
-{ 0x93a0,	16,	{0x82, 0x85, 0x63, 0x83, 0xe0, 0x14, 0xb4, 0x0b, 0x00, 0x40, 0x03, 0x02, 0x98, 0x43, 0x90, 0x93} },
-{ 0x93b0,	16,	{0xb5, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x93, 0xd6, 0x02, 0x94, 0x7c, 0x02, 0x95, 0xba, 0x02, 0x95} },
-{ 0x93c0,	16,	{0xda, 0x02, 0x95, 0xda, 0x02, 0x96, 0x7f, 0x02, 0x96, 0xbd, 0x02, 0x96, 0xe4, 0x02, 0x97, 0xa6} },
-{ 0x93d0,	16,	{0x02, 0x97, 0xda, 0x02, 0x98, 0x0b, 0xe4, 0xf5, 0x5e, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24} },
-{ 0x93e0,	16,	{0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xe4, 0xff, 0xe4, 0xfe} },
-{ 0x93f0,	16,	{0xef, 0x60, 0x10, 0x74, 0x28, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf4, 0xf5} },
-{ 0x9400,	16,	{0x5f, 0x80, 0x0d, 0x74, 0x28, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf5, 0x5f} },
-{ 0x9410,	16,	{0xe5, 0x62, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83, 0xe5, 0x5f, 0xf0, 0xe0, 0xf5} },
-{ 0x9420,	16,	{0x60, 0x65, 0x5f, 0x60, 0x3d, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5} },
-{ 0x9430,	16,	{0x5e, 0x04, 0xfd, 0x05, 0x68, 0xe5, 0x68, 0xaa, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82} },
-{ 0x9440,	16,	{0x8a, 0x83, 0xed, 0xf0, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5} },
-{ 0x9450,	16,	{0x82, 0x8c, 0x83, 0xe5, 0x5f, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0xe5, 0x60, 0xf0, 0x02} },
-{ 0x9460,	16,	{0x98, 0x4e, 0x0e, 0xee, 0x64, 0x24, 0x70, 0x88, 0x0f, 0xef, 0x64, 0x02, 0x70, 0x80, 0x05, 0x5e} },
-{ 0x9470,	16,	{0xe5, 0x5e, 0x64, 0x04, 0x60, 0x03, 0x02, 0x93, 0xd9, 0x02, 0x98, 0x4e, 0x7e, 0x20, 0x7f, 0x00} },
-{ 0x9480,	16,	{0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe4, 0xf5, 0x5e, 0xaf, 0x62, 0xae, 0x61, 0xe4, 0xfd, 0x12} },
-{ 0x9490,	16,	{0x81, 0xe0, 0x74, 0x08, 0x25, 0x62, 0xf5, 0x62, 0xe4, 0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5} },
-{ 0x94a0,	16,	{0x5e, 0xd3, 0x94, 0x03, 0x40, 0xe3, 0x90, 0x00, 0x04, 0x74, 0x92, 0xf0, 0xa3, 0x74, 0x7e, 0xf0} },
-{ 0x94b0,	16,	{0xe4, 0xf5, 0x60, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xf5, 0x5e, 0xaf} },
-{ 0x94c0,	16,	{0x5e, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x90, 0x01} },
-{ 0x94d0,	16,	{0x62, 0xf0, 0x90, 0x01, 0x5e, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x85, 0x62, 0x82, 0x85, 0x61} },
-{ 0x94e0,	16,	{0x83, 0xa3, 0x74, 0x02, 0xf0, 0x90, 0x01, 0x62, 0xe0, 0x65, 0x5f, 0x70, 0x39, 0x90, 0x01, 0x5e} },
-{ 0x94f0,	16,	{0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xee, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xf0} },
-{ 0x9500,	16,	{0xe5, 0x5e, 0x04, 0xff, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5} },
-{ 0x9510,	16,	{0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0x74, 0xff, 0xf0, 0xe4, 0x90} },
-{ 0x9520,	16,	{0x01, 0x62, 0xf0, 0x75, 0x60, 0xff, 0x90, 0x01, 0x62, 0xe0, 0xff, 0x60, 0x3c, 0x85, 0x66, 0x82} },
-{ 0x9530,	16,	{0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5e, 0x04, 0xfe, 0x05, 0x68, 0xe5, 0x68, 0xac} },
-{ 0x9540,	16,	{0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xee, 0xf0, 0x05, 0x68, 0xe5, 0x68} },
-{ 0x9550,	16,	{0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82} },
-{ 0x9560,	16,	{0x85, 0x67, 0x83, 0xe5, 0x5f, 0xf0, 0x75, 0x60, 0xff, 0xe5, 0x60, 0x70, 0x16, 0x74, 0x08, 0x25} },
-{ 0x9570,	16,	{0x62, 0xf5, 0x62, 0xe4, 0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5, 0x5e, 0x64, 0x04, 0x60, 0x03} },
-{ 0x9580,	16,	{0x02, 0x94, 0xbf, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe4, 0xf5, 0x5e} },
-{ 0x9590,	16,	{0xaf, 0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0x74, 0x08, 0x25, 0x62, 0xf5, 0x62, 0xe4} },
-{ 0x95a0,	16,	{0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x03, 0x40, 0xe3, 0x90, 0x00, 0x04} },
-{ 0x95b0,	16,	{0x74, 0x13, 0xf0, 0xa3, 0x74, 0x12, 0xf0, 0x02, 0x98, 0x4e, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83} },
-{ 0x95c0,	16,	{0xa3, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x90} },
-{ 0x95d0,	16,	{0x02, 0x95, 0xf0, 0x90, 0x01, 0x62, 0xf0, 0x02, 0x98, 0x4e, 0x90, 0x01, 0x5e, 0x74, 0x03, 0xf0} },
-{ 0x95e0,	16,	{0xa3, 0x74, 0xe8, 0xf0, 0xe4, 0xf5, 0x60, 0x90, 0x02, 0x95, 0xe0, 0xff, 0x90, 0x01, 0x62, 0xe0} },
-{ 0x95f0,	16,	{0xb5, 0x07, 0x1e, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xea, 0x85, 0x66, 0x82} },
-{ 0x9600,	16,	{0x85, 0x65, 0x83, 0xa3, 0xa3, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0x74, 0xff, 0xf0, 0xf5} },
-{ 0x9610,	16,	{0x60, 0xe5, 0x60, 0x60, 0x03, 0x02, 0x98, 0x4e, 0x90, 0x01, 0x5e, 0xf0, 0xa3, 0x74, 0x96, 0xf0} },
-{ 0x9620,	16,	{0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xf6, 0x7f, 0x02, 0x12, 0x81, 0x11, 0xc3} },
-{ 0x9630,	16,	{0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xef, 0x54, 0x0f, 0xf5, 0x60, 0x90, 0x02, 0x95, 0xe0} },
-{ 0x9640,	16,	{0x55, 0x60, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f, 0x5f, 0x85, 0x64, 0x82, 0x85} },
-{ 0x9650,	16,	{0x63, 0x83, 0xe0, 0xb4, 0x05, 0x0c, 0xe5, 0x5f, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00} },
-{ 0x9660,	16,	{0x8f, 0x5f, 0xe5, 0x5f, 0x70, 0x03, 0x02, 0x98, 0x4e, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3} },
-{ 0x9670,	16,	{0xa3, 0xe4, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0xe5, 0x60, 0xf0, 0x02, 0x98, 0x4e, 0x7e} },
-{ 0x9680,	16,	{0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xaf, 0x62, 0xae, 0x61, 0xe4, 0xfd, 0x12} },
-{ 0x9690,	16,	{0x81, 0xe0, 0x85, 0x62, 0x82, 0x85, 0x61, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
-{ 0x96a0,	16,	{0x62, 0x82, 0x85, 0x61, 0x83, 0x74, 0x01, 0xf0, 0xa3, 0xe4, 0xf0, 0x85, 0x62, 0x82, 0x85, 0x61} },
-{ 0x96b0,	16,	{0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xd2, 0x04, 0x02, 0x98, 0x4e, 0xc2, 0x04, 0x7e} },
-{ 0x96c0,	16,	{0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe5, 0x62, 0x24, 0x05, 0xf5, 0x82, 0xe4} },
-{ 0x96d0,	16,	{0x35, 0x61, 0xf5, 0x83, 0xe0, 0x30, 0xe6, 0xf1, 0xaf, 0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81} },
-{ 0x96e0,	16,	{0xe0, 0x02, 0x98, 0x4e, 0xe4, 0xf5, 0x60, 0xf5, 0x5e, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24} },
-{ 0x96f0,	16,	{0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xfe, 0xe4, 0xfd, 0x12} },
-{ 0x9700,	16,	{0x81, 0xe0, 0xe5, 0x62, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83, 0xe0, 0x54, 0xfc} },
-{ 0x9710,	16,	{0xf0, 0xaf, 0x5e, 0x7d, 0x01, 0x7b, 0x01, 0x75, 0x6c, 0x80, 0x75, 0x6d, 0x40, 0x12, 0x92, 0xcc} },
-{ 0x9720,	16,	{0x8f, 0x60, 0xe5, 0x60, 0x70, 0x11, 0xaf, 0x5e, 0x7d, 0x02, 0x7b, 0x01, 0x75, 0x6c, 0x10, 0x75} },
-{ 0x9730,	16,	{0x6d, 0x20, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xe5, 0x60, 0x70, 0x10, 0xaf, 0x5e, 0x7d, 0x01, 0xfb} },
-{ 0x9740,	16,	{0x75, 0x6c, 0x80, 0x75, 0x6d, 0x40, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xe5, 0x60, 0x70, 0x10, 0xaf} },
-{ 0x9750,	16,	{0x5e, 0x7d, 0x02, 0xfb, 0x75, 0x6c, 0x10, 0x75, 0x6d, 0x20, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xaf} },
-{ 0x9760,	16,	{0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0xe5, 0x60, 0x60, 0x2b, 0x85, 0x66, 0x82, 0x85} },
-{ 0x9770,	16,	{0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5e, 0x04, 0xff, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67} },
-{ 0x9780,	16,	{0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67} },
-{ 0x9790,	16,	{0x83, 0xe5, 0x60, 0xf0, 0x02, 0x98, 0x4e, 0x05, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x03, 0x50, 0x03} },
-{ 0x97a0,	16,	{0x02, 0x96, 0xe9, 0x02, 0x98, 0x4e, 0xe4, 0x90, 0x02, 0xd3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x97b0,	16,	{0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x98, 0xf0, 0xa3, 0x74, 0x6d, 0xf0, 0x7e} },
-{ 0x97c0,	16,	{0x02, 0x7f, 0xd3, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08, 0x70, 0x03, 0x02, 0x98, 0x4e, 0x85, 0x66} },
-{ 0x97d0,	16,	{0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0x80, 0x74, 0xe4, 0x90, 0x02, 0xd3, 0xf0, 0xa3} },
-{ 0x97e0,	16,	{0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0xe5, 0x67, 0xf0, 0xa3} },
-{ 0x97f0,	16,	{0xe5, 0x68, 0xf0, 0x7e, 0x02, 0x7f, 0xd3, 0x12, 0x19, 0xc1, 0xef, 0x64, 0x08, 0x60, 0x4f, 0x85} },
-{ 0x9800,	16,	{0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0x80, 0x43, 0xe4, 0x90, 0x02, 0xd3, 0xf0} },
-{ 0x9810,	16,	{0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xe5, 0x64, 0x24, 0x02} },
-{ 0x9820,	16,	{0x90, 0x02, 0xda, 0xf0, 0xe4, 0x35, 0x63, 0x90, 0x02, 0xd9, 0xf0, 0x7e, 0x02, 0x7f, 0xd3, 0x12} },
-{ 0x9830,	16,	{0x80, 0x00, 0xef, 0x64, 0x08, 0x60, 0x17, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4} },
-{ 0x9840,	16,	{0xf0, 0x80, 0x0b, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0x74, 0x01, 0xf0, 0x90, 0x01} },
-{ 0x9850,	16,	{0x5e, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70} },
-{ 0x9860,	12,	{0xf6, 0x90, 0x7f, 0xc3, 0x74, 0x24, 0xf0, 0xe4, 0x90, 0x02, 0x4d, 0xf0} },
-{ 0x986c,	1,	{0x22} },
-{ 0x986d,	16,	{0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0} },
-{ 0x987d,	16,	{0xe4, 0xfd, 0x74, 0x01, 0x7e, 0x00, 0xa8, 0x05, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce} },
-{ 0x988d,	16,	{0xd8, 0xf9, 0xff, 0xe5, 0x3b, 0xfb, 0xe4, 0xef, 0x5b, 0x70, 0x03, 0x02, 0x99, 0x45, 0xed, 0x75} },
-{ 0x989d,	16,	{0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xfe, 0xf5, 0x83, 0xe5} },
-{ 0x98ad,	16,	{0x82, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x60, 0x64, 0x60, 0x60} },
-{ 0x98bd,	16,	{0x03, 0x02, 0x99, 0x45, 0xef, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0xfc, 0x74} },
-{ 0x98cd,	16,	{0x36, 0x2d, 0xf8, 0xec, 0xf6, 0x30, 0xe5, 0x70, 0x74, 0x96, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x02} },
-{ 0x98dd,	16,	{0xf5, 0x83, 0xe0, 0x60, 0x63, 0xed, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
-{ 0x98ed,	16,	{0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0, 0x8f, 0x82} },
-{ 0x98fd,	16,	{0x8e, 0x83, 0xf0, 0x74, 0x96, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x14, 0xf0} },
-{ 0x990d,	16,	{0x70, 0x36, 0xed, 0x25, 0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0} },
-{ 0x991d,	16,	{0xed, 0x25, 0xe0, 0xff, 0xc3, 0x74, 0x0c, 0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82} },
-{ 0x992d,	16,	{0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82, 0xfe, 0xed, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x993d,	16,	{0x02, 0xf5, 0x83, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x0d, 0xed, 0x64, 0x04, 0x60, 0x03, 0x02, 0x98} },
-{ 0x994d,	1,	{0x7f} },
-{ 0x994e,	1,	{0x22} },
-{ 0x994f,	16,	{0xe7, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e} },
-{ 0x995f,	16,	{0x88, 0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08} },
-{ 0x996f,	16,	{0xdf, 0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83} },
-{ 0x997f,	16,	{0xe3, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08} },
-{ 0x998f,	16,	{0xdf, 0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c} },
-{ 0x999f,	16,	{0x80, 0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10} },
-{ 0x99af,	16,	{0x80, 0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33} },
-{ 0x99bf,	16,	{0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83} },
-{ 0x99cf,	16,	{0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80} },
-{ 0x99df,	16,	{0x0d, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0} },
-{ 0x99ef,	16,	{0xed, 0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc} },
-{ 0x99ff,	16,	{0xc5, 0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde} },
-{ 0x9a0f,	16,	{0xe8, 0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc} },
-{ 0x9a1f,	16,	{0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xc2, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4} },
-{ 0x9a2f,	16,	{0x04, 0x00, 0x50, 0xb8, 0x23, 0x23, 0x45, 0x82, 0xf5, 0x82, 0xef, 0x4e, 0x60, 0xae, 0xef, 0x60} },
-{ 0x9a3f,	9,	{0x01, 0x0e, 0xe5, 0x82, 0x23, 0x90, 0x99, 0x9f, 0x73} },
-{ 0x9a48,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
-{ 0x9a58,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
-{ 0x9a61,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
-{ 0x9a71,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
-{ 0x9a81,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
-{ 0x9a8e,	16,	{0xc5, 0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02} },
-{ 0x9a9e,	6,	{0x15, 0x83, 0xe0, 0x38, 0xf0, 0x22} },
-{ 0x9aa4,	16,	{0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83} },
-{ 0x9ab4,	6,	{0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22} },
-{ 0x9aba,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
-{ 0x9aca,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
-{ 0x9ada,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
-{ 0x9aea,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
-{ 0x9af2,	16,	{0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc} },
-{ 0x9b02,	16,	{0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40} },
-{ 0x9b12,	16,	{0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6} },
-{ 0x9b22,	16,	{0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9} },
-{ 0x9b32,	16,	{0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb} },
-{ 0x9b42,	16,	{0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb} },
-{ 0x9b52,	16,	{0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9} },
-{ 0x9b62,	16,	{0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc} },
-{ 0x9b72,	16,	{0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a} },
-{ 0x9b82,	16,	{0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f} },
-{ 0x9b92,	16,	{0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07} },
-{ 0x9ba2,	16,	{0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8} },
-{ 0x9bb2,	14,	{0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22} },
-{ 0x9bc0,	16,	{0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
-{ 0x9bd0,	1,	{0x22} },
-{ 0x9bd1,	16,	{0xe8, 0x60, 0x0f, 0xec, 0xc3, 0x13, 0xfc, 0xed, 0x13, 0xfd, 0xee, 0x13, 0xfe, 0xef, 0x13, 0xff} },
-{ 0x9be1,	3,	{0xd8, 0xf1, 0x22} },
-{ 0x9be4,	16,	{0x08, 0x08, 0x08, 0xe6, 0xcf, 0x2f, 0xf6, 0x18, 0xe6, 0xce, 0x3e, 0xf6, 0x18, 0xe6, 0xcd, 0x3d} },
-{ 0x9bf4,	7,	{0xf6, 0x18, 0xe6, 0xcc, 0x3c, 0xf6, 0x22} },
-{ 0x9bfb,	12,	{0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
-{ 0x9c07,	16,	{0xa8, 0x82, 0x85, 0x83, 0xf0, 0xd0, 0x83, 0xd0, 0x82, 0x12, 0x9c, 0x1e, 0x12, 0x9c, 0x1e, 0x12} },
-{ 0x9c17,	16,	{0x9c, 0x1e, 0x12, 0x9c, 0x1e, 0xe4, 0x73, 0xe4, 0x93, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83} },
-{ 0x9c27,	16,	{0xc8, 0xc5, 0x82, 0xc8, 0xf0, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83, 0xc8, 0xc5, 0x82, 0xc8} },
-{ 0x9c37,	1,	{0x22} },
-{ 0xffff,	0,	{0x00} }
-};
-
-#ifdef DEBUG
-static const struct whiteheat_hex_record whiteheat_loader[] = {
-{ 0x0000,	3,	{0x02, 0x09, 0x8d} },
-{ 0x0033,	3,	{0x02, 0x0e, 0x70} },
-{ 0x0043,	3,	{0x02, 0x0b, 0x00} },
-{ 0x004b,	3,	{0x02, 0x05, 0xb3} },
-{ 0x0100,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x54, 0x10, 0xff, 0xc4, 0x54, 0x0f, 0x44, 0x50, 0xf5, 0x0f, 0x13, 0xe4} },
-{ 0x0110,	16,	{0x33, 0xf5, 0x11, 0x90, 0x7f, 0xe9, 0xe0, 0x24, 0x5e, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x03} },
-{ 0x0120,	16,	{0x7c, 0x90, 0x01, 0x28, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x01, 0xbc, 0x02, 0x01, 0xbc, 0x02, 0x01} },
-{ 0x0130,	16,	{0x91, 0x02, 0x01, 0x3d, 0x02, 0x01, 0x53, 0x02, 0x01, 0x6f, 0x02, 0x01, 0x9a, 0x90, 0x7f, 0x00} },
-{ 0x0140,	16,	{0xe5, 0x11, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
-{ 0x0150,	16,	{0x02, 0x03, 0x7c, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x90, 0x7f, 0x00, 0xf0, 0x90} },
-{ 0x0160,	16,	{0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03, 0x7c, 0x12} },
-{ 0x0170,	16,	{0x0a, 0x89, 0x50, 0x07, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0x80, 0x06, 0x90, 0x7f, 0x00, 0x74, 0x0f} },
-{ 0x0180,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03} },
-{ 0x0190,	16,	{0x7c, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0f, 0x02, 0x03, 0x7c, 0x90, 0x7f, 0x00, 0x74, 0x07, 0xf0} },
-{ 0x01a0,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xe8, 0x7e} },
-{ 0x01b0,	16,	{0x03, 0x12, 0x0d, 0xd5, 0xd2, 0x06, 0x12, 0x0d, 0x0d, 0x02, 0x03, 0x7c, 0x90, 0x7f, 0xea, 0xe0} },
-{ 0x01c0,	16,	{0x75, 0x29, 0x00, 0xf5, 0x2a, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x29, 0x90, 0x7f, 0xee, 0xe0} },
-{ 0x01d0,	16,	{0x75, 0x2b, 0x00, 0xf5, 0x2c, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x2b, 0x90, 0x7f, 0xe8, 0xe0} },
-{ 0x01e0,	16,	{0x64, 0xc0, 0x60, 0x03, 0x02, 0x02, 0xc9, 0xe5, 0x2c, 0x45, 0x2b, 0x70, 0x03, 0x02, 0x03, 0x7c} },
-{ 0x01f0,	16,	{0xc3, 0xe5, 0x2c, 0x94, 0x40, 0xe5, 0x2b, 0x94, 0x00, 0x50, 0x08, 0x85, 0x2b, 0x2d, 0x85, 0x2c} },
-{ 0x0200,	16,	{0x2e, 0x80, 0x06, 0x75, 0x2d, 0x00, 0x75, 0x2e, 0x40, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70} },
-{ 0x0210,	16,	{0x34, 0xf5, 0x31, 0xf5, 0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5, 0x31, 0x95, 0x2d, 0x50, 0x5c} },
-{ 0x0220,	16,	{0xe5, 0x2a, 0x25, 0x32, 0xf5, 0x82, 0xe5, 0x31, 0x35, 0x29, 0xf5, 0x83, 0xe0, 0xff, 0x74, 0x00} },
-{ 0x0230,	16,	{0x25, 0x32, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70} },
-{ 0x0240,	16,	{0x02, 0x05, 0x31, 0x80, 0xd0, 0xe4, 0xf5, 0x31, 0xf5, 0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5} },
-{ 0x0250,	16,	{0x31, 0x95, 0x2d, 0x50, 0x18, 0x74, 0x00, 0x25, 0x32, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83} },
-{ 0x0260,	16,	{0x74, 0xcd, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70, 0x02, 0x05, 0x31, 0x80, 0xdd, 0xaf, 0x2a, 0xae} },
-{ 0x0270,	16,	{0x29, 0xad, 0x2e, 0x7a, 0x7f, 0x79, 0x00, 0x7b, 0x00, 0x12, 0x0b, 0xf4, 0x90, 0x7f, 0xb5, 0xe5} },
-{ 0x0280,	16,	{0x2e, 0xf0, 0xe5, 0x2e, 0x25, 0x2a, 0xf5, 0x2a, 0xe5, 0x2d, 0x35, 0x29, 0xf5, 0x29, 0xc3, 0xe5} },
-{ 0x0290,	16,	{0x2c, 0x95, 0x2e, 0xf5, 0x2c, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0x90, 0x7f, 0x92, 0xe0, 0xff} },
-{ 0x02a0,	16,	{0xc4, 0x54, 0x0f, 0x75, 0x2f, 0x00, 0xf5, 0x30, 0xd3, 0x94, 0x00, 0xe5, 0x2f, 0x94, 0x00, 0x50} },
-{ 0x02b0,	16,	{0x0c, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe1, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xb4} },
-{ 0x02c0,	16,	{0xe0, 0x20, 0xe2, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xe8, 0xe0, 0x64, 0x40, 0x60} },
-{ 0x02d0,	16,	{0x03, 0x02, 0x03, 0x7c, 0xe5, 0x2c, 0x45, 0x2b, 0x70, 0x03, 0x02, 0x03, 0x7c, 0xe4, 0x90, 0x7f} },
-{ 0x02e0,	16,	{0xc5, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x75, 0x2f, 0x00, 0xf5, 0x30, 0xd3} },
-{ 0x02f0,	16,	{0x94, 0x00, 0xe5, 0x2f, 0x94, 0x00, 0x50, 0x09, 0x90, 0x7f, 0xc4, 0xe0, 0x30, 0xe1, 0x09, 0x80} },
-{ 0x0300,	16,	{0xf7, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe3, 0xf9, 0x90, 0x7f, 0xc5, 0xe0, 0x75, 0x2d, 0x00, 0xf5} },
-{ 0x0310,	16,	{0x2e, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70, 0x38, 0x90, 0x20, 0x6b, 0xf0, 0xf5, 0x31, 0xf5} },
-{ 0x0320,	16,	{0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5, 0x31, 0x95, 0x2d, 0x50, 0x34, 0x74, 0xc0, 0x25, 0x32} },
-{ 0x0330,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x2a, 0x25, 0x32, 0xf5, 0x82, 0xe5} },
-{ 0x0340,	16,	{0x31, 0x35, 0x29, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70, 0x02, 0x05, 0x31, 0x80} },
-{ 0x0350,	16,	{0xd0, 0xaf, 0x2a, 0xae, 0x29, 0xad, 0x2e, 0x7a, 0x7e, 0x79, 0xc0, 0x7b, 0xc0, 0x12, 0x0c, 0x80} },
-{ 0x0360,	16,	{0xe5, 0x2e, 0x25, 0x2a, 0xf5, 0x2a, 0xe5, 0x2d, 0x35, 0x29, 0xf5, 0x29, 0xc3, 0xe5, 0x2c, 0x95} },
-{ 0x0370,	13,	{0x2e, 0xf5, 0x2c, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0x02, 0x02, 0xd4, 0xc3} },
-{ 0x037d,	1,	{0x22} },
-{ 0x037e,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x56, 0x14, 0x70, 0x03, 0x02, 0x04, 0xd2, 0x24} },
-{ 0x038e,	16,	{0xfe, 0x70, 0x03, 0x02, 0x05, 0x46, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x50, 0x14, 0x70, 0x03} },
-{ 0x039e,	16,	{0x02, 0x04, 0x4a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3e, 0x14, 0x70, 0x03, 0x02, 0x04, 0x44, 0x24} },
-{ 0x03ae,	16,	{0x05, 0x60, 0x03, 0x02, 0x05, 0x9a, 0x12, 0x0e, 0x7b, 0x40, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f} },
-{ 0x03be,	16,	{0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02, 0x70, 0x69, 0x74, 0x11, 0x90} },
-{ 0x03ce,	16,	{0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0} },
-{ 0x03de,	16,	{0xff, 0x12, 0x0b, 0x58, 0x8b, 0x26, 0x8a, 0x27, 0x89, 0x28, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02} },
-{ 0x03ee,	16,	{0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90} },
-{ 0x03fe,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0c} },
-{ 0x040e,	16,	{0x3f, 0x8b, 0x26, 0x8a, 0x27, 0x89, 0x28, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f} },
-{ 0x041e,	16,	{0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0} },
-{ 0x042e,	16,	{0x44, 0x01, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xab} },
-{ 0x043e,	16,	{0x12, 0x0e, 0x52, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x60, 0x02, 0x05, 0xab, 0x12, 0x0a, 0xf7, 0x02} },
-{ 0x044e,	16,	{0x05, 0xab, 0x12, 0x08, 0xf1, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x7d, 0x40, 0x03, 0x02, 0x05, 0xab} },
-{ 0x045e,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
-{ 0x046e,	16,	{0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x02, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
-{ 0x047e,	16,	{0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0xe4, 0x90, 0x7f, 0x00} },
-{ 0x048e,	16,	{0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xec, 0xe0} },
-{ 0x049e,	16,	{0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
-{ 0x04ae,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
-{ 0x04be,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
-{ 0x04ce,	16,	{0xf0, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x7f, 0x40, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xe8, 0xe0} },
-{ 0x04de,	16,	{0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0, 0xb4} },
-{ 0x04ee,	16,	{0x01, 0x05, 0xc2, 0x00, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05} },
-{ 0x04fe,	16,	{0xab, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4} },
-{ 0x050e,	16,	{0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f} },
-{ 0x051e,	16,	{0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f} },
-{ 0x052e,	16,	{0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x6e, 0x90} },
-{ 0x053e,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x65, 0x12, 0x0e, 0x81, 0x50, 0x60, 0x90, 0x7f, 0xe8} },
-{ 0x054e,	16,	{0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x54, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
-{ 0x055e,	16,	{0xd2, 0x00, 0x80, 0x49, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x40, 0x90, 0x7f, 0xea} },
-{ 0x056e,	16,	{0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
-{ 0x057e,	16,	{0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
-{ 0x058e,	16,	{0xf0, 0x80, 0x1a, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xe4, 0x90, 0x20, 0x6a} },
-{ 0x059e,	16,	{0xf0, 0x12, 0x01, 0x00, 0x50, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4} },
-{ 0x05ae,	4,	{0xe0, 0x44, 0x02, 0xf0} },
-{ 0x05b2,	1,	{0x22} },
-{ 0x05b3,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
-{ 0x05c3,	16,	{0xd0, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x06, 0xc0, 0x07, 0x90, 0x7f, 0xa5} },
-{ 0x05d3,	16,	{0xe0, 0x30, 0xe2, 0x06, 0x75, 0x0d, 0x06, 0x02, 0x06, 0x7f, 0x90, 0x7f, 0xa5, 0xe0, 0x20, 0xe1} },
-{ 0x05e3,	16,	{0x0c, 0xe5, 0x0d, 0x64, 0x02, 0x60, 0x06, 0x75, 0x0d, 0x07, 0x02, 0x06, 0x7f, 0xaf, 0x0d, 0xef} },
-{ 0x05f3,	16,	{0x24, 0xfe, 0x60, 0x48, 0x14, 0x60, 0x2c, 0x24, 0xfe, 0x60, 0x77, 0x24, 0x04, 0x60, 0x03, 0x02} },
-{ 0x0603,	16,	{0x06, 0x7f, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xaf, 0x0c, 0x05, 0x0c, 0x8f, 0x82, 0x75, 0x83} },
-{ 0x0613,	16,	{0x00, 0x12, 0x07, 0x85, 0x90, 0x7f, 0xa6, 0xf0, 0xe5, 0x0c, 0x65, 0x08, 0x70, 0x5e, 0x75, 0x0d} },
-{ 0x0623,	16,	{0x05, 0x80, 0x59, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e} },
-{ 0x0633,	16,	{0x82, 0x75, 0x83, 0x00, 0x12, 0x07, 0xb2, 0x75, 0x0d, 0x02, 0x80, 0x40, 0xe5, 0x08, 0x24, 0xfe} },
-{ 0x0643,	16,	{0xb5, 0x0c, 0x07, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0xe5, 0x08, 0x14, 0xb5, 0x0c, 0x0a} },
-{ 0x0653,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09} },
-{ 0x0663,	16,	{0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e, 0x82, 0x75, 0x83, 0x00, 0x12, 0x07, 0xb2, 0x05, 0x0c} },
-{ 0x0673,	16,	{0x80, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x53, 0x91, 0xdf, 0xd0} },
-{ 0x0683,	16,	{0x07, 0xd0, 0x06, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x86, 0xd0} },
-{ 0x0693,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x069d,	16,	{0xc2, 0x04, 0xd2, 0x05, 0xe4, 0xf5, 0x25, 0xc2, 0x03, 0xc2, 0x00, 0xc2, 0x02, 0xc2, 0x01, 0x12} },
-{ 0x06ad,	16,	{0x0e, 0x74, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9} },
-{ 0x06bd,	16,	{0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0x90} },
-{ 0x06cd,	16,	{0x7f, 0x93, 0x74, 0x30, 0xf0, 0x12, 0x0a, 0x19, 0x75, 0x24, 0x48, 0x75, 0x23, 0x92, 0x75, 0x22} },
-{ 0x06dd,	16,	{0x00, 0x75, 0x21, 0x00, 0xe4, 0xff, 0xfe, 0x7e, 0x05, 0x90, 0x20, 0x68, 0x74, 0x01, 0xf0, 0xa3} },
-{ 0x06ed,	16,	{0xde, 0xfc, 0x7e, 0x00, 0x7f, 0x05, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae} },
-{ 0x06fd,	16,	{0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0x12, 0x0e, 0x68, 0x30, 0x01, 0x0a, 0xe4, 0x90, 0x20, 0x69} },
-{ 0x070d,	16,	{0xf0, 0x12, 0x03, 0x7e, 0xc2, 0x01, 0x30, 0x04, 0x1a, 0x12, 0x0e, 0x77, 0x50, 0x13, 0x12, 0x09} },
-{ 0x071d,	16,	{0x00, 0x30, 0x00, 0x07, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0xf3, 0x12, 0x0d, 0x8b, 0x12, 0x0e} },
-{ 0x072d,	16,	{0x79, 0xc2, 0x03, 0x7f, 0xff, 0x7e, 0xff, 0x7d, 0xff, 0x7c, 0xff, 0x78, 0x21, 0x12, 0x08, 0x1d} },
-{ 0x073d,	16,	{0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x08, 0x0c, 0x70, 0x1b, 0x75, 0x24} },
-{ 0x074d,	16,	{0x48, 0x75, 0x23, 0x92, 0xf5, 0x22, 0xf5, 0x21, 0x63, 0x25, 0xff, 0x90, 0x20, 0x68, 0xe5, 0x25} },
-{ 0x075d,	14,	{0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0x12, 0x08, 0xff, 0x80, 0x9b} },
-{ 0x076b,	1,	{0x22} },
-{ 0x076c,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
-{ 0x077c,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
-{ 0x0785,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
-{ 0x0795,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
-{ 0x07a5,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
-{ 0x07b2,	16,	{0xf8, 0xbb, 0x01, 0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0} },
-{ 0x07c2,	16,	{0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8} },
-{ 0x07d2,	2,	{0xf2, 0x22} },
-{ 0x07d4,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
-{ 0x07e4,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
-{ 0x07f4,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
-{ 0x0804,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
-{ 0x080c,	16,	{0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
-{ 0x081c,	1,	{0x22} },
-{ 0x081d,	16,	{0x08, 0x08, 0x08, 0xe6, 0x2f, 0xff, 0xf6, 0x18, 0xe6, 0x3e, 0xfe, 0xf6, 0x18, 0xe6, 0x3d, 0xfd} },
-{ 0x082d,	7,	{0xf6, 0x18, 0xe6, 0x3c, 0xfc, 0xf6, 0x22} },
-{ 0x0834,	4,	{0x8c, 0x34, 0x8d, 0x35} },
-{ 0x0838,	16,	{0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0xe4, 0xf5, 0x36, 0xf5, 0x37, 0xc3, 0xe5, 0x37, 0x95} },
-{ 0x0848,	16,	{0x35, 0xe5, 0x36, 0x95, 0x34, 0x50, 0x69, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5} },
-{ 0x0858,	16,	{0x83, 0x74, 0xff, 0xf0, 0xf4, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36} },
-{ 0x0868,	16,	{0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36} },
-{ 0x0878,	16,	{0x3e, 0xf5, 0x83, 0x74, 0xaa, 0xf0, 0x64, 0xaa, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5} },
-{ 0x0888,	16,	{0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0x74, 0x55, 0xf0, 0x64, 0x55, 0x60, 0x02, 0xc3, 0x22, 0xad} },
-{ 0x0898,	16,	{0x37, 0xe5, 0x37, 0x2f, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xed, 0xf0, 0xfc, 0xac, 0x05} },
-{ 0x08a8,	16,	{0xed, 0x6c, 0x60, 0x02, 0xc3, 0x22, 0x05, 0x37, 0xe5, 0x37, 0x70, 0x02, 0x05, 0x36, 0x80, 0x8c} },
-{ 0x08b8,	16,	{0xe4, 0xf5, 0x36, 0xf5, 0x37, 0xc3, 0xe5, 0x37, 0x95, 0x35, 0xe5, 0x36, 0x95, 0x34, 0x50, 0x27} },
-{ 0x08c8,	16,	{0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xe0, 0x65, 0x37, 0x60, 0x02, 0xc3} },
-{ 0x08d8,	16,	{0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x37, 0xe5} },
-{ 0x08e8,	8,	{0x37, 0x70, 0x02, 0x05, 0x36, 0x80, 0xce, 0xd3} },
-{ 0x08f0,	1,	{0x22} },
-{ 0x08f1,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x10, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
-{ 0x08ff,	1,	{0x22} },
-{ 0x0900,	9,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
-{ 0x097d,	16,	{0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
-{ 0x098d,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x3a, 0x02, 0x09, 0xd4} },
-{ 0x0999,	16,	{0x02, 0x06, 0x9d, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
-{ 0x09a9,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
-{ 0x09b9,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
-{ 0x09c9,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0e, 0x2d, 0xe4, 0x7e} },
-{ 0x09d9,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
-{ 0x09e9,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
-{ 0x09f9,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
-{ 0x0a09,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
-{ 0x0a19,	16,	{0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0x74, 0x89} },
-{ 0x0a29,	16,	{0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0d, 0xd5, 0x90, 0x7f} },
-{ 0x0a39,	16,	{0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x7f, 0x05, 0x7e, 0x00} },
-{ 0x0a49,	16,	{0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02, 0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05} },
-{ 0x0a59,	16,	{0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00} },
-{ 0x0a69,	16,	{0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d} },
-{ 0x0a79,	16,	{0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x22} },
-{ 0x0a89,	16,	{0x75, 0x33, 0x01, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x01, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x0e} },
-{ 0x0a99,	16,	{0x7d, 0x00, 0x7c, 0x01, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12} },
-{ 0x0aa9,	16,	{0x0e, 0x18, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x02, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x80, 0x7d} },
-{ 0x0ab9,	16,	{0x00, 0x7c, 0x80, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0e} },
-{ 0x0ac9,	16,	{0x18, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x03, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x20, 0x7d, 0x40} },
-{ 0x0ad9,	16,	{0x7c, 0x5b, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0e, 0x18} },
-{ 0x0ae9,	13,	{0xe5, 0x33, 0x60, 0x05, 0xe4, 0xff, 0x12, 0x0e, 0x18, 0xe5, 0x33, 0x24, 0xff} },
-{ 0x0af6,	1,	{0x22} },
-{ 0x0af7,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x10, 0xd3, 0x22} },
-{ 0x0aff,	1,	{0x32} },
-{ 0x0b00,	16,	{0x02, 0x0d, 0xa5, 0x00, 0x02, 0x0d, 0xec, 0x00, 0x02, 0x0d, 0x70, 0x00, 0x02, 0x0d, 0xbd, 0x00} },
-{ 0x0b10,	16,	{0x02, 0x0e, 0x02, 0x00, 0x02, 0x0a, 0xff, 0x00, 0x02, 0x0e, 0x83, 0x00, 0x02, 0x0e, 0x84, 0x00} },
-{ 0x0b20,	16,	{0x02, 0x0e, 0x85, 0x00, 0x02, 0x0e, 0x86, 0x00, 0x02, 0x0e, 0x87, 0x00, 0x02, 0x0e, 0x88, 0x00} },
-{ 0x0b30,	16,	{0x02, 0x0e, 0x89, 0x00, 0x02, 0x0e, 0x8a, 0x00, 0x02, 0x0e, 0x8b, 0x00, 0x02, 0x0e, 0x8c, 0x00} },
-{ 0x0b40,	16,	{0x02, 0x0e, 0x8d, 0x00, 0x02, 0x0e, 0x8e, 0x00, 0x02, 0x0e, 0x8f, 0x00, 0x02, 0x0e, 0x90, 0x00} },
-{ 0x0b50,	8,	{0x02, 0x0e, 0x91, 0x00, 0x02, 0x0e, 0x92, 0x00} },
-{ 0x0b58,	16,	{0xe4, 0xfe, 0x75, 0x2b, 0xff, 0x75, 0x2c, 0x11, 0x75, 0x2d, 0x12, 0xab, 0x2b, 0xaa, 0x2c, 0xa9} },
-{ 0x0b68,	16,	{0x2d, 0x90, 0x00, 0x01, 0x12, 0x07, 0x85, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
-{ 0x0b78,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x07, 0xd4, 0x85, 0xf0, 0x29, 0xf5, 0x2a, 0x62, 0x29} },
-{ 0x0b88,	16,	{0xe5, 0x29, 0x62, 0x2a, 0xe5, 0x2a, 0x62, 0x29, 0x29, 0xfd, 0xe5, 0x29, 0x3a, 0xa9, 0x05, 0x75} },
-{ 0x0b98,	14,	{0x2b, 0xff, 0xf5, 0x2c, 0x89, 0x2d, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
-{ 0x0ba6,	1,	{0x22} },
-{ 0x0ba7,	6,	{0xab, 0x07, 0xaa, 0x06, 0xac, 0x05} },
-{ 0x0bad,	16,	{0xe4, 0xfd, 0xe5, 0x11, 0x60, 0x11, 0xea, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24, 0x10, 0xf5, 0x82} },
-{ 0x0bbd,	16,	{0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xeb, 0xae, 0x05, 0x0d, 0x74, 0x10, 0x2e, 0xf5, 0x82} },
-{ 0x0bcd,	16,	{0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xeb, 0xf0, 0xaf, 0x05, 0x0d, 0x74, 0x10, 0x2f, 0xf5, 0x82, 0xe4} },
-{ 0x0bdd,	16,	{0x34, 0x0f, 0xf5, 0x83, 0xec, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f, 0x7b, 0x10, 0x12, 0x0d, 0x51, 0x7f} },
-{ 0x0bed,	6,	{0x0a, 0x7e, 0x00, 0x12, 0x0d, 0xd5} },
-{ 0x0bf3,	1,	{0x22} },
-{ 0x0bf4,	10,	{0x8e, 0x33, 0x8f, 0x34, 0x8d, 0x35, 0x8a, 0x36, 0x8b, 0x37} },
-{ 0x0bfe,	16,	{0xe4, 0xfd, 0xf5, 0x38, 0xe5, 0x11, 0x60, 0x12, 0xe5, 0x33, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24} },
-{ 0x0c0e,	16,	{0x13, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x34, 0xae, 0x05, 0x0d, 0x74} },
-{ 0x0c1e,	16,	{0x13, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xe5, 0x34, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f} },
-{ 0x0c2e,	16,	{0x7b, 0x13, 0x12, 0x0d, 0x51, 0xaf, 0x0f, 0xad, 0x35, 0xab, 0x37, 0xaa, 0x36, 0x12, 0x0d, 0x32} },
-{ 0x0c3e,	1,	{0x22} },
-{ 0x0c3f,	2,	{0x8f, 0x29} },
-{ 0x0c41,	16,	{0xe4, 0xf5, 0x2a, 0x75, 0x2b, 0xff, 0x75, 0x2c, 0x11, 0x75, 0x2d, 0x32, 0xab, 0x2b, 0xaa, 0x2c} },
-{ 0x0c51,	16,	{0xa9, 0x2d, 0x90, 0x00, 0x01, 0x12, 0x07, 0x85, 0xb4, 0x03, 0x1d, 0xaf, 0x2a, 0x05, 0x2a, 0xef} },
-{ 0x0c61,	16,	{0xb5, 0x29, 0x01, 0x22, 0x12, 0x07, 0x6c, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
-{ 0x0c71,	14,	{0x2b, 0xff, 0xf5, 0x2c, 0x89, 0x2d, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
-{ 0x0c7f,	1,	{0x22} },
-{ 0x0c80,	10,	{0x8e, 0x33, 0x8f, 0x34, 0x8d, 0x35, 0x8a, 0x36, 0x8b, 0x37} },
-{ 0x0c8a,	16,	{0xe4, 0xf5, 0x38, 0xe5, 0x38, 0xc3, 0x95, 0x35, 0x50, 0x20, 0x05, 0x34, 0xe5, 0x34, 0xae, 0x33} },
-{ 0x0c9a,	16,	{0x70, 0x02, 0x05, 0x33, 0x14, 0xff, 0xe5, 0x37, 0x25, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x36, 0xf5} },
-{ 0x0caa,	10,	{0x83, 0xe0, 0xfd, 0x12, 0x0b, 0xa7, 0x05, 0x38, 0x80, 0xd9} },
-{ 0x0cb4,	1,	{0x22} },
-{ 0x0cb5,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x25, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
-{ 0x0cc5,	16,	{0x44, 0x01, 0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a} },
-{ 0x0cd5,	13,	{0x0a, 0x89, 0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x03, 0xd3, 0x22, 0xc3, 0x22} },
-{ 0x0ce2,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
-{ 0x0cf2,	16,	{0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a, 0x0a, 0x89} },
-{ 0x0d02,	11,	{0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x01, 0xd3, 0x22, 0xc3, 0x22} },
-{ 0x0d0d,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x06, 0x04, 0xe0, 0x44} },
-{ 0x0d1d,	16,	{0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
-{ 0x0d2d,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
-{ 0x0d32,	16,	{0x12, 0x0c, 0xb5, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
-{ 0x0d42,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
-{ 0x0d51,	16,	{0x12, 0x0c, 0xe2, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
-{ 0x0d61,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
-{ 0x0d70,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
-{ 0x0d80,	11,	{0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0d8b,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x12, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x14, 0x7e, 0x00, 0x12} },
-{ 0x0d9b,	10,	{0x0d, 0xd5, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
-{ 0x0da5,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
-{ 0x0db5,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0dbd,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x03, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
-{ 0x0dcd,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0dd5,	16,	{0x8e, 0x39, 0x8f, 0x3a, 0xe5, 0x3a, 0x15, 0x3a, 0xae, 0x39, 0x70, 0x02, 0x15, 0x39, 0x4e, 0x60} },
-{ 0x0de5,	7,	{0x05, 0x12, 0x0e, 0x41, 0x80, 0xee, 0x22} },
-{ 0x0dec,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0} },
-{ 0x0dfc,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0e02,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
-{ 0x0e12,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0e18,	16,	{0xae, 0x07, 0x7f, 0x21, 0x7d, 0x01, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xab, 0x82} },
-{ 0x0e28,	5,	{0xfa, 0x12, 0x0d, 0x51, 0x22} },
-{ 0x0e2d,	16,	{0x50, 0x0f, 0x00, 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, 0x88, 0x83, 0xc6} },
-{ 0x0e3d,	3,	{0xa1, 0x86, 0x8e} },
-{ 0x0e40,	1,	{0x00} },
-{ 0x0e41,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
-{ 0x0e51,	1,	{0x22} },
-{ 0x0e52,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x0e, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
-{ 0x0e60,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0e, 0xd3, 0x22} },
-{ 0x0e68,	8,	{0xe4, 0xf5, 0x0d, 0xd2, 0xe9, 0xd2, 0xaf, 0x22} },
-{ 0x0e70,	4,	{0x53, 0xd8, 0xef, 0x32} },
-{ 0x0e74,	3,	{0xd2, 0x00, 0x22} },
-{ 0x0e77,	2,	{0xd3, 0x22} },
-{ 0x0e79,	2,	{0xd3, 0x22} },
-{ 0x0e7b,	2,	{0xd3, 0x22} },
-{ 0x0e7d,	2,	{0xd3, 0x22} },
-{ 0x0e7f,	2,	{0xd3, 0x22} },
-{ 0x0e81,	2,	{0xd3, 0x22} },
-{ 0x0e83,	1,	{0x32} },
-{ 0x0e84,	1,	{0x32} },
-{ 0x0e85,	1,	{0x32} },
-{ 0x0e86,	1,	{0x32} },
-{ 0x0e87,	1,	{0x32} },
-{ 0x0e88,	1,	{0x32} },
-{ 0x0e89,	1,	{0x32} },
-{ 0x0e8a,	1,	{0x32} },
-{ 0x0e8b,	1,	{0x32} },
-{ 0x0e8c,	1,	{0x32} },
-{ 0x0e8d,	1,	{0x32} },
-{ 0x0e8e,	1,	{0x32} },
-{ 0x0e8f,	1,	{0x32} },
-{ 0x0e90,	1,	{0x32} },
-{ 0x0e91,	1,	{0x32} },
-{ 0x0e92,	1,	{0x32} },
-{ 0x1100,	16,	{0x12, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x47, 0x05, 0x10, 0x27, 0x01, 0x00, 0x01, 0x02} },
-{ 0x1110,	16,	{0x00, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x03, 0xa0, 0x00, 0x09, 0x04, 0x00, 0x00, 0x02} },
-{ 0x1120,	16,	{0xff, 0x00, 0x00, 0x04, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
-{ 0x1130,	16,	{0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x26, 0x03, 0x41, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x68, 0x00} },
-{ 0x1140,	16,	{0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x43, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x73, 0x00} },
-{ 0x1150,	16,	{0x2c, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x28, 0x03, 0x46, 0x00} },
-{ 0x1160,	16,	{0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00} },
-{ 0x1170,	16,	{0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00} },
-{ 0x1180,	16,	{0x6b, 0x00, 0x73, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
-{ 0x1190,	16,	{0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
-{ 0x11a0,	16,	{0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
-{ 0x11b0,	16,	{0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
-{ 0x11c0,	16,	{0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
-{ 0x11d0,	2,	{0x00, 0x00} },
-{ 0xffff,	0,	{0x00} }
-};
-
-#else
-
-static const struct whiteheat_hex_record whiteheat_loader[] = {
-{ 0x0000,	3,	{0x02, 0x09, 0x8d} },
-{ 0x0033,	3,	{0x02, 0x08, 0xfb} },
-{ 0x0043,	3,	{0x02, 0x0b, 0x00} },
-{ 0x004b,	3,	{0x02, 0x05, 0xaa} },
-{ 0x0100,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x54, 0x10, 0xff, 0xc4, 0x54, 0x0f, 0x44, 0x50, 0xf5, 0x0f, 0x13, 0xe4} },
-{ 0x0110,	16,	{0x33, 0xf5, 0x11, 0x90, 0x7f, 0xe9, 0xe0, 0x24, 0x5e, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x03} },
-{ 0x0120,	16,	{0x78, 0x90, 0x01, 0x28, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x01, 0xbc, 0x02, 0x01, 0xbc, 0x02, 0x01} },
-{ 0x0130,	16,	{0x91, 0x02, 0x01, 0x3d, 0x02, 0x01, 0x53, 0x02, 0x01, 0x6f, 0x02, 0x01, 0x9a, 0x90, 0x7f, 0x00} },
-{ 0x0140,	16,	{0xe5, 0x11, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
-{ 0x0150,	16,	{0x02, 0x03, 0x78, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x90, 0x7f, 0x00, 0xf0, 0x90} },
-{ 0x0160,	16,	{0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03, 0x78, 0x12} },
-{ 0x0170,	16,	{0x0a, 0x89, 0x50, 0x07, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0x80, 0x06, 0x90, 0x7f, 0x00, 0x74, 0x0f} },
-{ 0x0180,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03} },
-{ 0x0190,	16,	{0x78, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0f, 0x02, 0x03, 0x78, 0x90, 0x7f, 0x00, 0x74, 0x07, 0xf0} },
-{ 0x01a0,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xe8, 0x7e} },
-{ 0x01b0,	16,	{0x03, 0x12, 0x0d, 0x94, 0xd2, 0x06, 0x12, 0x0c, 0xcc, 0x02, 0x03, 0x78, 0x90, 0x7f, 0xea, 0xe0} },
-{ 0x01c0,	16,	{0x75, 0x28, 0x00, 0xf5, 0x29, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x28, 0x90, 0x7f, 0xee, 0xe0} },
-{ 0x01d0,	16,	{0x75, 0x2a, 0x00, 0xf5, 0x2b, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x2a, 0x90, 0x7f, 0xe8, 0xe0} },
-{ 0x01e0,	16,	{0x64, 0xc0, 0x60, 0x03, 0x02, 0x02, 0xc9, 0xe5, 0x2b, 0x45, 0x2a, 0x70, 0x03, 0x02, 0x03, 0x78} },
-{ 0x01f0,	16,	{0xc3, 0xe5, 0x2b, 0x94, 0x40, 0xe5, 0x2a, 0x94, 0x00, 0x50, 0x08, 0x85, 0x2a, 0x2c, 0x85, 0x2b} },
-{ 0x0200,	16,	{0x2d, 0x80, 0x06, 0x75, 0x2c, 0x00, 0x75, 0x2d, 0x40, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70} },
-{ 0x0210,	16,	{0x34, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31, 0x95, 0x2d, 0xe5, 0x30, 0x95, 0x2c, 0x50, 0x5c} },
-{ 0x0220,	16,	{0xe5, 0x29, 0x25, 0x31, 0xf5, 0x82, 0xe5, 0x30, 0x35, 0x28, 0xf5, 0x83, 0xe0, 0xff, 0x74, 0x00} },
-{ 0x0230,	16,	{0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70} },
-{ 0x0240,	16,	{0x02, 0x05, 0x30, 0x80, 0xd0, 0xe4, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31, 0x95, 0x2d, 0xe5} },
-{ 0x0250,	16,	{0x30, 0x95, 0x2c, 0x50, 0x18, 0x74, 0x00, 0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83} },
-{ 0x0260,	16,	{0x74, 0xcd, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70, 0x02, 0x05, 0x30, 0x80, 0xdd, 0xaf, 0x29, 0xae} },
-{ 0x0270,	16,	{0x28, 0xad, 0x2d, 0x7a, 0x7f, 0x79, 0x00, 0x7b, 0x00, 0x12, 0x0b, 0xf4, 0x90, 0x7f, 0xb5, 0xe5} },
-{ 0x0280,	16,	{0x2d, 0xf0, 0xe5, 0x2d, 0x25, 0x29, 0xf5, 0x29, 0xe5, 0x2c, 0x35, 0x28, 0xf5, 0x28, 0xc3, 0xe5} },
-{ 0x0290,	16,	{0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0xe5, 0x2a, 0x95, 0x2c, 0xf5, 0x2a, 0x90, 0x7f, 0x92, 0xe0, 0xff} },
-{ 0x02a0,	16,	{0xc4, 0x54, 0x0f, 0x75, 0x2e, 0x00, 0xf5, 0x2f, 0xd3, 0x94, 0x00, 0xe5, 0x2e, 0x94, 0x00, 0x50} },
-{ 0x02b0,	16,	{0x0c, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe1, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xb4} },
-{ 0x02c0,	16,	{0xe0, 0x20, 0xe2, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xe8, 0xe0, 0x64, 0x40, 0x60} },
-{ 0x02d0,	16,	{0x03, 0x02, 0x03, 0x78, 0xe5, 0x2b, 0x45, 0x2a, 0x70, 0x03, 0x02, 0x03, 0x78, 0xe4, 0x90, 0x7f} },
-{ 0x02e0,	16,	{0xc5, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x75, 0x2e, 0x00, 0xf5, 0x2f, 0xd3} },
-{ 0x02f0,	16,	{0x94, 0x00, 0xe5, 0x2e, 0x94, 0x00, 0x50, 0x09, 0x90, 0x7f, 0xc4, 0xe0, 0x30, 0xe1, 0x09, 0x80} },
-{ 0x0300,	16,	{0xf7, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe3, 0xf9, 0x90, 0x7f, 0xc5, 0xe0, 0x75, 0x2c, 0x00, 0xf5} },
-{ 0x0310,	16,	{0x2d, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70, 0x34, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31} },
-{ 0x0320,	16,	{0x95, 0x2d, 0xe5, 0x30, 0x95, 0x2c, 0x50, 0x34, 0x74, 0xc0, 0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x0330,	1,	{0x7e} },
-{ 0x0331,	16,	{0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x29, 0x25, 0x31, 0xf5, 0x82, 0xe5, 0x30, 0x35, 0x28, 0xf5, 0x83} },
-{ 0x0341,	16,	{0xef, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70, 0x02, 0x05, 0x30, 0x80, 0xd0, 0xaf, 0x29, 0xae, 0x28} },
-{ 0x0351,	16,	{0xad, 0x2d, 0x7a, 0x7e, 0x79, 0xc0, 0x7b, 0xc0, 0x12, 0x0c, 0x3f, 0xe5, 0x2d, 0x25, 0x29, 0xf5} },
-{ 0x0361,	16,	{0x29, 0xe5, 0x2c, 0x35, 0x28, 0xf5, 0x28, 0xc3, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0xe5, 0x2a} },
-{ 0x0371,	9,	{0x95, 0x2c, 0xf5, 0x2a, 0x02, 0x02, 0xd4, 0xc3, 0x22} },
-{ 0x037a,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x52, 0x14, 0x70, 0x03, 0x02, 0x04, 0xce, 0x24} },
-{ 0x038a,	16,	{0xfe, 0x70, 0x03, 0x02, 0x05, 0x42, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x4c, 0x14, 0x70, 0x03} },
-{ 0x039a,	16,	{0x02, 0x04, 0x46, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x40, 0x24} },
-{ 0x03aa,	16,	{0x05, 0x60, 0x03, 0x02, 0x05, 0x96, 0x12, 0x0e, 0x44, 0x40, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f} },
-{ 0x03ba,	16,	{0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02, 0x70, 0x69, 0x74, 0x11, 0x90} },
-{ 0x03ca,	16,	{0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0} },
-{ 0x03da,	16,	{0xff, 0x12, 0x0b, 0x58, 0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02} },
-{ 0x03ea,	16,	{0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90} },
-{ 0x03fa,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x08} },
-{ 0x040a,	16,	{0xba, 0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f} },
-{ 0x041a,	16,	{0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0} },
-{ 0x042a,	16,	{0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2} },
-{ 0x043a,	16,	{0x12, 0x0e, 0x1f, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x2d, 0x02, 0x05, 0xa2, 0x12, 0x0a, 0xf7, 0x02} },
-{ 0x044a,	16,	{0x05, 0xa2, 0x12, 0x0e, 0x11, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x46, 0x40, 0x03, 0x02, 0x05, 0xa2} },
-{ 0x045a,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
-{ 0x046a,	16,	{0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x02, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
-{ 0x047a,	16,	{0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0xe4, 0x90, 0x7f, 0x00} },
-{ 0x048a,	16,	{0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xec, 0xe0} },
-{ 0x049a,	16,	{0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
-{ 0x04aa,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
-{ 0x04ba,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
-{ 0x04ca,	16,	{0xf0, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x48, 0x40, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xe8, 0xe0} },
-{ 0x04da,	16,	{0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0, 0xb4} },
-{ 0x04ea,	16,	{0x01, 0x05, 0xc2, 0x00, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05} },
-{ 0x04fa,	16,	{0xa2, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4} },
-{ 0x050a,	16,	{0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f} },
-{ 0x051a,	16,	{0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f} },
-{ 0x052a,	16,	{0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x69, 0x90} },
-{ 0x053a,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x60, 0x12, 0x0e, 0x4a, 0x50, 0x5b, 0x90, 0x7f, 0xe8} },
-{ 0x054a,	16,	{0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4f, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
-{ 0x055a,	16,	{0xd2, 0x00, 0x80, 0x44, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x3b, 0x90, 0x7f, 0xea} },
-{ 0x056a,	16,	{0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
-{ 0x057a,	16,	{0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
-{ 0x058a,	16,	{0xf0, 0x80, 0x15, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x0c, 0x12, 0x01, 0x00, 0x50} },
-{ 0x059a,	16,	{0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22} },
-{ 0x05aa,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
-{ 0x05ba,	16,	{0xd0, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x06, 0xc0, 0x07, 0x90, 0x7f, 0xa5} },
-{ 0x05ca,	16,	{0xe0, 0x30, 0xe2, 0x06, 0x75, 0x0d, 0x06, 0x02, 0x06, 0x76, 0x90, 0x7f, 0xa5, 0xe0, 0x20, 0xe1} },
-{ 0x05da,	16,	{0x0c, 0xe5, 0x0d, 0x64, 0x02, 0x60, 0x06, 0x75, 0x0d, 0x07, 0x02, 0x06, 0x76, 0xaf, 0x0d, 0xef} },
-{ 0x05ea,	16,	{0x24, 0xfe, 0x60, 0x48, 0x14, 0x60, 0x2c, 0x24, 0xfe, 0x60, 0x77, 0x24, 0x04, 0x60, 0x03, 0x02} },
-{ 0x05fa,	16,	{0x06, 0x76, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xaf, 0x0c, 0x05, 0x0c, 0x8f, 0x82, 0x75, 0x83} },
-{ 0x060a,	16,	{0x00, 0x12, 0x08, 0x22, 0x90, 0x7f, 0xa6, 0xf0, 0xe5, 0x0c, 0x65, 0x08, 0x70, 0x5e, 0x75, 0x0d} },
-{ 0x061a,	16,	{0x05, 0x80, 0x59, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e} },
-{ 0x062a,	16,	{0x82, 0x75, 0x83, 0x00, 0x12, 0x08, 0x4f, 0x75, 0x0d, 0x02, 0x80, 0x40, 0xe5, 0x08, 0x24, 0xfe} },
-{ 0x063a,	16,	{0xb5, 0x0c, 0x07, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0xe5, 0x08, 0x14, 0xb5, 0x0c, 0x0a} },
-{ 0x064a,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09} },
-{ 0x065a,	16,	{0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e, 0x82, 0x75, 0x83, 0x00, 0x12, 0x08, 0x4f, 0x05, 0x0c} },
-{ 0x066a,	16,	{0x80, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x53, 0x91, 0xdf, 0xd0} },
-{ 0x067a,	16,	{0x07, 0xd0, 0x06, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x86, 0xd0} },
-{ 0x068a,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0694,	16,	{0x8c, 0x33, 0x8d, 0x34, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0xe4, 0xf5, 0x35, 0xf5, 0x36} },
-{ 0x06a4,	16,	{0xc3, 0xe5, 0x36, 0x95, 0x34, 0xe5, 0x35, 0x95, 0x33, 0x50, 0x69, 0xef, 0x25, 0x36, 0xf5, 0x82} },
-{ 0x06b4,	16,	{0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0xff, 0xf0, 0xf4, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36} },
-{ 0x06c4,	16,	{0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36} },
-{ 0x06d4,	16,	{0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0xaa, 0xf0, 0x64, 0xaa, 0x60, 0x02, 0xc3, 0x22} },
-{ 0x06e4,	16,	{0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0x55, 0xf0, 0x64, 0x55, 0x60} },
-{ 0x06f4,	16,	{0x02, 0xc3, 0x22, 0xad, 0x36, 0xe5, 0x36, 0x2f, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xed} },
-{ 0x0704,	16,	{0xf0, 0xfc, 0xac, 0x05, 0xed, 0x6c, 0x60, 0x02, 0xc3, 0x22, 0x05, 0x36, 0xe5, 0x36, 0x70, 0x02} },
-{ 0x0714,	16,	{0x05, 0x35, 0x80, 0x8c, 0xe4, 0xf5, 0x35, 0xf5, 0x36, 0xc3, 0xe5, 0x36, 0x95, 0x34, 0xe5, 0x35} },
-{ 0x0724,	16,	{0x95, 0x33, 0x50, 0x27, 0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe0, 0x65} },
-{ 0x0734,	16,	{0x36, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe4} },
-{ 0x0744,	13,	{0xf0, 0x05, 0x36, 0xe5, 0x36, 0x70, 0x02, 0x05, 0x35, 0x80, 0xce, 0xd3, 0x22} },
-{ 0x0751,	16,	{0xc2, 0x04, 0xd2, 0x05, 0xc2, 0x03, 0xc2, 0x00, 0xc2, 0x02, 0xc2, 0x01, 0x12, 0x0e, 0x3d, 0xd2} },
-{ 0x0761,	16,	{0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f} },
-{ 0x0771,	16,	{0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x7f, 0x93, 0x74} },
-{ 0x0781,	16,	{0x30, 0xf0, 0x12, 0x0a, 0x19, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0} },
-{ 0x0791,	16,	{0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0x12, 0x0e, 0x35, 0x20, 0x01, 0x42, 0x75, 0x24, 0x00, 0x75, 0x23} },
-{ 0x07a1,	16,	{0x00, 0x75, 0x22, 0x00, 0x75, 0x21, 0x00, 0x7f, 0x48, 0x7e, 0x92, 0x7d, 0x00, 0x7c, 0x00, 0xab} },
-{ 0x07b1,	16,	{0x24, 0xaa, 0x23, 0xa9, 0x22, 0xa8, 0x21, 0xc3, 0x12, 0x08, 0xa9, 0x50, 0xdb, 0x20, 0x01, 0xd8} },
-{ 0x07c1,	16,	{0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xe5, 0x24, 0x24, 0x01, 0xf5, 0x24, 0xea, 0x35, 0x23, 0xf5} },
-{ 0x07d1,	16,	{0x23, 0xe9, 0x35, 0x22, 0xf5, 0x22, 0xe8, 0x35, 0x21, 0xf5, 0x21, 0x80, 0xca, 0x30, 0x01, 0x05} },
-{ 0x07e1,	16,	{0x12, 0x03, 0x7a, 0xc2, 0x01, 0x30, 0x04, 0x1a, 0x12, 0x0e, 0x40, 0x50, 0x13, 0x12, 0x09, 0x00} },
-{ 0x07f1,	16,	{0x30, 0x00, 0x07, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0xf3, 0x12, 0x0d, 0x4a, 0x12, 0x0e, 0x42} },
-{ 0x0801,	8,	{0xc2, 0x03, 0x12, 0x08, 0xff, 0x80, 0xd6, 0x22} },
-{ 0x0809,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
-{ 0x0819,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
-{ 0x0822,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
-{ 0x0832,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
-{ 0x0842,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
-{ 0x084f,	16,	{0xf8, 0xbb, 0x01, 0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0} },
-{ 0x085f,	16,	{0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8} },
-{ 0x086f,	2,	{0xf2, 0x22} },
-{ 0x0871,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
-{ 0x0881,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
-{ 0x0891,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
-{ 0x08a1,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
-{ 0x08a9,	16,	{0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
-{ 0x08b9,	1,	{0x22} },
-{ 0x08ba,	2,	{0x8f, 0x28} },
-{ 0x08bc,	16,	{0xe4, 0xf5, 0x29, 0x75, 0x2a, 0xff, 0x75, 0x2b, 0x11, 0x75, 0x2c, 0x32, 0xab, 0x2a, 0xaa, 0x2b} },
-{ 0x08cc,	16,	{0xa9, 0x2c, 0x90, 0x00, 0x01, 0x12, 0x08, 0x22, 0xb4, 0x03, 0x1d, 0xaf, 0x29, 0x05, 0x29, 0xef} },
-{ 0x08dc,	16,	{0xb5, 0x28, 0x01, 0x22, 0x12, 0x08, 0x09, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
-{ 0x08ec,	14,	{0x2a, 0xff, 0xf5, 0x2b, 0x89, 0x2c, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
-{ 0x08fa,	1,	{0x22} },
-{ 0x08fb,	4,	{0x53, 0xd8, 0xef, 0x32} },
-{ 0x08ff,	1,	{0x22} },
-{ 0x0900,	9,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
-{ 0x097d,	16,	{0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
-{ 0x098d,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x39, 0x02, 0x09, 0xd4} },
-{ 0x0999,	16,	{0x02, 0x07, 0x51, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
-{ 0x09a9,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
-{ 0x09b9,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
-{ 0x09c9,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0d, 0xec, 0xe4, 0x7e} },
-{ 0x09d9,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
-{ 0x09e9,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
-{ 0x09f9,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
-{ 0x0a09,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
-{ 0x0a19,	16,	{0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0x74, 0x89} },
-{ 0x0a29,	16,	{0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0d, 0x94, 0x90, 0x7f} },
-{ 0x0a39,	16,	{0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x7f, 0x05, 0x7e, 0x00} },
-{ 0x0a49,	16,	{0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02, 0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05} },
-{ 0x0a59,	16,	{0x7e, 0x00, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00} },
-{ 0x0a69,	16,	{0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d} },
-{ 0x0a79,	16,	{0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x22} },
-{ 0x0a89,	16,	{0x75, 0x32, 0x01, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x01, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x0e} },
-{ 0x0a99,	16,	{0x7d, 0x00, 0x7c, 0x01, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12} },
-{ 0x0aa9,	16,	{0x0d, 0xd7, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x02, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x80, 0x7d} },
-{ 0x0ab9,	16,	{0x00, 0x7c, 0x80, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0d} },
-{ 0x0ac9,	16,	{0xd7, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x03, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x20, 0x7d, 0x40} },
-{ 0x0ad9,	16,	{0x7c, 0x5b, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0d, 0xd7} },
-{ 0x0ae9,	14,	{0xe5, 0x32, 0x60, 0x05, 0xe4, 0xff, 0x12, 0x0d, 0xd7, 0xe5, 0x32, 0x24, 0xff, 0x22} },
-{ 0x0af7,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x10, 0xd3, 0x22} },
-{ 0x0aff,	1,	{0x32} },
-{ 0x0b00,	16,	{0x02, 0x0d, 0x64, 0x00, 0x02, 0x0d, 0xab, 0x00, 0x02, 0x0d, 0x2f, 0x00, 0x02, 0x0d, 0x7c, 0x00} },
-{ 0x0b10,	16,	{0x02, 0x0d, 0xc1, 0x00, 0x02, 0x0a, 0xff, 0x00, 0x02, 0x0e, 0x4c, 0x00, 0x02, 0x0e, 0x4d, 0x00} },
-{ 0x0b20,	16,	{0x02, 0x0e, 0x4e, 0x00, 0x02, 0x0e, 0x4f, 0x00, 0x02, 0x0e, 0x50, 0x00, 0x02, 0x0e, 0x51, 0x00} },
-{ 0x0b30,	16,	{0x02, 0x0e, 0x52, 0x00, 0x02, 0x0e, 0x53, 0x00, 0x02, 0x0e, 0x54, 0x00, 0x02, 0x0e, 0x55, 0x00} },
-{ 0x0b40,	16,	{0x02, 0x0e, 0x56, 0x00, 0x02, 0x0e, 0x57, 0x00, 0x02, 0x0e, 0x58, 0x00, 0x02, 0x0e, 0x59, 0x00} },
-{ 0x0b50,	8,	{0x02, 0x0e, 0x5a, 0x00, 0x02, 0x0e, 0x5b, 0x00} },
-{ 0x0b58,	16,	{0xe4, 0xfe, 0x75, 0x2a, 0xff, 0x75, 0x2b, 0x11, 0x75, 0x2c, 0x12, 0xab, 0x2a, 0xaa, 0x2b, 0xa9} },
-{ 0x0b68,	16,	{0x2c, 0x90, 0x00, 0x01, 0x12, 0x08, 0x22, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
-{ 0x0b78,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x08, 0x71, 0x85, 0xf0, 0x28, 0xf5, 0x29, 0x62, 0x28} },
-{ 0x0b88,	16,	{0xe5, 0x28, 0x62, 0x29, 0xe5, 0x29, 0x62, 0x28, 0x29, 0xfd, 0xe5, 0x28, 0x3a, 0xa9, 0x05, 0x75} },
-{ 0x0b98,	14,	{0x2a, 0xff, 0xf5, 0x2b, 0x89, 0x2c, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
-{ 0x0ba6,	1,	{0x22} },
-{ 0x0ba7,	16,	{0xab, 0x07, 0xaa, 0x06, 0xac, 0x05, 0xe4, 0xfd, 0xe5, 0x11, 0x60, 0x11, 0xea, 0xff, 0xae, 0x05} },
-{ 0x0bb7,	16,	{0x0d, 0xee, 0x24, 0x10, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xeb, 0xae, 0x05} },
-{ 0x0bc7,	16,	{0x0d, 0x74, 0x10, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xeb, 0xf0, 0xaf, 0x05, 0x0d} },
-{ 0x0bd7,	16,	{0x74, 0x10, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xec, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f} },
-{ 0x0be7,	13,	{0x7b, 0x10, 0x12, 0x0d, 0x10, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x22} },
-{ 0x0bf4,	16,	{0x8e, 0x32, 0x8f, 0x33, 0x8d, 0x34, 0x8a, 0x35, 0x8b, 0x36, 0xe4, 0xfd, 0xf5, 0x37, 0xe5, 0x11} },
-{ 0x0c04,	16,	{0x60, 0x12, 0xe5, 0x32, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24, 0x13, 0xf5, 0x82, 0xe4, 0x34, 0x0f} },
-{ 0x0c14,	16,	{0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x33, 0xae, 0x05, 0x0d, 0x74, 0x13, 0x2e, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x0c24,	16,	{0x0f, 0xf5, 0x83, 0xe5, 0x33, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f, 0x7b, 0x13, 0x12, 0x0d, 0x10, 0xaf} },
-{ 0x0c34,	11,	{0x0f, 0xad, 0x34, 0xab, 0x36, 0xaa, 0x35, 0x12, 0x0c, 0xf1, 0x22} },
-{ 0x0c3f,	16,	{0x8e, 0x32, 0x8f, 0x33, 0x8d, 0x34, 0x8a, 0x35, 0x8b, 0x36, 0xe4, 0xf5, 0x37, 0xe5, 0x37, 0xc3} },
-{ 0x0c4f,	16,	{0x95, 0x34, 0x50, 0x20, 0x05, 0x33, 0xe5, 0x33, 0xae, 0x32, 0x70, 0x02, 0x05, 0x32, 0x14, 0xff} },
-{ 0x0c5f,	16,	{0xe5, 0x36, 0x25, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x35, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x0b, 0xa7} },
-{ 0x0c6f,	5,	{0x05, 0x37, 0x80, 0xd9, 0x22} },
-{ 0x0c74,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x25, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
-{ 0x0c84,	16,	{0x44, 0x01, 0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a} },
-{ 0x0c94,	13,	{0x0a, 0x89, 0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x03, 0xd3, 0x22, 0xc3, 0x22} },
-{ 0x0ca1,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
-{ 0x0cb1,	16,	{0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a, 0x0a, 0x89} },
-{ 0x0cc1,	11,	{0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x01, 0xd3, 0x22, 0xc3, 0x22} },
-{ 0x0ccc,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x06, 0x04, 0xe0, 0x44} },
-{ 0x0cdc,	16,	{0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
-{ 0x0cec,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
-{ 0x0cf1,	16,	{0x12, 0x0c, 0x74, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
-{ 0x0d01,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
-{ 0x0d10,	16,	{0x12, 0x0c, 0xa1, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
-{ 0x0d20,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
-{ 0x0d2f,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
-{ 0x0d3f,	11,	{0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0d4a,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x12, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x14, 0x7e, 0x00, 0x12} },
-{ 0x0d5a,	10,	{0x0d, 0x94, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
-{ 0x0d64,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
-{ 0x0d74,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0d7c,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x03, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
-{ 0x0d8c,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0d94,	16,	{0x8e, 0x38, 0x8f, 0x39, 0xe5, 0x39, 0x15, 0x39, 0xae, 0x38, 0x70, 0x02, 0x15, 0x38, 0x4e, 0x60} },
-{ 0x0da4,	7,	{0x05, 0x12, 0x0e, 0x00, 0x80, 0xee, 0x22} },
-{ 0x0dab,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0} },
-{ 0x0dbb,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0dc1,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
-{ 0x0dd1,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0dd7,	16,	{0xae, 0x07, 0x7f, 0x21, 0x7d, 0x01, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xab, 0x82} },
-{ 0x0de7,	5,	{0xfa, 0x12, 0x0d, 0x10, 0x22} },
-{ 0x0dec,	16,	{0x50, 0x0f, 0x00, 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, 0x88, 0x83, 0xc6} },
-{ 0x0dfc,	3,	{0xa1, 0x86, 0x8e} },
-{ 0x0dff,	1,	{0x00} },
-{ 0x0e00,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
-{ 0x0e10,	1,	{0x22} },
-{ 0x0e11,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x10, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
-{ 0x0e1f,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x0e, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
-{ 0x0e2d,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0e, 0xd3, 0x22} },
-{ 0x0e35,	8,	{0xe4, 0xf5, 0x0d, 0xd2, 0xe9, 0xd2, 0xaf, 0x22} },
-{ 0x0e3d,	3,	{0xd2, 0x00, 0x22} },
-{ 0x0e40,	2,	{0xd3, 0x22} },
-{ 0x0e42,	2,	{0xd3, 0x22} },
-{ 0x0e44,	2,	{0xd3, 0x22} },
-{ 0x0e46,	2,	{0xd3, 0x22} },
-{ 0x0e48,	2,	{0xd3, 0x22} },
-{ 0x0e4a,	2,	{0xd3, 0x22} },
-{ 0x0e4c,	1,	{0x32} },
-{ 0x0e4d,	1,	{0x32} },
-{ 0x0e4e,	1,	{0x32} },
-{ 0x0e4f,	1,	{0x32} },
-{ 0x0e50,	1,	{0x32} },
-{ 0x0e51,	1,	{0x32} },
-{ 0x0e52,	1,	{0x32} },
-{ 0x0e53,	1,	{0x32} },
-{ 0x0e54,	1,	{0x32} },
-{ 0x0e55,	1,	{0x32} },
-{ 0x0e56,	1,	{0x32} },
-{ 0x0e57,	1,	{0x32} },
-{ 0x0e58,	1,	{0x32} },
-{ 0x0e59,	1,	{0x32} },
-{ 0x0e5a,	1,	{0x32} },
-{ 0x0e5b,	1,	{0x32} },
-{ 0x1100,	16,	{0x12, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x47, 0x05, 0x10, 0x27, 0x01, 0x00, 0x01, 0x02} },
-{ 0x1110,	16,	{0x00, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x03, 0xa0, 0x00, 0x09, 0x04, 0x00, 0x00, 0x02} },
-{ 0x1120,	16,	{0xff, 0x00, 0x00, 0x04, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
-{ 0x1130,	16,	{0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x26, 0x03, 0x41, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x68, 0x00} },
-{ 0x1140,	16,	{0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x43, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x73, 0x00} },
-{ 0x1150,	16,	{0x2c, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x28, 0x03, 0x46, 0x00} },
-{ 0x1160,	16,	{0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00} },
-{ 0x1170,	16,	{0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00} },
-{ 0x1180,	16,	{0x6b, 0x00, 0x73, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
-{ 0x1190,	16,	{0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
-{ 0x11a0,	16,	{0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
-{ 0x11b0,	16,	{0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
-{ 0x11c0,	16,	{0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
-{ 0x11d0,	2,	{0x00, 0x00} },
-{ 0xffff,	0,	{0x00} }
-};
-#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/serial/whiteheat_fw.h linux/drivers/usb/serial/whiteheat_fw.h
--- v2.3.99-pre3/linux/drivers/usb/serial/whiteheat_fw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/whiteheat_fw.h	Mon Apr 10 22:54:09 2000
@@ -0,0 +1,1556 @@
+/*****************************************************************************
+ *
+ *      whiteheat.h  --  ConnectTech WhiteHEAT Firmware.
+ *
+ *      Copyright (C) 2000  ConnectTech Inc (http://www.connecttech.com/)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * (04/09/2000) gkh
+ *	Updated the firmware with the latest provided by ConnectTech.
+ *
+ * (01/16/2000) gkh
+ *	Fixed my intel hex processing tool, so now the firmware actually
+ *	matches the original file (this was causing a few problems...)
+ *
+ * (01/15/2000) gkh
+ *	Added debug loader firmware if DEBUG is #defined:
+ *		Port 1 LED flashes when the vend_ax program is running
+ *		Port 2 LED flashes when any SETUP command arrives
+ *		Port 3 LED flashes when any valid VENDOR request occurs
+ *		Port 4 LED flashes when the EXTERNAL RAM DOWNLOAD request occurs
+ *
+ * version 1.0 (01/09/2000) gkh
+ *	Original firmware from ConnectTech massaged a little to be program
+ *	readable.
+ *
+ *****************************************************************************/
+
+#define whiteheat_DATE "20000106"
+
+struct whiteheat_hex_record {
+	__u16	address;
+	__u8	data_size;
+	__u8	data[16];
+};
+
+static const struct whiteheat_hex_record whiteheat_firmware[] = {
+{ 0x0000,	3,	{0x02, 0x93, 0xa9} },
+{ 0x0003,	3,	{0x02, 0x13, 0x12} },
+{ 0x000b,	3,	{0x02, 0x0a, 0x80} },
+{ 0x0033,	3,	{0x02, 0x08, 0x15} },
+{ 0x0043,	3,	{0x02, 0x0a, 0x00} },
+{ 0x005b,	3,	{0x02, 0x82, 0x31} },
+{ 0x0370,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x73, 0x14, 0x70, 0x03, 0x02, 0x04, 0xe7, 0x24} },
+{ 0x0380,	16,	{0xfe, 0x70, 0x03, 0x02, 0x05, 0x45, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x64, 0x14, 0x70, 0x03} },
+{ 0x0390,	16,	{0x02, 0x04, 0x52, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x49, 0x24} },
+{ 0x03a0,	16,	{0x05, 0x60, 0x03, 0x02, 0x05, 0x94, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60} },
+{ 0x03b0,	16,	{0x36, 0x24, 0x02, 0x70, 0x7b, 0x74, 0x12, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
+{ 0x03c0,	16,	{0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x7b, 0xea, 0x49, 0x60, 0x0d} },
+{ 0x03d0,	16,	{0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4} },
+{ 0x03e0,	16,	{0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x3a, 0xea} },
+{ 0x03f0,	16,	{0x49, 0x60, 0x33, 0x12, 0x9b, 0x72, 0xf5, 0x4b, 0x90, 0x7f, 0xee, 0xe0, 0xff, 0xe5, 0x4b, 0xd3} },
+{ 0x0400,	16,	{0x9f, 0x40, 0x03, 0xe0, 0xf5, 0x4b, 0xe5, 0x4b, 0xd3, 0x94, 0x40, 0x40, 0x03, 0x75, 0x4b, 0x40} },
+{ 0x0410,	16,	{0xae, 0x02, 0xaf, 0x01, 0x7c, 0x7f, 0x7d, 0x00, 0xab, 0x4b, 0x12, 0x8d, 0xd9, 0x90, 0x7f, 0xb5} },
+{ 0x0420,	16,	{0xe5, 0x4b, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b} },
+{ 0x0430,	16,	{0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0x00, 0xe5, 0x21, 0xf0} },
+{ 0x0440,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x21, 0x02} },
+{ 0x0450,	16,	{0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x31, 0xd2, 0x02, 0x43, 0x88, 0x10, 0xd2, 0xeb, 0xd2} },
+{ 0x0460,	16,	{0xa8, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0x00, 0xe5, 0x31, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0} },
+{ 0x0470,	16,	{0x02, 0x05, 0x9b, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02} },
+{ 0x0480,	16,	{0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x05, 0xe4, 0x33, 0x4f, 0x90} },
+{ 0x0490,	16,	{0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0xe4} },
+{ 0x04a0,	16,	{0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0x90} },
+{ 0x04b0,	16,	{0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25} },
+{ 0x04c0,	16,	{0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0x01, 0x90, 0x7f, 0x00} },
+{ 0x04d0,	16,	{0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4} },
+{ 0x04e0,	16,	{0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24} },
+{ 0x04f0,	16,	{0x02, 0x60, 0x03, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02} },
+{ 0x0500,	16,	{0x05, 0x9b, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x0510,	16,	{0x70, 0x2a, 0x90, 0x7f, 0xec, 0xe0, 0xff, 0xf4, 0x54, 0x80, 0xfe, 0xc4, 0x54, 0x0f, 0xfe, 0xef} },
+{ 0x0520,	16,	{0x54, 0x07, 0xfd, 0x2e, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4} },
+{ 0x0530,	16,	{0xf0, 0x90, 0x7f, 0xd7, 0xed, 0xf0, 0xef, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0540,	16,	{0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70} },
+{ 0x0550,	16,	{0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x00, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0560,	16,	{0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4} },
+{ 0x0570,	16,	{0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
+{ 0x0580,	16,	{0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x0590,	16,	{0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x05a0,	2,	{0x02, 0xf0} },
+{ 0x05a2,	1,	{0x22} },
+{ 0x05a3,	16,	{0x75, 0x47, 0xff, 0x75, 0x46, 0xff, 0x75, 0x45, 0x0f, 0x75, 0x44, 0x00, 0xd2, 0x03, 0xc2, 0x06} },
+{ 0x05b3,	16,	{0xc2, 0x02, 0xc2, 0x00, 0xc2, 0x05, 0xc2, 0x01, 0x90, 0x03, 0x00, 0x74, 0x19, 0xf0, 0xe4, 0x90} },
+{ 0x05c3,	16,	{0x01, 0xbc, 0xf0, 0xc2, 0x04, 0x90, 0x01, 0xc0, 0xf0, 0xa3, 0xf0, 0xc2, 0xaf, 0xc2, 0xa8, 0x12} },
+{ 0x05d3,	16,	{0x0b, 0x8d, 0xe4, 0x90, 0x02, 0xaf, 0xf0, 0x90, 0x01, 0x00, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x05e3,	16,	{0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0x7e} },
+{ 0x05f3,	16,	{0x01, 0x7f, 0x00, 0x12, 0x19, 0xc1, 0x75, 0x49, 0x12, 0x75, 0x4a, 0x0a, 0x90, 0x01, 0x0b, 0xe0} },
+{ 0x0603,	16,	{0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
+{ 0x0613,	16,	{0xef, 0xf0, 0x90, 0x01, 0x0c, 0xe0, 0x44, 0x80, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70} },
+{ 0x0623,	16,	{0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0d, 0xe0, 0xff, 0x05} },
+{ 0x0633,	16,	{0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
+{ 0x0643,	16,	{0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14} },
+{ 0x0653,	16,	{0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x12, 0x0a, 0xe4, 0x93, 0xff, 0x74, 0x01, 0x93, 0x90} },
+{ 0x0663,	16,	{0x01, 0x1c, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0xff, 0xa3, 0xe0, 0xfe, 0xef} },
+{ 0x0673,	16,	{0x6e, 0xff, 0x90, 0x01, 0x1c, 0xf0, 0xa3, 0xe0, 0x6f, 0xff, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0x6f} },
+{ 0x0683,	16,	{0xf0, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xe4, 0xfc, 0xfd, 0x75, 0x4f, 0x10, 0x75, 0x50, 0x02, 0x75} },
+{ 0x0693,	16,	{0x51, 0x12, 0x75, 0x52, 0xac, 0x12, 0x90, 0x15, 0x75, 0x49, 0x12, 0x75, 0x4a, 0xb2, 0x90, 0x01} },
+{ 0x06a3,	16,	{0x0d, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82} },
+{ 0x06b3,	16,	{0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70} },
+{ 0x06c3,	16,	{0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4} },
+{ 0x06d3,	16,	{0x54, 0x0f, 0x24, 0x41, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14} },
+{ 0x06e3,	16,	{0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x05, 0x4a, 0xe5, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x05, 0x49} },
+{ 0x06f3,	16,	{0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x75, 0x82, 0x10, 0x75, 0x83, 0x01, 0xe0, 0xfc, 0xa3} },
+{ 0x0703,	16,	{0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x90, 0x01, 0x18, 0x12, 0x9d, 0x25, 0x7e, 0x01} },
+{ 0x0713,	16,	{0x7f, 0x18, 0x12, 0x85, 0x08, 0x90, 0x01, 0x18, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
+{ 0x0723,	16,	{0xa3, 0xe0, 0xff, 0x75, 0x4f, 0x0a, 0x75, 0x50, 0x06, 0x75, 0x51, 0x12, 0x75, 0x52, 0xb8, 0x12} },
+{ 0x0733,	16,	{0x90, 0x15, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x53, 0x91, 0xef} },
+{ 0x0743,	16,	{0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x1f, 0xf0, 0xd2, 0xaf} },
+{ 0x0753,	16,	{0x20, 0x01, 0x2e, 0x20, 0x01, 0x2b, 0xa2, 0x03, 0x92, 0x07, 0x12, 0x09, 0xca, 0x75, 0x43, 0x50} },
+{ 0x0763,	16,	{0x75, 0x42, 0x6d, 0x75, 0x41, 0x33, 0x75, 0x40, 0x00, 0x20, 0x01, 0xe4, 0x7f, 0xff, 0x7e, 0xff} },
+{ 0x0773,	16,	{0x7d, 0xff, 0x7c, 0xff, 0x78, 0x40, 0x12, 0x9d, 0x0e, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0xd1, 0x80} },
+{ 0x0783,	16,	{0xe8, 0x30, 0x01, 0x05, 0x12, 0x03, 0x70, 0xc2, 0x01, 0x30, 0x06, 0x0d, 0x12, 0x0a, 0xed, 0x50} },
+{ 0x0793,	16,	{0x06, 0x12, 0x0b, 0x00, 0x12, 0x0a, 0xf2, 0xc2, 0x06, 0x12, 0x92, 0x38, 0x90, 0x01, 0xbd, 0xe0} },
+{ 0x07a3,	16,	{0x60, 0x10, 0x7e, 0x7b, 0x7f, 0x40, 0x12, 0x8e, 0xc1, 0xe4, 0x90, 0x01, 0xbd, 0xf0, 0x90, 0x7f} },
+{ 0x07b3,	16,	{0xd3, 0xf0, 0x90, 0x02, 0xaf, 0xe0, 0xb4, 0x0f, 0x03, 0x12, 0x95, 0x30, 0x12, 0x99, 0xcc, 0xe4} },
+{ 0x07c3,	16,	{0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x90, 0x01, 0xbc} },
+{ 0x07d3,	16,	{0xe0, 0x5e, 0x60, 0x14, 0x74, 0x27, 0x2f, 0xf8, 0xe6, 0xd3, 0x94, 0x0a, 0x40, 0x04, 0x7e, 0x01} },
+{ 0x07e3,	16,	{0x80, 0x02, 0x7e, 0x00, 0x8e, 0x48, 0x80, 0x03, 0x75, 0x48, 0x01, 0x74, 0x68, 0x2f, 0xf5, 0x82} },
+{ 0x07f3,	16,	{0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe5, 0x48, 0xf0, 0x0f, 0xbf, 0x04, 0xc5, 0xe5, 0x2b, 0xd3, 0x94} },
+{ 0x0803,	16,	{0x0a, 0x40, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x20, 0x6c, 0xef, 0xf0, 0x02, 0x07} },
+{ 0x0813,	1,	{0x84} },
+{ 0x0814,	1,	{0x22} },
+{ 0x0815,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x0819,	16,	{0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0829,	16,	{0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x09, 0x23, 0x90, 0x7f} },
+{ 0x0839,	16,	{0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x02, 0x7d, 0xff} },
+{ 0x0849,	16,	{0x12, 0x81, 0xe0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02} },
+{ 0x0859,	16,	{0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0} },
+{ 0x0869,	16,	{0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf} },
+{ 0x0879,	16,	{0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f} },
+{ 0x0889,	7,	{0x32, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x22} },
+{ 0x0890,	16,	{0x90, 0x7f, 0x96, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x80, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12} },
+{ 0x08a0,	16,	{0x09, 0x23, 0x7f, 0x02, 0xe4, 0xfd, 0x12, 0x81, 0xe0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23} },
+{ 0x08b0,	16,	{0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f} },
+{ 0x08c0,	16,	{0x96, 0xe0, 0x44, 0x04, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0} },
+{ 0x08d0,	16,	{0x54, 0xf7, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x01} },
+{ 0x08e0,	12,	{0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x12, 0x0b, 0x00, 0x22} },
+{ 0x08ec,	16,	{0x90, 0x11, 0xfc, 0xe4, 0x93, 0x70, 0x2f, 0x90, 0x7f, 0x93, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x94} },
+{ 0x08fc,	16,	{0x74, 0x3c, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc6, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x7f} },
+{ 0x090c,	16,	{0x9d, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0xe2, 0x74, 0x12, 0xf0, 0x12, 0x08, 0x19, 0x75, 0x82, 0xfc} },
+{ 0x091c,	7,	{0x75, 0x83, 0x11, 0x74, 0xff, 0xf0, 0x22} },
+{ 0x0923,	16,	{0x8e, 0x58, 0x8f, 0x59, 0xe5, 0x59, 0x15, 0x59, 0xae, 0x58, 0x70, 0x02, 0x15, 0x58, 0x4e, 0x60} },
+{ 0x0933,	7,	{0x05, 0x12, 0x09, 0xef, 0x80, 0xee, 0x22} },
+{ 0x093a,	2,	{0x8f, 0x4c} },
+{ 0x093c,	16,	{0xe4, 0xf5, 0x4d, 0x75, 0x4e, 0xff, 0x75, 0x4f, 0x12, 0x75, 0x50, 0x6a, 0xab, 0x4e, 0xaa, 0x4f} },
+{ 0x094c,	16,	{0xa9, 0x50, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0xb4, 0x03, 0x1d, 0xaf, 0x4d, 0x05, 0x4d, 0xef} },
+{ 0x095c,	16,	{0xb5, 0x4c, 0x01, 0x22, 0x12, 0x9b, 0x72, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x096c,	14,	{0x4e, 0xff, 0xf5, 0x4f, 0x89, 0x50, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x097a,	1,	{0x22} },
+{ 0x097b,	16,	{0xe4, 0xfe, 0x75, 0x4e, 0xff, 0x75, 0x4f, 0x12, 0x75, 0x50, 0x12, 0xab, 0x4e, 0xaa, 0x4f, 0xa9} },
+{ 0x098b,	16,	{0x50, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x099b,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x9b, 0xe4, 0x85, 0xf0, 0x4c, 0xf5, 0x4d, 0x62, 0x4c} },
+{ 0x09ab,	16,	{0xe5, 0x4c, 0x62, 0x4d, 0xe5, 0x4d, 0x62, 0x4c, 0x29, 0xfd, 0xe5, 0x4c, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x09bb,	14,	{0x4e, 0xff, 0xf5, 0x4f, 0x89, 0x50, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x09c9,	1,	{0x22} },
+{ 0x09ca,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x07, 0x04, 0xe0, 0x44} },
+{ 0x09da,	16,	{0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x09, 0x23, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x09ea,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x09ef,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x09ff,	1,	{0x22} },
+{ 0x0a00,	16,	{0x02, 0x0b, 0xaa, 0x00, 0x02, 0x0b, 0xdd, 0x00, 0x02, 0x0b, 0xc2, 0x00, 0x02, 0x0c, 0x1c, 0x00} },
+{ 0x0a10,	16,	{0x02, 0x0c, 0x06, 0x00, 0x02, 0x0a, 0xf7, 0x00, 0x02, 0x0a, 0xf8, 0x00, 0x02, 0x0a, 0xf9, 0x00} },
+{ 0x0a20,	16,	{0x02, 0x0c, 0x37, 0x00, 0x02, 0x0d, 0x27, 0x00, 0x02, 0x0c, 0x73, 0x00, 0x02, 0x0d, 0x7b, 0x00} },
+{ 0x0a30,	16,	{0x02, 0x0c, 0xaf, 0x00, 0x02, 0x0d, 0xcf, 0x00, 0x02, 0x0c, 0xeb, 0x00, 0x02, 0x0e, 0x23, 0x00} },
+{ 0x0a40,	16,	{0x02, 0x0a, 0xfa, 0x00, 0x02, 0x0a, 0xfc, 0x00, 0x02, 0x0a, 0xfb, 0x00, 0x02, 0x0a, 0xfd, 0x00} },
+{ 0x0a50,	8,	{0x02, 0x0e, 0x77, 0x00, 0x02, 0x0e, 0x8d, 0x00} },
+{ 0x0a58,	16,	{0x53, 0x8e, 0xf7, 0xe5, 0x89, 0x54, 0xf1, 0x44, 0x01, 0xf5, 0x89, 0x75, 0x8c, 0xb1, 0xd2, 0xa9} },
+{ 0x0a68,	16,	{0x75, 0x98, 0x40, 0x75, 0xcb, 0xff, 0x75, 0xca, 0xf3, 0x75, 0xc8, 0x34, 0xe4, 0xff, 0x7f, 0x05} },
+{ 0x0a78,	7,	{0x78, 0x27, 0xe4, 0xf6, 0x08, 0xdf, 0xfc} },
+{ 0x0a7f,	1,	{0x22} },
+{ 0x0a80,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x06, 0xc0} },
+{ 0x0a90,	1,	{0x07} },
+{ 0x0a91,	16,	{0x30, 0x04, 0x16, 0x75, 0x8c, 0xf8, 0x75, 0x8a, 0x30, 0x7f, 0x2f, 0xae, 0x07, 0x1f, 0xee, 0x60} },
+{ 0x0aa1,	16,	{0x3c, 0x90, 0x20, 0x00, 0x74, 0x55, 0xf0, 0x80, 0xf2, 0x75, 0x8c, 0xb1, 0x7f, 0x27, 0xef, 0xd3} },
+{ 0x0ab1,	16,	{0x94, 0x2b, 0x50, 0x09, 0xa8, 0x07, 0xe6, 0x60, 0x01, 0x16, 0x0f, 0x80, 0xf1, 0x90, 0x03, 0x00} },
+{ 0x0ac1,	16,	{0xe0, 0x60, 0x02, 0x14, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x0e, 0x90} },
+{ 0x0ad1,	13,	{0x01, 0xc1, 0xe0, 0x24, 0xff, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x34, 0xff, 0xf0} },
+{ 0x0ade,	15,	{0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0aed,	5,	{0x12, 0x08, 0x90, 0xd3, 0x22} },
+{ 0x0af2,	5,	{0x12, 0x08, 0x19, 0xd3, 0x22} },
+{ 0x0af7,	1,	{0x32} },
+{ 0x0af8,	1,	{0x32} },
+{ 0x0af9,	1,	{0x32} },
+{ 0x0afa,	1,	{0x32} },
+{ 0x0afb,	1,	{0x32} },
+{ 0x0afc,	1,	{0x32} },
+{ 0x0afd,	1,	{0x32} },
+{ 0x0b00,	9,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x0b7d,	16,	{0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x0b8d,	16,	{0xd2, 0x00, 0x75, 0x8e, 0x10, 0xe4, 0x90, 0x7f, 0x92, 0xf0, 0x12, 0x10, 0x0c, 0x12, 0x08, 0xec} },
+{ 0x0b9d,	13,	{0x12, 0x0e, 0xa9, 0x12, 0x90, 0xe6, 0x12, 0x1b, 0x0c, 0x12, 0x0a, 0x58, 0x22} },
+{ 0x0baa,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0bba,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0bc2,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0bd2,	11,	{0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0bdd,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0x90} },
+{ 0x0bed,	16,	{0x7f, 0xd8, 0xe0, 0x70, 0x0d, 0x90, 0x7f, 0xd9, 0xe0, 0x70, 0x07, 0xe5, 0x2b, 0x70, 0x03, 0x75} },
+{ 0x0bfd,	9,	{0x2b, 0x14, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c06,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0c16,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c1c,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x30, 0x02, 0x02, 0xd2, 0x06, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c2c,	11,	{0xab, 0x74, 0x08, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c37,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c47,	16,	{0xa9, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x30, 0xe0, 0x13, 0xe5, 0x3b, 0x30, 0xe0, 0x07, 0x90, 0x20} },
+{ 0x0c57,	16,	{0x04, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0c67,	12,	{0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c73,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c83,	16,	{0xa9, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x30, 0xe1, 0x13, 0xe5, 0x3b, 0x30, 0xe1, 0x07, 0x90, 0x20} },
+{ 0x0c93,	16,	{0x0c, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0ca3,	12,	{0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0caf,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0cbf,	16,	{0xa9, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x30, 0xe2, 0x13, 0xe5, 0x3b, 0x30, 0xe2, 0x07, 0x90, 0x20} },
+{ 0x0ccf,	16,	{0x14, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0cdf,	12,	{0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0ceb,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0cfb,	16,	{0xa9, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x30, 0xe3, 0x13, 0xe5, 0x3b, 0x30, 0xe3, 0x07, 0x90, 0x20} },
+{ 0x0d0b,	16,	{0x1c, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0d1b,	12,	{0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d27,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0d37,	16,	{0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0d47,	16,	{0xe0, 0x06, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x90, 0x7f, 0xc7} },
+{ 0x0d57,	16,	{0xe0, 0x90, 0x02, 0xf8, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0d67,	16,	{0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0d77,	4,	{0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d7b,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0d8b,	16,	{0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0d9b,	16,	{0xe1, 0x06, 0x90, 0x7f, 0xc9, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x90, 0x7f, 0xc9} },
+{ 0x0dab,	16,	{0xe0, 0x90, 0x02, 0xf9, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0dbb,	16,	{0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0dcb,	4,	{0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dcf,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0ddf,	16,	{0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0def,	16,	{0xe2, 0x06, 0x90, 0x7f, 0xcb, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x90, 0x7f, 0xcb} },
+{ 0x0dff,	16,	{0xe0, 0x90, 0x02, 0xfa, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0e0f,	16,	{0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0e1f,	4,	{0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e23,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0e33,	16,	{0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0e43,	16,	{0xe3, 0x06, 0x90, 0x7f, 0xcd, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x90, 0x7f, 0xcd} },
+{ 0x0e53,	16,	{0xe0, 0x90, 0x02, 0xfb, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0e63,	16,	{0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0e73,	4,	{0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e77,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x80, 0xf0, 0xd0} },
+{ 0x0e87,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e8d,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x80, 0xf0, 0x90} },
+{ 0x0e9d,	12,	{0x01, 0xbd, 0x74, 0xff, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0ea9,	16,	{0x90, 0x01, 0x20, 0x12, 0x9d, 0x31, 0x00, 0x00, 0x25, 0x80, 0x90, 0x01, 0x24, 0x74, 0x08, 0xf0} },
+{ 0x0eb9,	16,	{0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x6e, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x13, 0xf0, 0xa3, 0x74} },
+{ 0x0ec9,	16,	{0x11, 0xf0, 0xe4, 0xa3, 0xf0, 0xa3, 0xf0, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff} },
+{ 0x0ed9,	16,	{0xc3, 0x94, 0x04, 0x50, 0x13, 0xef, 0x04, 0xa3, 0xf0, 0x7e, 0x01, 0x7f, 0x1f, 0x12, 0x85, 0xe1} },
+{ 0x0ee9,	16,	{0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xe3, 0xe4, 0xf5, 0x26, 0x90, 0x01, 0x1e, 0xf0, 0x90} },
+{ 0x0ef9,	16,	{0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50, 0x1a, 0x74, 0xf8, 0x2f, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0f09,	16,	{0x02, 0xf5, 0x83, 0xe4, 0xf0, 0x74, 0x22, 0x2f, 0xf8, 0xe4, 0xf6, 0x90, 0x01, 0x1e, 0xe0, 0x04} },
+{ 0x0f19,	16,	{0xf0, 0x80, 0xdc, 0xe4, 0xf5, 0x30, 0xe5, 0xc0, 0x60, 0x2f, 0x90, 0x01, 0x1e, 0x74, 0x01, 0xf0} },
+{ 0x0f29,	16,	{0x90, 0x01, 0x1e, 0xe0, 0xff, 0xd3, 0x94, 0x04, 0x50, 0x1f, 0xef, 0x14, 0xff, 0x74, 0x01, 0xa8} },
+{ 0x0f39,	16,	{0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x30, 0x7e, 0x01, 0x7f, 0x1e, 0x12, 0x83} },
+{ 0x0f49,	16,	{0x5f, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xd7, 0xe4, 0xf5, 0x3a, 0x90, 0x01, 0x1e, 0xf0} },
+{ 0x0f59,	16,	{0x90, 0x01, 0x1e, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20} },
+{ 0x0f69,	16,	{0xf5, 0x83, 0xe0, 0x54, 0xf0, 0xfe, 0x74, 0xc5, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83} },
+{ 0x0f79,	16,	{0xee, 0xf0, 0x74, 0x36, 0x2f, 0xf8, 0xa6, 0x06, 0x74, 0x32, 0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0x2c} },
+{ 0x0f89,	16,	{0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0xfc, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0} },
+{ 0x0f99,	16,	{0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0xe0, 0xb4, 0x04, 0xb6, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f} },
+{ 0x0fa9,	16,	{0xf5, 0x4b, 0x60, 0x5e, 0xe4, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94} },
+{ 0x0fb9,	16,	{0x04, 0x50, 0xe7, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x55, 0x4b} },
+{ 0x0fc9,	16,	{0x60, 0x38, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4} },
+{ 0x0fd9,	16,	{0x34, 0x20, 0xf5, 0x83, 0xe0, 0xfe, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4} },
+{ 0x0fe9,	16,	{0x34, 0x20, 0xf5, 0x83, 0xe0, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0ff9,	16,	{0x20, 0xf5, 0x83, 0xe0, 0xfe, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0} },
+{ 0x1009,	3,	{0x80, 0xa7, 0x22} },
+{ 0x100c,	16,	{0x7b, 0xff, 0x7a, 0x12, 0x79, 0x1b, 0x90, 0x00, 0x04, 0x12, 0x9b, 0x8b, 0xfd, 0x8b, 0x4d, 0x75} },
+{ 0x101c,	16,	{0x4e, 0x12, 0x75, 0x4f, 0x24, 0xe4, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x7f, 0xe0, 0xf0, 0xf5, 0x4b} },
+{ 0x102c,	16,	{0xf5, 0x4c, 0x90, 0x02, 0xae, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f} },
+{ 0x103c,	16,	{0xa9, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0xe4, 0xfc, 0xec, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
+{ 0x104c,	16,	{0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x0c, 0xbc, 0x10, 0xee, 0xe4, 0x90, 0x7f, 0xdd} },
+{ 0x105c,	16,	{0xf0, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03, 0x02, 0x11, 0xd2, 0xab, 0x4d, 0xaa, 0x4e, 0xa9, 0x4f} },
+{ 0x106c,	16,	{0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0x64, 0x05, 0x60, 0x03, 0x02, 0x11, 0xc1, 0x90, 0x00, 0x03} },
+{ 0x107c,	16,	{0x12, 0x9b, 0x8b, 0x64, 0x01, 0x60, 0x03, 0x02, 0x11, 0x48, 0x90, 0x00, 0x02, 0x12, 0x9b, 0x8b} },
+{ 0x108c,	16,	{0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x11, 0x22, 0xec, 0xc3, 0x94, 0x10} },
+{ 0x109c,	16,	{0x40, 0x03, 0x02, 0x11, 0x22, 0xef, 0x30, 0xe7, 0x42, 0xe5, 0x4c, 0xae, 0x4b, 0x78, 0x02, 0xce} },
+{ 0x10ac,	16,	{0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xf0, 0x2c, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5} },
+{ 0x10bc,	16,	{0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe0, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01, 0xa8, 0x06} },
+{ 0x10cc,	16,	{0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe0, 0xf0, 0x90, 0x02, 0xae, 0xe0} },
+{ 0x10dc,	16,	{0x04, 0xf0, 0x90, 0x7f, 0xdd, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x3e, 0xe5, 0x4c, 0xae, 0x4b, 0x78} },
+{ 0x10ec,	16,	{0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xe8, 0x2c, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x10fc,	16,	{0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe1, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01} },
+{ 0x110c,	16,	{0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x02} },
+{ 0x111c,	16,	{0xae, 0xe0, 0x04, 0xf0, 0x80, 0x03, 0x7f, 0xff, 0x22, 0x90, 0x00, 0x04, 0x12, 0x9b, 0x8b, 0x25} },
+{ 0x112c,	16,	{0x4c, 0xf5, 0x4c, 0xe4, 0x35, 0x4b, 0xf5, 0x4b, 0x90, 0x00, 0x05, 0x12, 0x9b, 0x8b, 0xfe, 0xe4} },
+{ 0x113c,	16,	{0x25, 0x4c, 0xf5, 0x4c, 0xee, 0x35, 0x4b, 0xf5, 0x4b, 0x02, 0x11, 0xc4, 0xab, 0x4d, 0xaa, 0x4e} },
+{ 0x114c,	16,	{0xa9, 0x4f, 0x90, 0x00, 0x03, 0x12, 0x9b, 0x8b, 0xff, 0x64, 0x02, 0x60, 0x05, 0xef, 0x64, 0x03} },
+{ 0x115c,	16,	{0x70, 0x60, 0x90, 0x00, 0x02, 0x12, 0x9b, 0x8b, 0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50} },
+{ 0x116c,	16,	{0x4e, 0xef, 0x30, 0xe7, 0x1e, 0x90, 0x7f, 0xde, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80} },
+{ 0x117c,	16,	{0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x4e} },
+{ 0x118c,	16,	{0xf0, 0x80, 0x35, 0x90, 0x7f, 0xdf, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80, 0x02, 0xc3} },
+{ 0x119c,	16,	{0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xad, 0xe0, 0x4e, 0xf0, 0xec} },
+{ 0x11ac,	16,	{0x25, 0xe0, 0x24, 0xc5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x80, 0x09, 0x7f} },
+{ 0x11bc,	16,	{0xff, 0x22, 0x7f, 0xff, 0x22, 0x7f, 0xff, 0x22, 0x74, 0x07, 0x25, 0x4f, 0xf5, 0x4f, 0xe4, 0x35} },
+{ 0x11cc,	16,	{0x4e, 0xf5, 0x4e, 0x02, 0x10, 0x5d, 0x20, 0x03, 0x0d, 0x90, 0x02, 0xae, 0xe0, 0x60, 0x07, 0x90} },
+{ 0x11dc,	8,	{0x7f, 0xae, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0x00} },
+{ 0x11e4,	1,	{0x22} },
+{ 0x11e5,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33} },
+{ 0x11f5,	7,	{0xd8, 0xfc, 0x42, 0x3a, 0x7f, 0x00, 0x22} },
+{ 0x11fc,	3,	{0x00, 0x03, 0x15} },
+{ 0x1200,	16,	{0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40, 0x10, 0x07, 0x01, 0x80, 0x42, 0x00, 0x01, 0x02} },
+{ 0x1210,	16,	{0x03, 0x01, 0x09, 0x02, 0x58, 0x00, 0x01, 0x01, 0x04, 0x80, 0x3c, 0x09, 0x04, 0x00, 0x00, 0x0a} },
+{ 0x1220,	16,	{0xff, 0xff, 0xff, 0x05, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40} },
+{ 0x1230,	16,	{0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00} },
+{ 0x1240,	16,	{0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x1250,	16,	{0x84, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x87, 0x02} },
+{ 0x1260,	16,	{0x40, 0x00, 0x00, 0x07, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x24, 0x03} },
+{ 0x1270,	16,	{0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x20, 0x00} },
+{ 0x1280,	16,	{0x54, 0x00, 0x65, 0x00, 0x63, 0x00, 0x68, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
+{ 0x1290,	16,	{0x2e, 0x00, 0x18, 0x03, 0x57, 0x00, 0x68, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, 0x00, 0x48, 0x00} },
+{ 0x12a0,	16,	{0x45, 0x00, 0x41, 0x00, 0x54, 0x00, 0x2d, 0x00, 0x34, 0x00, 0x1a, 0x03, 0x58, 0x00, 0x58, 0x00} },
+{ 0x12b0,	16,	{0x2d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x2d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00} },
+{ 0x12c0,	16,	{0x58, 0x00, 0x58, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
+{ 0x12d0,	16,	{0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
+{ 0x12e0,	16,	{0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
+{ 0x12f0,	16,	{0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
+{ 0x1300,	16,	{0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
+{ 0x1310,	2,	{0x00, 0x00} },
+{ 0x1312,	16,	{0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0xc0, 0xd0} },
+{ 0x1322,	16,	{0x75, 0x86, 0x00, 0x75, 0xd0, 0x18, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xf5, 0xf0, 0x70, 0x11} },
+{ 0x1332,	16,	{0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0} },
+{ 0x1342,	16,	{0x32, 0x75, 0x86, 0x00, 0x10, 0xf0, 0x0b, 0x10, 0xf1, 0x12, 0x10, 0xf2, 0x19, 0x10, 0xf3, 0x20} },
+{ 0x1352,	16,	{0x80, 0xd4, 0xe5, 0x27, 0x70, 0x03, 0x75, 0x27, 0x14, 0x02, 0x13, 0x7c, 0xe5, 0x28, 0x70, 0x03} },
+{ 0x1362,	16,	{0x75, 0x28, 0x14, 0x02, 0x15, 0x0d, 0xe5, 0x29, 0x70, 0x03, 0x75, 0x29, 0x14, 0x02, 0x16, 0x9e} },
+{ 0x1372,	16,	{0xe5, 0x2a, 0x70, 0x03, 0x75, 0x2a, 0x14, 0x02, 0x18, 0x2f, 0x90, 0x20, 0x02, 0xe0, 0x54, 0x3f} },
+{ 0x1382,	16,	{0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14, 0x60, 0x09, 0x02, 0x13} },
+{ 0x1392,	16,	{0x43, 0x02, 0x14, 0x65, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5, 0x36, 0x02, 0x13, 0x43} },
+{ 0x13a2,	16,	{0x43, 0x82, 0x04, 0xe0, 0x43, 0x2c, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x05} },
+{ 0x13b2,	16,	{0xe0, 0x42, 0x32, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13, 0x43, 0x30, 0xe1, 0x02} },
+{ 0x13c2,	16,	{0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x04, 0xe0} },
+{ 0x13d2,	16,	{0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74, 0x00, 0xf0, 0x90, 0x20} },
+{ 0x13e2,	16,	{0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86} },
+{ 0x13f2,	16,	{0x90, 0x7e, 0x80, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f} },
+{ 0x1402,	16,	{0xe5, 0xe5, 0x3c, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0} },
+{ 0x1412,	16,	{0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x90} },
+{ 0x1422,	16,	{0x7f, 0xb7, 0xed, 0xf0, 0x90, 0x20, 0x01, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x7f, 0x40} },
+{ 0x1432,	16,	{0x90, 0x7e, 0x80, 0x05, 0x86, 0x90, 0x20, 0x00, 0xe5, 0x84, 0xfe, 0x24, 0x05, 0xfd, 0x8d, 0x84} },
+{ 0x1442,	16,	{0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xef, 0x05} },
+{ 0x1452,	16,	{0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xb7, 0xf0, 0x05, 0x86, 0xa3, 0xe0, 0x54, 0xfe, 0xf0} },
+{ 0x1462,	16,	{0x02, 0x13, 0x43, 0x53, 0x2c, 0xfa, 0xe5, 0x22, 0x60, 0x08, 0x75, 0x22, 0x00, 0xd2, 0xe7, 0xfe} },
+{ 0x1472,	16,	{0x80, 0x0a, 0x90, 0x7f, 0xc7, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x14, 0xff, 0x90, 0x20, 0x50, 0x74} },
+{ 0x1482,	16,	{0x00, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
+{ 0x1492,	16,	{0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7e, 0x40, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0} },
+{ 0x14a2,	16,	{0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0, 0x24, 0x38, 0xf0, 0x05} },
+{ 0x14b2,	16,	{0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60, 0x30, 0x03, 0x03, 0x03} },
+{ 0x14c2,	16,	{0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0} },
+{ 0x14d2,	16,	{0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11, 0x8b, 0x22, 0x90, 0x7f} },
+{ 0x14e2,	16,	{0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80, 0x1b, 0xe0, 0xde, 0xfd} },
+{ 0x14f2,	16,	{0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x90, 0x20, 0x01} },
+{ 0x1502,	16,	{0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xc7, 0xf0, 0x02, 0x13, 0x43, 0x90, 0x20, 0x0a, 0xe0, 0x54} },
+{ 0x1512,	16,	{0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14, 0x60, 0x09, 0x02} },
+{ 0x1522,	16,	{0x13, 0x43, 0x02, 0x15, 0xf6, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5, 0x37, 0x02, 0x13} },
+{ 0x1532,	16,	{0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2d, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82, 0xf8, 0x43, 0x82} },
+{ 0x1542,	16,	{0x05, 0xe0, 0x42, 0x33, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13, 0x43, 0x30, 0xe1} },
+{ 0x1552,	16,	{0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x04} },
+{ 0x1562,	16,	{0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74, 0x01, 0xf0, 0x90} },
+{ 0x1572,	16,	{0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05} },
+{ 0x1582,	16,	{0x86, 0x90, 0x7e, 0x00, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90} },
+{ 0x1592,	16,	{0x7f, 0xe5, 0xe5, 0x3d, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0} },
+{ 0x15a2,	16,	{0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
+{ 0x15b2,	16,	{0x90, 0x7f, 0xb9, 0xed, 0xf0, 0x90, 0x20, 0x09, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x7f} },
+{ 0x15c2,	16,	{0x40, 0x90, 0x7e, 0x00, 0x05, 0x86, 0x90, 0x20, 0x08, 0xe5, 0x84, 0xfe, 0x24, 0x05, 0xfd, 0x8d} },
+{ 0x15d2,	16,	{0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xef} },
+{ 0x15e2,	16,	{0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xb9, 0xf0, 0x05, 0x86, 0xa3, 0xe0, 0x54, 0xfe} },
+{ 0x15f2,	16,	{0xf0, 0x02, 0x13, 0x43, 0x53, 0x2d, 0xfa, 0xe5, 0x23, 0x60, 0x08, 0x75, 0x23, 0x00, 0xd2, 0xe7} },
+{ 0x1602,	16,	{0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xc9, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x16, 0x90, 0x90, 0x20, 0x50} },
+{ 0x1612,	16,	{0x74, 0x01, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0} },
+{ 0x1622,	16,	{0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0xc0, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84} },
+{ 0x1632,	16,	{0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0, 0x24, 0x38, 0xf0} },
+{ 0x1642,	16,	{0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60, 0x30, 0x03, 0x03} },
+{ 0x1652,	16,	{0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0} },
+{ 0x1662,	16,	{0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11, 0x8b, 0x23, 0x90} },
+{ 0x1672,	16,	{0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80, 0x1b, 0xe0, 0xde} },
+{ 0x1682,	14,	{0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
+{ 0x1690,	16,	{0x90, 0x20, 0x09, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x02, 0x13, 0x43, 0x90, 0x20} },
+{ 0x16a0,	16,	{0x12, 0xe0, 0x54, 0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14} },
+{ 0x16b0,	16,	{0x60, 0x09, 0x02, 0x13, 0x43, 0x02, 0x17, 0x87, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5} },
+{ 0x16c0,	16,	{0x38, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2e, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82} },
+{ 0x16d0,	16,	{0xf8, 0x43, 0x82, 0x05, 0xe0, 0x42, 0x34, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13} },
+{ 0x16e0,	16,	{0x43, 0x30, 0xe1, 0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x53, 0x82, 0xf8} },
+{ 0x16f0,	16,	{0x43, 0x82, 0x04, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74} },
+{ 0x1700,	16,	{0x02, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
+{ 0x1710,	16,	{0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x80, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0} },
+{ 0x1720,	16,	{0x05, 0x86, 0x90, 0x7f, 0xe5, 0xe5, 0x3e, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0} },
+{ 0x1730,	16,	{0xf0, 0xf0, 0xf0, 0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58} },
+{ 0x1740,	16,	{0x74, 0x00, 0xf0, 0x90, 0x7f, 0xbb, 0xed, 0xf0, 0x90, 0x20, 0x11, 0xe0, 0x54, 0xfe, 0xf0, 0x02} },
+{ 0x1750,	16,	{0x13, 0x43, 0x7f, 0x40, 0x90, 0x7d, 0x80, 0x05, 0x86, 0x90, 0x20, 0x10, 0xe5, 0x84, 0xfe, 0x24} },
+{ 0x1760,	16,	{0x05, 0xfd, 0x8d, 0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05} },
+{ 0x1770,	16,	{0x86, 0xdf, 0xef, 0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xbb, 0xf0, 0x05, 0x86, 0xa3} },
+{ 0x1780,	16,	{0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x53, 0x2e, 0xfa, 0xe5, 0x24, 0x60, 0x08, 0x75, 0x24} },
+{ 0x1790,	16,	{0x00, 0xd2, 0xe7, 0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x18, 0x21} },
+{ 0x17a0,	16,	{0x90, 0x20, 0x50, 0x74, 0x02, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0} },
+{ 0x17b0,	16,	{0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x40, 0x05, 0x86, 0xe5, 0x85, 0xf0} },
+{ 0x17c0,	16,	{0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0} },
+{ 0x17d0,	16,	{0x24, 0x38, 0xf0, 0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60} },
+{ 0x17e0,	16,	{0x30, 0x03, 0x03, 0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0} },
+{ 0x17f0,	16,	{0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11} },
+{ 0x1800,	16,	{0x8b, 0x24, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80} },
+{ 0x1810,	16,	{0x1b, 0xe0, 0xde, 0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00} },
+{ 0x1820,	16,	{0xf0, 0x90, 0x20, 0x11, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xcb, 0xf0, 0x02, 0x13, 0x43, 0x90} },
+{ 0x1830,	16,	{0x20, 0x1a, 0xe0, 0x54, 0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5} },
+{ 0x1840,	16,	{0x14, 0x60, 0x09, 0x02, 0x13, 0x43, 0x02, 0x19, 0x18, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0} },
+{ 0x1850,	16,	{0xf5, 0x39, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2f, 0x01, 0x02, 0x13, 0x43, 0x53} },
+{ 0x1860,	16,	{0x82, 0xf8, 0x43, 0x82, 0x05, 0xe0, 0x42, 0x35, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02} },
+{ 0x1870,	16,	{0x13, 0x43, 0x30, 0xe1, 0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x53, 0x82} },
+{ 0x1880,	16,	{0xf8, 0x43, 0x82, 0x04, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50} },
+{ 0x1890,	16,	{0x74, 0x03, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0} },
+{ 0x18a0,	16,	{0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x00, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84} },
+{ 0x18b0,	16,	{0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xe5, 0x3f, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0} },
+{ 0x18c0,	16,	{0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20} },
+{ 0x18d0,	16,	{0x58, 0x74, 0x00, 0xf0, 0x90, 0x7f, 0xbd, 0xed, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x54, 0xfe, 0xf0} },
+{ 0x18e0,	16,	{0x02, 0x13, 0x43, 0x7f, 0x40, 0x90, 0x7d, 0x00, 0x05, 0x86, 0x90, 0x20, 0x18, 0xe5, 0x84, 0xfe} },
+{ 0x18f0,	16,	{0x24, 0x05, 0xfd, 0x8d, 0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3} },
+{ 0x1900,	16,	{0x05, 0x86, 0xdf, 0xef, 0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xbd, 0xf0, 0x05, 0x86} },
+{ 0x1910,	16,	{0xa3, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x53, 0x2f, 0xfa, 0xe5, 0x25, 0x60, 0x08, 0x75} },
+{ 0x1920,	16,	{0x25, 0x00, 0xd2, 0xe7, 0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x19} },
+{ 0x1930,	16,	{0xb2, 0x90, 0x20, 0x50, 0x74, 0x03, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2} },
+{ 0x1940,	16,	{0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7c, 0xc0, 0x05, 0x86, 0xe5, 0x85} },
+{ 0x1950,	16,	{0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86} },
+{ 0x1960,	16,	{0xe0, 0x24, 0x38, 0xf0, 0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78} },
+{ 0x1970,	16,	{0x60, 0x30, 0x03, 0x03, 0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0} },
+{ 0x1980,	16,	{0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70} },
+{ 0x1990,	16,	{0x11, 0x8b, 0x25, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
+{ 0x19a0,	16,	{0x80, 0x1b, 0xe0, 0xde, 0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74} },
+{ 0x19b0,	16,	{0x00, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xcd, 0xf0, 0x02, 0x13, 0x43} },
+{ 0x19c0,	1,	{0x32} },
+{ 0x19c1,	4,	{0xad, 0x07, 0xac, 0x06} },
+{ 0x19c5,	16,	{0x79, 0x06, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb} },
+{ 0x19d5,	16,	{0x4a, 0x70, 0x03, 0x02, 0x1b, 0x09, 0xe9, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x1a, 0xdb, 0x90} },
+{ 0x19e5,	16,	{0x19, 0xeb, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x1a, 0xb9, 0x02, 0x1a, 0x71, 0x02, 0x1a, 0x5a, 0x02} },
+{ 0x19f5,	16,	{0x1a, 0x40, 0x02, 0x1a, 0x2f, 0x02, 0x1a, 0x1a, 0x02, 0x1a, 0x00, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x1a05,	16,	{0x80, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6} },
+{ 0x1a15,	16,	{0xf0, 0x19, 0x02, 0x1a, 0xdb, 0x19, 0x8d, 0x82, 0x8c, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x0a} },
+{ 0x1a25,	16,	{0xa3, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x02, 0x1a, 0xdb, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
+{ 0x1a35,	16,	{0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x19, 0x02, 0x1a, 0xdb, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x1a45,	16,	{0x80, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa1, 0x90, 0x7f, 0xa6} },
+{ 0x1a55,	16,	{0xf0, 0x19, 0x02, 0x1a, 0xdb, 0xeb, 0x64, 0x01, 0x4a, 0x70, 0x08, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x1a65,	16,	{0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xf5, 0x54, 0x19, 0x80, 0x6a, 0xed, 0x24, 0x04, 0xf5} },
+{ 0x1a75,	16,	{0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0x64, 0x02, 0x4e, 0x70, 0x08, 0x90, 0x7f} },
+{ 0x1a85,	16,	{0xa5, 0xe0, 0x44, 0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xff, 0xed, 0x24, 0x06, 0xf5, 0x82} },
+{ 0x1a95,	16,	{0xe4, 0x3c, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
+{ 0x1aa5,	16,	{0xef, 0xf0, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12} },
+{ 0x1ab5,	16,	{0x9b, 0xb8, 0x80, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xff} },
+{ 0x1ac5,	16,	{0xed, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfa, 0xa3, 0xe0, 0xf5, 0x82, 0x8a} },
+{ 0x1ad5,	16,	{0x83, 0xef, 0xf0, 0x7f, 0x08, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x54, 0x30, 0xe0, 0xf7, 0x30} },
+{ 0x1ae5,	16,	{0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xe9, 0xd3, 0x94, 0x02, 0x50, 0x03, 0x02} },
+{ 0x1af5,	16,	{0x19, 0xc7, 0xe5, 0x54, 0x30, 0xe1, 0x03, 0x02, 0x19, 0xc7, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40} },
+{ 0x1b05,	6,	{0xf0, 0x7f, 0x07, 0x22, 0x7f, 0x08} },
+{ 0x1b0b,	1,	{0x22} },
+{ 0x1b0c,	16,	{0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x02, 0x7d, 0xff, 0x12, 0x81, 0xe0, 0x7f, 0x05} },
+{ 0x1b1c,	13,	{0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x03, 0x7d, 0xff, 0x12, 0x81, 0xe0, 0x22} },
+{ 0x1b29,	16,	{0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0} },
+{ 0x8000,	4,	{0x8e, 0x54, 0x8f, 0x55} },
+{ 0x8004,	16,	{0x75, 0x56, 0x03, 0xe5, 0x55, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xfe} },
+{ 0x8014,	16,	{0xa3, 0xe0, 0x4e, 0x70, 0x03, 0x02, 0x81, 0x0e, 0xe5, 0x56, 0x60, 0x4e, 0x14, 0x60, 0x38, 0x14} },
+{ 0x8024,	16,	{0x60, 0x20, 0x14, 0x60, 0x03, 0x02, 0x80, 0xb2, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
+{ 0x8034,	16,	{0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6, 0xf0} },
+{ 0x8044,	16,	{0x80, 0x6c, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x09, 0xa3, 0xa3} },
+{ 0x8054,	16,	{0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x57, 0x15, 0x56, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3} },
+{ 0x8064,	16,	{0xa3, 0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x44, 0xe5, 0x55, 0x24, 0x06, 0xf5, 0x82} },
+{ 0x8074,	16,	{0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5} },
+{ 0x8084,	16,	{0x83, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe5, 0x55, 0x24} },
+{ 0x8094,	16,	{0x04, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12, 0x9b, 0xb8, 0x85} },
+{ 0x80a4,	16,	{0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xb8, 0x90, 0x7f} },
+{ 0x80b4,	16,	{0xa5, 0xe0, 0xf5, 0x57, 0x30, 0xe0, 0xf7, 0x30, 0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06} },
+{ 0x80c4,	16,	{0x22, 0xe5, 0x57, 0x20, 0xe1, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22} },
+{ 0x80d4,	16,	{0xe5, 0x56, 0x70, 0x31, 0x7f, 0x01, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x80e4,	16,	{0x80, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90} },
+{ 0x80f4,	16,	{0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x57, 0x30, 0xe0, 0xf7, 0x30, 0xe1, 0xd5, 0x75} },
+{ 0x8104,	12,	{0x56, 0x03, 0x02, 0x80, 0x07, 0x15, 0x56, 0x02, 0x80, 0x07, 0x7f, 0x08} },
+{ 0x8110,	1,	{0x22} },
+{ 0x8111,	2,	{0xac, 0x07} },
+{ 0x8113,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xec, 0x25, 0xe0, 0x44, 0x41, 0x90, 0x7f, 0xa6, 0xf0} },
+{ 0x8123,	16,	{0x7b, 0x3c, 0xaf, 0x03, 0x1b, 0xef, 0x70, 0x16, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
+{ 0x8133,	16,	{0x7f, 0xa6, 0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x60, 0xd4, 0x80, 0xf8, 0x90, 0x7f} },
+{ 0x8143,	16,	{0xa5, 0xe0, 0xfd, 0x30, 0xe0, 0xdc, 0x20, 0xe1, 0x09, 0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f} },
+{ 0x8153,	16,	{0xf9, 0x22, 0xed, 0x30, 0xe2, 0x0c, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f} },
+{ 0x8163,	16,	{0xfa, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0x7b, 0x1e} },
+{ 0x8173,	16,	{0xaf, 0x03, 0x1b, 0xef, 0x70, 0x16, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6} },
+{ 0x8183,	16,	{0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x60, 0x86, 0x80, 0xf8, 0x90, 0x7f, 0xa5, 0xe0} },
+{ 0x8193,	16,	{0xfd, 0x20, 0xe0, 0xdc, 0x7b, 0x3c, 0xaf, 0x03, 0x1b, 0xef, 0x70, 0x19, 0x90, 0x7f, 0xa5, 0xe0} },
+{ 0x81a3,	16,	{0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03} },
+{ 0x81b3,	16,	{0x02, 0x81, 0x13, 0x80, 0xf5, 0x90, 0x7f, 0xa5, 0xe0, 0xfd, 0x30, 0xe0, 0xd9, 0x30, 0xe2, 0x09} },
+{ 0x81c3,	16,	{0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f, 0xfa, 0x22, 0xc2, 0xaf, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x81d3,	12,	{0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0xd2, 0xaf, 0xff, 0x7e, 0x00} },
+{ 0x81df,	1,	{0x22} },
+{ 0x81e0,	2,	{0xae, 0x07} },
+{ 0x81e2,	16,	{0x7c, 0x02, 0xec, 0x14, 0x60, 0x15, 0x14, 0x70, 0x1e, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0} },
+{ 0x81f2,	16,	{0xee, 0x25, 0xe0, 0x44, 0x40, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xa6, 0xed, 0xf0} },
+{ 0x8202,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xfb, 0x30, 0xe0, 0xf8, 0xbc} },
+{ 0x8212,	16,	{0x02, 0x0a, 0x20, 0xe1, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22, 0xeb, 0x30, 0xe2, 0x0a} },
+{ 0x8222,	14,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xdc, 0xb6, 0x7f, 0x08} },
+{ 0x8230,	1,	{0x22} },
+{ 0x8231,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc2, 0xa9, 0x90, 0x03, 0x00, 0x74, 0x19, 0xf0, 0xd2, 0xa9} },
+{ 0x8241,	15,	{0x53, 0x91, 0x7f, 0x90, 0x01, 0xc4, 0xe4, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x8250,	16,	{0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xf5} },
+{ 0x8260,	16,	{0x83, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x5e, 0x74, 0xbf} },
+{ 0x8270,	16,	{0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x44, 0x10, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3} },
+{ 0x8280,	16,	{0xa3, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xf0, 0xf9, 0xed, 0x60, 0x1d, 0x74, 0x01} },
+{ 0x8290,	16,	{0x7e, 0x00, 0xa8, 0x07, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0xe4} },
+{ 0x82a0,	16,	{0xef, 0x55, 0x3b, 0x60, 0x04, 0x79, 0x09, 0x80, 0x02, 0x79, 0x0d, 0x8b, 0x82, 0x8a, 0x83, 0xa3} },
+{ 0x82b0,	16,	{0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x54, 0xef, 0xf0, 0x8b} },
+{ 0x82c0,	16,	{0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x5e, 0xf0, 0xae, 0x02, 0xaf, 0x03, 0x8f, 0x82, 0x8e} },
+{ 0x82d0,	4,	{0x83, 0xa3, 0xe9, 0xf0} },
+{ 0x82d4,	1,	{0x22} },
+{ 0x82d5,	4,	{0x8f, 0x5e, 0x8d, 0x5f} },
+{ 0x82d9,	16,	{0xe4, 0xf5, 0x60, 0x74, 0x3c, 0x2f, 0xf8, 0x76, 0x08, 0xe5, 0x5e, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
+{ 0x82e9,	16,	{0x02, 0xf5, 0x82, 0xe4, 0x34, 0x03, 0xf5, 0x83, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
+{ 0x82f9,	16,	{0xa3, 0xe0, 0xff, 0x7b, 0x80, 0x7a, 0x25, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9c, 0xea, 0x50} },
+{ 0x8309,	16,	{0x3c, 0xe5, 0x5e, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34, 0x03, 0xf5, 0x83} },
+{ 0x8319,	16,	{0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x96, 0x78} },
+{ 0x8329,	16,	{0x00, 0xc3, 0x12, 0x9c, 0xea, 0x40, 0x0c, 0x75, 0x60, 0x40, 0x74, 0x3c, 0x25, 0x5e, 0xf8, 0x76} },
+{ 0x8339,	16,	{0x10, 0x80, 0x0a, 0x75, 0x60, 0x80, 0x74, 0x3c, 0x25, 0x5e, 0xf8, 0x76, 0x38, 0xe5, 0x60, 0x45} },
+{ 0x8349,	16,	{0x5f, 0x44, 0x01, 0xff, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x8359,	5,	{0x20, 0xf5, 0x83, 0xef, 0xf0} },
+{ 0x835e,	1,	{0x22} },
+{ 0x835f,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x54, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x836f,	16,	{0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x55, 0x8f, 0x56, 0xe5, 0x54, 0x25, 0xe0, 0x24, 0xc6, 0xf5} },
+{ 0x837f,	16,	{0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x0f, 0xe5, 0x54, 0x25, 0xe0, 0x24, 0xc7} },
+{ 0x838f,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x74, 0x22, 0x25, 0x54, 0xf8, 0xe4, 0xf6} },
+{ 0x839f,	16,	{0xe5, 0x56, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x55, 0xf5, 0x83, 0xe0, 0x44, 0x03, 0xf0, 0xaf} },
+{ 0x83af,	16,	{0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0xaf, 0x54, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x85, 0x56, 0x82} },
+{ 0x83bf,	16,	{0x85, 0x55, 0x83, 0xa3, 0xa3, 0xe0, 0x20, 0xe0, 0x22, 0xe0, 0xff, 0xe5, 0x56, 0x24, 0x05, 0xf5} },
+{ 0x83cf,	16,	{0x82, 0xe4, 0x35, 0x55, 0xf5, 0x83, 0xe0, 0xe5, 0x56, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x55} },
+{ 0x83df,	16,	{0xf5, 0x83, 0xe0, 0xff, 0xaf, 0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x74, 0xf8, 0x25, 0x54, 0xf5} },
+{ 0x83ef,	16,	{0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x54, 0x25, 0xe0, 0xff, 0xc3, 0x74, 0x0c} },
+{ 0x83ff,	16,	{0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82, 0xfe} },
+{ 0x840f,	16,	{0xe5, 0x54, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xee, 0xf0, 0xa3} },
+{ 0x841f,	16,	{0xef, 0xf0, 0xaf, 0x54, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42} },
+{ 0x842f,	3,	{0x30, 0x7f, 0x00} },
+{ 0x8432,	1,	{0x22} },
+{ 0x8433,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x54, 0xff, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0x74, 0xf8} },
+{ 0x8443,	16,	{0x25, 0x54, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x54, 0x75, 0xf0, 0x08} },
+{ 0x8453,	16,	{0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x56, 0x8f, 0x57, 0xf5, 0x83} },
+{ 0x8463,	16,	{0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf} },
+{ 0x8473,	16,	{0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0xe5, 0x57, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x56, 0xf5} },
+{ 0x8483,	16,	{0x83, 0xe0, 0x30, 0xe0, 0x09, 0x85, 0x57, 0x82, 0x85, 0x56, 0x83, 0xe0, 0xf5, 0x55, 0xaf, 0x54} },
+{ 0x8493,	16,	{0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x30, 0xe5, 0x54} },
+{ 0x84a3,	16,	{0x25, 0xe0, 0x24, 0xc6, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x0f, 0xe5} },
+{ 0x84b3,	16,	{0x54, 0x25, 0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x7f, 0x00} },
+{ 0x84c3,	1,	{0x22} },
+{ 0x84c4,	4,	{0x8e, 0x54, 0x8f, 0x55} },
+{ 0x84c8,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x56, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82} },
+{ 0x84d8,	16,	{0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x70, 0x23, 0x85, 0x55, 0x82, 0x8e, 0x83, 0xa3} },
+{ 0x84e8,	16,	{0xe0, 0x30, 0xe0, 0x07, 0xaf, 0x56, 0x7d, 0x02, 0x12, 0x82, 0xd5, 0x85, 0x55, 0x82, 0x85, 0x54} },
+{ 0x84f8,	15,	{0x83, 0xa3, 0xe0, 0x30, 0xe1, 0x07, 0xaf, 0x56, 0x7d, 0x04, 0x12, 0x82, 0xd5, 0x7f, 0x00} },
+{ 0x8507,	1,	{0x22} },
+{ 0x8508,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0xa3, 0xa3, 0xa3, 0xe0, 0xfc, 0xed} },
+{ 0x8518,	16,	{0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xc0, 0x83, 0xc0} },
+{ 0x8528,	16,	{0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0} },
+{ 0x8538,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0xe0, 0xfd, 0xec, 0x6d, 0xd0} },
+{ 0x8548,	16,	{0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f} },
+{ 0x8558,	16,	{0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82} },
+{ 0x8568,	16,	{0x8e, 0x83, 0xa3, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0} },
+{ 0x8578,	16,	{0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0} },
+{ 0x8588,	16,	{0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xff, 0xed, 0x6f, 0xd0, 0x82, 0xd0} },
+{ 0x8598,	3,	{0x83, 0xf0, 0x22} },
+{ 0x859b,	16,	{0x79, 0x0d, 0x8e, 0x54, 0x8f, 0x55, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
+{ 0x85ab,	16,	{0xf4, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xaf, 0x82, 0xfe, 0xad, 0x01, 0x19, 0xed, 0x60, 0x24, 0x0f} },
+{ 0x85bb,	16,	{0xef, 0xac, 0x06, 0x70, 0x01, 0x0e, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe0, 0xfd, 0x05, 0x55, 0xe5} },
+{ 0x85cb,	16,	{0x55, 0xaa, 0x54, 0x70, 0x02, 0x05, 0x54, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xe0, 0x6d, 0x60, 0xd9} },
+{ 0x85db,	5,	{0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x85e0,	1,	{0x22} },
+{ 0x85e1,	4,	{0x8e, 0x54, 0x8f, 0x55} },
+{ 0x85e5,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x5b, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x85f5,	16,	{0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x5c, 0x8f, 0x5d, 0xaa, 0x06, 0xa9, 0x55, 0x7b, 0x01, 0xc0} },
+{ 0x8605,	16,	{0x03, 0xc0, 0x01, 0xe5, 0x5b, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x01, 0xf9, 0x74, 0x03, 0x35, 0xf0} },
+{ 0x8615,	16,	{0xa8, 0x01, 0xfc, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x0d, 0x12, 0x9b, 0x49} },
+{ 0x8625,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8635,	16,	{0xe0, 0xff, 0x7b, 0x08, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xd3, 0x12, 0x9c, 0xea, 0x40, 0x10} },
+{ 0x8645,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0x12, 0x9d, 0x31, 0x00, 0x00, 0x00, 0x08, 0x80, 0x2e} },
+{ 0x8655,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8665,	16,	{0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x08, 0x79, 0x07, 0x78, 0x00, 0xc3, 0x12, 0x9c, 0xea, 0x50, 0x0e} },
+{ 0x8675,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0x12, 0x9d, 0x31, 0x00, 0x07, 0x08, 0x00, 0x85, 0x55} },
+{ 0x8685,	16,	{0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb} },
+{ 0x8695,	16,	{0x7f, 0x00, 0x7e, 0x50, 0x7d, 0x46, 0x7c, 0x00, 0x12, 0x9c, 0x58, 0x8f, 0x59, 0x8e, 0x58, 0x8d} },
+{ 0x86a5,	16,	{0x57, 0x8c, 0x56, 0x7b, 0x0a, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0x12, 0x9c, 0x58, 0xaf, 0x03} },
+{ 0x86b5,	16,	{0x8f, 0x5a, 0xaf, 0x59, 0xae, 0x58, 0xad, 0x57, 0xac, 0x56, 0x7b, 0x0a, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x86c5,	16,	{0x78, 0x00, 0x12, 0x9c, 0x58, 0x8f, 0x59, 0x8e, 0x58, 0x8d, 0x57, 0x8c, 0x56, 0xe5, 0x5a, 0xc3} },
+{ 0x86d5,	16,	{0x94, 0x05, 0x40, 0x15, 0xe5, 0x59, 0x24, 0x01, 0xf5, 0x59, 0xe4, 0x35, 0x58, 0xf5, 0x58, 0xe4} },
+{ 0x86e5,	16,	{0x35, 0x57, 0xf5, 0x57, 0xe4, 0x35, 0x56, 0xf5, 0x56, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3} },
+{ 0x86f5,	16,	{0xe4, 0xf0, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
+{ 0x8705,	16,	{0x5d, 0x82, 0x85, 0x5c, 0x83, 0xe5, 0x59, 0xf0, 0xaf, 0x59, 0xae, 0x58, 0xad, 0x57, 0xac, 0x56} },
+{ 0x8715,	16,	{0x78, 0x08, 0x12, 0x9c, 0xfb, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xef, 0xf0, 0x85, 0x5d} },
+{ 0x8725,	16,	{0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xe4, 0xf5, 0x5a, 0xe5, 0x55} },
+{ 0x8735,	16,	{0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xb4, 0x62, 0x05, 0x43, 0x5a} },
+{ 0x8745,	16,	{0x0a, 0x80, 0x10, 0xef, 0xb4, 0x72, 0x05, 0x43, 0x5a, 0x08, 0x80, 0x07, 0xef, 0xb4, 0x74, 0x03} },
+{ 0x8755,	16,	{0x43, 0x5a, 0x02, 0xe5, 0x55, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff} },
+{ 0x8765,	16,	{0x30, 0xe3, 0x03, 0x43, 0x5a, 0x80, 0xef, 0x30, 0xe7, 0x12, 0x43, 0x5a, 0x40, 0xe5, 0x5d, 0x24} },
+{ 0x8775,	16,	{0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x55, 0x24, 0x0b} },
+{ 0x8785,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0x20, 0xe1, 0x03, 0x30, 0xe4, 0x23, 0xaf} },
+{ 0x8795,	16,	{0x5b, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x3b, 0xe5, 0x5d} },
+{ 0x87a5,	16,	{0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0xe4, 0xf5, 0x5a} },
+{ 0x87b5,	16,	{0x80, 0x10, 0xaf, 0x5b, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4} },
+{ 0x87c5,	16,	{0x52, 0x3b, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x85, 0x5d} },
+{ 0x87d5,	16,	{0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5a, 0xf0, 0xe5, 0x55, 0x24, 0x0a, 0xf5} },
+{ 0x87e5,	16,	{0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x87f5,	16,	{0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x55, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83} },
+{ 0x8805,	16,	{0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5} },
+{ 0x8815,	16,	{0x55, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x06} },
+{ 0x8825,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x55, 0x24, 0x09, 0xf5, 0x82, 0xe4} },
+{ 0x8835,	16,	{0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5} },
+{ 0x8845,	16,	{0x83, 0xef, 0xf0, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe4, 0xf0, 0x85, 0x5d} },
+{ 0x8855,	16,	{0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xf0, 0xaf, 0x5b, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x75, 0x5a} },
+{ 0x8865,	16,	{0x08, 0xe5, 0x55, 0x24, 0x0c, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x43} },
+{ 0x8875,	16,	{0x5a, 0x10, 0xe5, 0x5d, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x54, 0x03} },
+{ 0x8885,	16,	{0x45, 0x5a, 0xf0, 0xe5, 0x55, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0x14} },
+{ 0x8895,	16,	{0xff, 0x25, 0xe0, 0x25, 0xe0, 0xff, 0xe5, 0x55, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5} },
+{ 0x88a5,	16,	{0x83, 0xe0, 0x24, 0xfb, 0x4f, 0xf5, 0x5a, 0xe5, 0x55, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x54} },
+{ 0x88b5,	16,	{0xf5, 0x83, 0xe0, 0x24, 0xd0, 0x60, 0x15, 0x14, 0x60, 0x17, 0x24, 0xc2, 0x60, 0x09, 0x24, 0x0a} },
+{ 0x88c5,	16,	{0x70, 0x12, 0x43, 0x5a, 0x18, 0x80, 0x0d, 0x43, 0x5a, 0x08, 0x80, 0x08, 0x43, 0x5a, 0x38, 0x80} },
+{ 0x88d5,	16,	{0x03, 0x43, 0x5a, 0x28, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x5a, 0xf0} },
+{ 0x88e5,	9,	{0xaf, 0x5b, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x7f, 0x00} },
+{ 0x88ee,	1,	{0x22} },
+{ 0x88ef,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4} },
+{ 0x88ff,	16,	{0x34, 0x20, 0xad, 0x82, 0xfc, 0x90, 0x01, 0x2c, 0x74, 0x08, 0xf0, 0xef, 0x04, 0xa3, 0xf0, 0xe4} },
+{ 0x890f,	16,	{0xa3, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5} },
+{ 0x891f,	16,	{0x83, 0xe0, 0x90, 0x01, 0x2f, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x05, 0xf5, 0x82} },
+{ 0x892f,	16,	{0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x1e, 0x90, 0x01, 0x30, 0xf0, 0x74, 0x2c, 0x2f, 0xf8} },
+{ 0x893f,	16,	{0xe6, 0xa3, 0xf0, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x54} },
+{ 0x894f,	16,	{0x7f, 0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xe5, 0x54, 0x5f} },
+{ 0x895f,	16,	{0x90, 0x01, 0x32, 0xf0, 0x7e, 0x01, 0x7f, 0x2c, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e} },
+{ 0x896f,	11,	{0x00, 0x75, 0x5d, 0x00, 0x7d, 0x07, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x897a,	1,	{0x22} },
+{ 0x897b,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x898b,	16,	{0xaf, 0x82, 0xfe, 0x90, 0x01, 0x33, 0x74, 0x0a, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xe5, 0x82, 0x24} },
+{ 0x899b,	16,	{0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x90, 0x01, 0x34, 0xf0, 0x7e, 0x01, 0x7f} },
+{ 0x89ab,	16,	{0x33, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x02, 0x12} },
+{ 0x89bb,	4,	{0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x89bf,	1,	{0x22} },
+{ 0x89c0,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x89d0,	16,	{0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
+{ 0x89e0,	16,	{0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
+{ 0x89f0,	11,	{0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0x7f, 0x00} },
+{ 0x89fb,	1,	{0x22} },
+{ 0x89fc,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x8a0c,	16,	{0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
+{ 0x8a1c,	16,	{0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
+{ 0x8a2c,	11,	{0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x00} },
+{ 0x8a37,	1,	{0x22} },
+{ 0x8a38,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x8a48,	16,	{0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0d, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3} },
+{ 0x8a58,	16,	{0xe0, 0x44, 0x40, 0xf0, 0x80, 0x0f, 0xae, 0x04, 0xaf, 0x05, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3} },
+{ 0x8a68,	7,	{0xa3, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x00} },
+{ 0x8a6f,	1,	{0x22} },
+{ 0x8a70,	4,	{0x8e, 0x54, 0x8f, 0x55} },
+{ 0x8a74,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0, 0xf5, 0x58, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x24, 0xfe, 0x60} },
+{ 0x8a84,	16,	{0x16, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x28, 0x24, 0x03, 0x70, 0x2e, 0x7e, 0x7e, 0x7f, 0x80, 0x75} },
+{ 0x8a94,	16,	{0x56, 0x7e, 0x75, 0x57, 0x80, 0x80, 0x22, 0x7e, 0x7e, 0x7f, 0x00, 0x75, 0x56, 0x7e, 0x75, 0x57} },
+{ 0x8aa4,	16,	{0x00, 0x80, 0x16, 0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x56, 0x7d, 0x75, 0x57, 0x80, 0x80, 0x0a, 0x7e} },
+{ 0x8ab4,	16,	{0x7d, 0x7f, 0x00, 0x75, 0x56, 0x7d, 0x75, 0x57, 0x00, 0xe5, 0x58, 0x70, 0x20, 0x85, 0x57, 0x82} },
+{ 0x8ac4,	16,	{0x85, 0x56, 0x83, 0x74, 0xff, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
+{ 0x8ad4,	16,	{0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x4d, 0xe5, 0x55, 0x24} },
+{ 0x8ae4,	16,	{0x02, 0xff, 0xe4, 0x35, 0x54, 0xfe, 0xe5, 0x58, 0x60, 0x23, 0x0f, 0xef, 0xac, 0x06, 0x70, 0x01} },
+{ 0x8af4,	16,	{0x0e, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe0, 0xfd, 0x05, 0x57, 0xe5, 0x57, 0xaa, 0x56, 0x70, 0x02} },
+{ 0x8b04,	16,	{0x05, 0x56, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xed, 0xf0, 0x15, 0x58, 0x80, 0xd9, 0x85, 0x55, 0x82} },
+{ 0x8b14,	16,	{0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
+{ 0x8b24,	12,	{0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x7f, 0x00} },
+{ 0x8b30,	1,	{0x22} },
+{ 0x8b31,	16,	{0xef, 0x24, 0x05, 0xf5, 0x55, 0xe4, 0x3e, 0xf5, 0x54, 0x90, 0x01, 0x35, 0x74, 0x07, 0xf0, 0x90} },
+{ 0x8b41,	16,	{0x01, 0x7a, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x36, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3} },
+{ 0x8b51,	16,	{0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0x8e, 0x56, 0xf5, 0x57, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8b61,	16,	{0xe0, 0x24, 0x9e, 0x60, 0x61, 0x24, 0xf9, 0x60, 0x0e, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8c, 0x12} },
+{ 0x8b71,	16,	{0x24, 0x14, 0x60, 0x03, 0x02, 0x8c, 0x5e, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe} },
+{ 0x8b81,	16,	{0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f, 0xf5, 0x59, 0x74, 0x01, 0x9e, 0xf5, 0x58, 0xd3, 0xe5, 0x59} },
+{ 0x8b91,	16,	{0x94, 0x40, 0xe5, 0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x40, 0xd3, 0xe5} },
+{ 0x8ba1,	16,	{0x57, 0x95, 0x59, 0xe5, 0x56, 0x95, 0x58, 0x50, 0x03, 0x02, 0x8c, 0x61, 0xae, 0x58, 0xaf, 0x59} },
+{ 0x8bb1,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e} },
+{ 0x8bc1,	16,	{0x56, 0xf5, 0x57, 0x02, 0x8c, 0x61, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8bd1,	16,	{0xe0, 0xff, 0xc3, 0x74, 0x30, 0x9f, 0xf5, 0x59, 0xe4, 0x9e, 0xf5, 0x58, 0xd3, 0xe5, 0x59, 0x94} },
+{ 0x8be1,	16,	{0x10, 0xe5, 0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x10, 0xd3, 0xe5, 0x57} },
+{ 0x8bf1,	16,	{0x95, 0x59, 0xe5, 0x56, 0x95, 0x58, 0x40, 0x68, 0xae, 0x58, 0xaf, 0x59, 0x85, 0x55, 0x82, 0x85} },
+{ 0x8c01,	16,	{0x54, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x56, 0xf5, 0x57, 0x80} },
+{ 0x8c11,	16,	{0x4f, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f} },
+{ 0x8c21,	16,	{0xf5, 0x59, 0xe4, 0x9e, 0xf5, 0x58, 0x45, 0x59, 0x60, 0x0b, 0xd3, 0xe5, 0x59, 0x94, 0x40, 0xe5} },
+{ 0x8c31,	16,	{0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x40, 0xd3, 0xe5, 0x57, 0x95, 0x59} },
+{ 0x8c41,	16,	{0xe5, 0x56, 0x95, 0x58, 0x40, 0x17, 0xae, 0x58, 0xaf, 0x59, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8c51,	16,	{0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x56, 0xf5, 0x57, 0x7f, 0x01, 0x22} },
+{ 0x8c61,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x24, 0x9e, 0x70, 0x03, 0x02, 0x8d, 0x21, 0x24, 0xf9} },
+{ 0x8c71,	16,	{0x60, 0x58, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8d, 0x71, 0x24, 0x14, 0x60, 0x03, 0x02, 0x8d, 0xb5} },
+{ 0x8c81,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xd3, 0x94, 0xff, 0xee} },
+{ 0x8c91,	16,	{0x94, 0x00, 0x40, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x75, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57} },
+{ 0x8ca1,	16,	{0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x70, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x75, 0xe0} },
+{ 0x8cb1,	16,	{0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b} },
+{ 0x8cc1,	16,	{0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8cd1,	16,	{0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x80, 0xee, 0x94, 0x00, 0x50, 0x03, 0x02, 0x8d} },
+{ 0x8ce1,	16,	{0xb5, 0xd3, 0xef, 0x94, 0xff, 0xee, 0x94, 0x00, 0x40, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x76} },
+{ 0x8cf1,	16,	{0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x70, 0x03, 0x02} },
+{ 0x8d01,	16,	{0x8d, 0xb5, 0x90, 0x01, 0x76, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a} },
+{ 0x8d11,	16,	{0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2} },
+{ 0x8d21,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x20, 0xee} },
+{ 0x8d31,	16,	{0x94, 0x00, 0x50, 0x03, 0x02, 0x8d, 0xb5, 0xd3, 0xef, 0x94, 0x2f, 0xee, 0x94, 0x00, 0x50, 0x74} },
+{ 0x8d41,	16,	{0x90, 0x01, 0x77, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e} },
+{ 0x8d51,	16,	{0x60, 0x62, 0x90, 0x01, 0x77, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a} },
+{ 0x8d61,	16,	{0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd5} },
+{ 0x8d71,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0x01, 0x78, 0xcf, 0xf0} },
+{ 0x8d81,	16,	{0xa3, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x60, 0x24} },
+{ 0x8d91,	16,	{0x90, 0x01, 0x78, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0} },
+{ 0x8da1,	16,	{0xff, 0x90, 0x01, 0x7a, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
+{ 0x8db1,	16,	{0xef, 0xf0, 0x80, 0xcf, 0x7e, 0x01, 0x7f, 0x35, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3} },
+{ 0x8dc1,	16,	{0xa3, 0xe0, 0xa3, 0xe0, 0x04, 0xfd, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75} },
+{ 0x8dd1,	7,	{0x5d, 0x00, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x8dd8,	1,	{0x22} },
+{ 0x8dd9,	16,	{0x8e, 0x61, 0x8f, 0x62, 0x8c, 0x63, 0x8d, 0x64, 0xaf, 0x03, 0x1b, 0xef, 0x60, 0x24, 0x05, 0x62} },
+{ 0x8de9,	16,	{0xe5, 0x62, 0xae, 0x61, 0x70, 0x02, 0x05, 0x61, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05} },
+{ 0x8df9,	16,	{0x64, 0xe5, 0x64, 0xac, 0x63, 0x70, 0x02, 0x05, 0x63, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
+{ 0x8e09,	3,	{0x80, 0xd6, 0x22} },
+{ 0x8e0c,	16,	{0x8d, 0x5c, 0xab, 0x07, 0xaa, 0x06, 0xaf, 0x60, 0xae, 0x5f, 0xad, 0x5e, 0xac, 0x5d, 0xec, 0x4d} },
+{ 0x8e1c,	16,	{0x4e, 0x4f, 0x60, 0x1c, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x1c, 0x7f, 0xff, 0x7e, 0xff, 0x7d} },
+{ 0x8e2c,	16,	{0xff, 0x7c, 0xff, 0x78, 0x5d, 0x12, 0x9d, 0x0e, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0x09, 0x80, 0xe4} },
+{ 0x8e3c,	16,	{0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0xf9, 0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x16, 0xaf, 0x03} },
+{ 0x8e4c,	16,	{0xae, 0x02, 0x7c, 0x7b, 0x7d, 0x80, 0xab, 0x5c, 0x12, 0x8d, 0xd9, 0x90, 0x7f, 0xc3, 0xe5, 0x5c} },
+{ 0x8e5c,	7,	{0xf0, 0x7f, 0x01, 0x22, 0x7f, 0x00, 0x22} },
+{ 0x8e63,	16,	{0x90, 0x01, 0x84, 0x74, 0x0b, 0xf0, 0x90, 0x20, 0x70, 0xe0, 0x54, 0xf0, 0xff, 0xc4, 0x54, 0x0f} },
+{ 0x8e73,	16,	{0x90, 0x01, 0x85, 0xf0, 0x90, 0x11, 0xfd, 0xe4, 0x93, 0x90, 0x01, 0x86, 0xf0, 0x90, 0x11, 0xfe} },
+{ 0x8e83,	16,	{0xe4, 0x93, 0x90, 0x01, 0x87, 0xf0, 0xe4, 0x90, 0x01, 0x7c, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x8e93,	16,	{0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x88, 0xf0, 0x7e} },
+{ 0x8ea3,	16,	{0x01, 0x7f, 0x7c, 0x12, 0x19, 0xc1, 0x7e, 0x01, 0x7f, 0x84, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00} },
+{ 0x8eb3,	13,	{0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x14, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x8ec0,	1,	{0x22} },
+{ 0x8ec1,	4,	{0x8e, 0x4b, 0x8f, 0x4c} },
+{ 0x8ec5,	16,	{0x85, 0x4b, 0x4e, 0x85, 0x4c, 0x4f, 0xe5, 0x4f, 0x24, 0x01, 0xf5, 0x53, 0xe4, 0x35, 0x4e, 0xf5} },
+{ 0x8ed5,	16,	{0x52, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xe0, 0x14, 0xb4, 0x0f, 0x00, 0x40, 0x03, 0x02, 0x8f} },
+{ 0x8ee5,	16,	{0xd6, 0x90, 0x8e, 0xed, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x8f, 0x1a, 0x02, 0x8f, 0x26, 0x02, 0x8f} },
+{ 0x8ef5,	16,	{0x32, 0x02, 0x8f, 0x5c, 0x02, 0x8f, 0x67, 0x02, 0x8f, 0x72, 0x02, 0x8f, 0x7d, 0x02, 0x8f, 0x88} },
+{ 0x8f05,	16,	{0x02, 0x8f, 0x93, 0x02, 0x8f, 0x9e, 0x02, 0x8f, 0xa9, 0x02, 0x8f, 0xb0, 0x02, 0x8f, 0xd6, 0x02} },
+{ 0x8f15,	16,	{0x8f, 0xbb, 0x02, 0x8f, 0xc6, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x83, 0x5f, 0x8f, 0x4d, 0x02, 0x8f} },
+{ 0x8f25,	16,	{0xd6, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x84, 0x33, 0x8f, 0x4d, 0x02, 0x8f, 0xd6, 0x85, 0x52, 0x50} },
+{ 0x8f35,	16,	{0x85, 0x53, 0x51, 0xe5, 0x51, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x50, 0xfe, 0x12, 0x85, 0x08, 0xaf} },
+{ 0x8f45,	16,	{0x51, 0xae, 0x50, 0x12, 0x85, 0x9b, 0xef, 0x70, 0x03, 0x02, 0x8f, 0xd6, 0xaf, 0x51, 0xae, 0x50} },
+{ 0x8f55,	16,	{0x12, 0x85, 0xe1, 0x8f, 0x4d, 0x80, 0x7a, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0xc0, 0x8f, 0x4d} },
+{ 0x8f65,	16,	{0x80, 0x6f, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0xfc, 0x8f, 0x4d, 0x80, 0x64, 0xaf, 0x53, 0xae} },
+{ 0x8f75,	16,	{0x52, 0x12, 0x8a, 0x38, 0x8f, 0x4d, 0x80, 0x59, 0xaf, 0x4c, 0xae, 0x4b, 0x12, 0x8b, 0x31, 0x8f} },
+{ 0x8f85,	16,	{0x4d, 0x80, 0x4e, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x88, 0xef, 0x8f, 0x4d, 0x80, 0x43, 0xaf, 0x53} },
+{ 0x8f95,	16,	{0xae, 0x52, 0x12, 0x84, 0xc4, 0x8f, 0x4d, 0x80, 0x38, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0x7b} },
+{ 0x8fa5,	16,	{0x8f, 0x4d, 0x80, 0x2d, 0x12, 0x8e, 0x63, 0x8f, 0x4d, 0x80, 0x26, 0xaf, 0x53, 0xae, 0x52, 0x12} },
+{ 0x8fb5,	16,	{0x11, 0xe5, 0x8f, 0x4d, 0x80, 0x1b, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x8a, 0x70, 0x8f, 0x4d, 0x80} },
+{ 0x8fc5,	16,	{0x10, 0xaf, 0x4c, 0xae, 0x4b, 0x7c, 0x02, 0x7d, 0xaf, 0x7b, 0x40, 0x12, 0x8d, 0xd9, 0xe4, 0xf5} },
+{ 0x8fd5,	16,	{0x4d, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xe0, 0xff, 0x14, 0x24, 0xfa, 0x50, 0x04, 0x24, 0xfe} },
+{ 0x8fe5,	16,	{0x70, 0x2b, 0x90, 0x01, 0x98, 0x74, 0x10, 0xf0, 0xa3, 0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x8ff5,	16,	{0x83, 0xe0, 0x90, 0x01, 0x9a, 0xf0, 0x7e, 0x01, 0x7f, 0x98, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00} },
+{ 0x9005,	15,	{0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x03, 0x12, 0x8e, 0x0c, 0x8f, 0x4d, 0xaf, 0x4d} },
+{ 0x9014,	1,	{0x22} },
+{ 0x9015,	8,	{0x8f, 0x4e, 0x8e, 0x4d, 0x8d, 0x4c, 0x8c, 0x4b} },
+{ 0x901d,	16,	{0x75, 0x55, 0x01, 0x75, 0x56, 0x9c, 0xe4, 0xf5, 0x54, 0xaf, 0x50, 0x15, 0x50, 0xef, 0x70, 0x03} },
+{ 0x902d,	16,	{0x02, 0x90, 0xb3, 0xaf, 0x4f, 0xe4, 0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xaf, 0x4e} },
+{ 0x903d,	16,	{0xae, 0x4d, 0xad, 0x4c, 0xac, 0x4b, 0x12, 0x9c, 0x58, 0xaf, 0x03, 0x8f, 0x53, 0xaf, 0x4e, 0xae} },
+{ 0x904d,	16,	{0x4d, 0xad, 0x4c, 0xac, 0x4b, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xaf, 0x4f, 0xe4} },
+{ 0x905d,	16,	{0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04} },
+{ 0x906d,	16,	{0x12, 0x9c, 0x58, 0x8f, 0x4e, 0x8e, 0x4d, 0x8d, 0x4c, 0x8c, 0x4b, 0xe5, 0x53, 0x24, 0x30, 0xf5} },
+{ 0x907d,	16,	{0x53, 0xd3, 0x94, 0x39, 0x40, 0x06, 0x74, 0x07, 0x25, 0x53, 0xf5, 0x53, 0x05, 0x56, 0xe5, 0x56} },
+{ 0x908d,	16,	{0xae, 0x55, 0x70, 0x02, 0x05, 0x55, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x05, 0x56, 0xe5} },
+{ 0x909d,	16,	{0x56, 0xae, 0x55, 0x70, 0x02, 0x05, 0x55, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x53, 0xf0, 0x05} },
+{ 0x90ad,	16,	{0x54, 0x05, 0x54, 0x02, 0x90, 0x26, 0xe5, 0x56, 0x15, 0x56, 0x70, 0x02, 0x15, 0x55, 0xaf, 0x54} },
+{ 0x90bd,	16,	{0x15, 0x54, 0xef, 0x60, 0x23, 0xe5, 0x56, 0x15, 0x56, 0xae, 0x55, 0x70, 0x02, 0x15, 0x55, 0xf5} },
+{ 0x90cd,	16,	{0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05, 0x52, 0xe5, 0x52, 0xac, 0x51, 0x70, 0x02, 0x05, 0x51, 0x14} },
+{ 0x90dd,	8,	{0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x80, 0xd6} },
+{ 0x90e5,	1,	{0x22} },
+{ 0x90e6,	16,	{0xe4, 0x90, 0x01, 0xc9, 0xf0, 0x7e, 0x01, 0x7f, 0xca, 0x90, 0x01, 0xbe, 0xee, 0xf0, 0xa3, 0xef} },
+{ 0x90f6,	10,	{0xf0, 0x90, 0x01, 0xc2, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
+{ 0x9100,	16,	{0xaa, 0x07, 0xa9, 0x05, 0x90, 0x01, 0xc9, 0xe0, 0xc3, 0x94, 0x40, 0x50, 0x61, 0xac, 0x02, 0x74} },
+{ 0x9110,	16,	{0x01, 0x7e, 0x00, 0xa8, 0x04, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff} },
+{ 0x9120,	16,	{0xe4, 0xef, 0x55, 0x30, 0x60, 0x45, 0xea, 0x04, 0xff, 0x90, 0x01, 0xc2, 0xe0, 0xfc, 0xa3, 0xe0} },
+{ 0x9130,	16,	{0xfd, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0xa3, 0xe9, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
+{ 0x9140,	16,	{0xeb, 0xf0, 0x90, 0x01, 0xc2, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9b, 0xb8, 0xfc, 0xd3, 0xe5, 0xf0} },
+{ 0x9150,	16,	{0x94, 0x87, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0xc2, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0xca} },
+{ 0x9160,	16,	{0xf0, 0xc2, 0xaf, 0x90, 0x01, 0xc9, 0xe0, 0x04, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x9170,	1,	{0x22} },
+{ 0x9171,	16,	{0x90, 0x01, 0xc9, 0xe0, 0xd3, 0x94, 0x00, 0x40, 0x55, 0x90, 0x01, 0xbe, 0xe0, 0xfc, 0xa3, 0xe0} },
+{ 0x9181,	16,	{0xaa, 0x04, 0xf9, 0x7b, 0x01, 0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0xaa, 0x06, 0xa9, 0x07, 0xa8} },
+{ 0x9191,	16,	{0x01, 0xac, 0x02, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x03, 0x12} },
+{ 0x91a1,	16,	{0x9b, 0x49, 0x90, 0x01, 0xbe, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9b, 0xb8, 0xfc, 0xd3, 0xe5, 0xf0} },
+{ 0x91b1,	16,	{0x94, 0x87, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0xbe, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0xca} },
+{ 0x91c1,	16,	{0xf0, 0xc2, 0xaf, 0x90, 0x01, 0xc9, 0xe0, 0x14, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x91d1,	1,	{0x22} },
+{ 0x91d2,	16,	{0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x5e, 0x7e, 0x7b, 0x7f, 0x80, 0x75, 0x50, 0x7b, 0x75, 0x51} },
+{ 0x91e2,	16,	{0x80, 0xe5, 0x51, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x50, 0xa9, 0x07, 0x7b, 0x01, 0x8b, 0x52, 0xf5} },
+{ 0x91f2,	16,	{0x53, 0x89, 0x54, 0xfe, 0x12, 0x91, 0x71, 0xef, 0x60, 0x3b, 0xab, 0x52, 0xaa, 0x53, 0xa9, 0x54} },
+{ 0x9202,	16,	{0x12, 0x9b, 0x72, 0x14, 0xff, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0xb4, 0x02, 0x16, 0xc2, 0xaf} },
+{ 0x9212,	16,	{0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x44} },
+{ 0x9222,	16,	{0x04, 0xf0, 0xd2, 0xaf, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0xc3} },
+{ 0x9232,	5,	{0x74, 0x04, 0xf0, 0xd2, 0xaf} },
+{ 0x9237,	1,	{0x22} },
+{ 0x9238,	16,	{0x12, 0x91, 0xd2, 0xe4, 0xf5, 0x4b, 0x74, 0x36, 0x25, 0x4b, 0xf8, 0xe6, 0x54, 0xf0, 0xf5, 0x4c} },
+{ 0x9248,	16,	{0x74, 0xc5, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xe0, 0x65, 0x4c, 0xff, 0xc4} },
+{ 0x9258,	16,	{0x54, 0x0f, 0xf5, 0x4d, 0x60, 0x22, 0x74, 0xc5, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5} },
+{ 0x9268,	16,	{0x83, 0xe5, 0x4c, 0xf0, 0xaf, 0x4b, 0x7d, 0x01, 0xe5, 0x4c, 0x45, 0x4d, 0xfb, 0x12, 0x91, 0x00} },
+{ 0x9278,	16,	{0xef, 0x70, 0x05, 0x12, 0x91, 0xd2, 0x80, 0xec, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40} },
+{ 0x9288,	16,	{0xb5, 0x12, 0x91, 0xd2, 0xe5, 0x3a, 0x60, 0x48, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8} },
+{ 0x9298,	16,	{0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x55, 0x3a, 0x60, 0x29, 0xe5, 0x4b} },
+{ 0x92a8,	16,	{0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x30, 0xe6} },
+{ 0x92b8,	16,	{0x16, 0xaf, 0x4b, 0x7d, 0x04, 0x7b, 0x80, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05, 0x12, 0x91, 0xd2} },
+{ 0x92c8,	16,	{0x80, 0xef, 0xe5, 0x4c, 0xf4, 0x52, 0x3a, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0xbb} },
+{ 0x92d8,	16,	{0x90, 0x03, 0x00, 0xe0, 0x60, 0x03, 0x02, 0x93, 0xa5, 0x74, 0x19, 0xf0, 0x7f, 0x02, 0x12, 0x81} },
+{ 0x92e8,	16,	{0x11, 0x8e, 0x4e, 0x8f, 0x4f, 0xc3, 0xe5, 0x4e, 0x64, 0x80, 0x94, 0x80, 0x40, 0xee, 0x90, 0x01} },
+{ 0x92f8,	16,	{0xbc, 0xe0, 0x65, 0x4f, 0xf0, 0x60, 0x37, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8, 0x07} },
+{ 0x9308,	16,	{0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x90, 0x01, 0xbc, 0xe0, 0x55, 0x4c, 0x60} },
+{ 0x9318,	16,	{0x14, 0xaf, 0x4b, 0x7d, 0x08, 0xe5, 0x4c, 0x55, 0x4f, 0xfb, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05} },
+{ 0x9328,	16,	{0x12, 0x91, 0xd2, 0x80, 0xec, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0xcc, 0x90, 0x01} },
+{ 0x9338,	16,	{0xbc, 0xe5, 0x4f, 0xf0, 0xe4, 0xf5, 0x4b, 0xc2, 0xaf, 0x74, 0x32, 0x25, 0x4b, 0xf8, 0xe6, 0xf5} },
+{ 0x9348,	16,	{0x4c, 0xe4, 0xf6, 0xd2, 0xaf, 0x53, 0x4c, 0x1e, 0xe5, 0x4c, 0x60, 0x11, 0xaf, 0x4b, 0x7d, 0x02} },
+{ 0x9358,	16,	{0xab, 0x4c, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05, 0x12, 0x91, 0xd2, 0x80, 0xef, 0x74, 0x2c, 0x25} },
+{ 0x9368,	16,	{0x4b, 0xf8, 0xe6, 0xf5, 0x4c, 0x74, 0xfc, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
+{ 0x9378,	16,	{0xe0, 0x65, 0x4c, 0x60, 0x11, 0xaf, 0x4b, 0x7d, 0x04, 0xab, 0x4c, 0x12, 0x91, 0x00, 0xef, 0x70} },
+{ 0x9388,	16,	{0x05, 0x12, 0x91, 0xd2, 0x80, 0xef, 0x74, 0xfc, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
+{ 0x9398,	16,	{0x83, 0xe5, 0x4c, 0xf0, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0x9a, 0x12, 0x91, 0xd2} },
+{ 0x93a8,	1,	{0x22} },
+{ 0x93a9,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x64, 0x02, 0x93, 0xf0} },
+{ 0x93b5,	16,	{0x02, 0x05, 0xa3, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x93c5,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x93d5,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x93e5,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x94, 0x35, 0xe4, 0x7e} },
+{ 0x93f5,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x9405,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x9415,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x9425,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x9435,	16,	{0x60, 0x24, 0x02, 0x8a, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x81, 0x82, 0x84, 0x88} },
+{ 0x9445,	16,	{0x90, 0xa0, 0xc0, 0xc1, 0xc2, 0xc4, 0xc8, 0xd0, 0xe0, 0xe1, 0xe2, 0xe4, 0xe8, 0xf0, 0xf1, 0xf2} },
+{ 0x9455,	8,	{0xf4, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xfe, 0xff} },
+{ 0x945d,	1,	{0x00} },
+{ 0x945e,	11,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18} },
+{ 0x9469,	16,	{0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xfe, 0x30, 0xe0, 0x05, 0x90, 0x20, 0x02, 0xe0, 0xff, 0xee} },
+{ 0x9479,	16,	{0x30, 0xe1, 0x05, 0x90, 0x20, 0x0a, 0xe0, 0xff, 0xee, 0x30, 0xe2, 0x05, 0x90, 0x20, 0x12, 0xe0} },
+{ 0x9489,	16,	{0xff, 0xee, 0x30, 0xe3, 0x05, 0x90, 0x20, 0x1a, 0xe0, 0xff, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x1e} },
+{ 0x9499,	10,	{0x04, 0xe4, 0xf0, 0x80, 0x05, 0x90, 0x01, 0xc4, 0xee, 0xf0} },
+{ 0x94a3,	9,	{0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x94ac,	2,	{0xa9, 0x03} },
+{ 0x94ae,	16,	{0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xe5} },
+{ 0x94be,	16,	{0x57, 0x45, 0x58, 0xf5, 0x59, 0xe9, 0x60, 0x14, 0x8a, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82} },
+{ 0x94ce,	16,	{0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x4d, 0xf0, 0xe4, 0xfe, 0x80, 0x13, 0xeb, 0x24, 0x04, 0xf5} },
+{ 0x94de,	16,	{0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0xff, 0xed, 0xf4, 0xfc, 0xef, 0x5c, 0xf0, 0xae, 0x59, 0xeb} },
+{ 0x94ee,	16,	{0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0x55, 0x59, 0xfc, 0xb5, 0x06, 0x03, 0xaf} },
+{ 0x94fe,	16,	{0x05, 0x22, 0xe5, 0x57, 0x5c, 0xfe, 0xe5, 0x58, 0x5c, 0xfd, 0xe9, 0x60, 0x16, 0xee, 0x70, 0x04} },
+{ 0x950e,	16,	{0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xae, 0x07, 0xed, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f} },
+{ 0x951e,	16,	{0x00, 0xad, 0x07, 0xee, 0x60, 0x03, 0xaf, 0x57, 0x22, 0xed, 0x60, 0x03, 0xaf, 0x58, 0x22, 0x7f} },
+{ 0x952e,	1,	{0x00} },
+{ 0x952f,	1,	{0x22} },
+{ 0x9530,	16,	{0x75, 0x50, 0x02, 0x75, 0x51, 0xb0, 0x90, 0x03, 0x35, 0x74, 0x0f, 0xf0, 0x85, 0x51, 0x82, 0x85} },
+{ 0x9540,	16,	{0x50, 0x83, 0xe0, 0xff, 0x90, 0x03, 0x36, 0xf0, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xa3, 0xe0} },
+{ 0x9550,	16,	{0x90, 0x03, 0x37, 0xf0, 0xa3, 0x74, 0xff, 0xf0, 0x75, 0x52, 0x03, 0x75, 0x53, 0x39, 0xef, 0x14} },
+{ 0x9560,	16,	{0xb4, 0x0b, 0x00, 0x40, 0x03, 0x02, 0x99, 0x98, 0x90, 0x95, 0x6f, 0xf8, 0x28, 0x28, 0x73, 0x02} },
+{ 0x9570,	16,	{0x95, 0x90, 0x02, 0x96, 0x2f, 0x02, 0x97, 0x34, 0x02, 0x97, 0x54, 0x02, 0x97, 0x54, 0x02, 0x97} },
+{ 0x9580,	16,	{0xef, 0x02, 0x98, 0x2a, 0x02, 0x98, 0x4f, 0x02, 0x99, 0x0d, 0x02, 0x99, 0x39, 0x02, 0x99, 0x65} },
+{ 0x9590,	16,	{0xe4, 0xf5, 0x4b, 0xe5, 0x4b, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20} },
+{ 0x95a0,	16,	{0xaf, 0x82, 0xf5, 0x4e, 0x8f, 0x4f, 0xe4, 0xff, 0xe4, 0xfe, 0xef, 0x60, 0x10, 0x74, 0x8a, 0x2e} },
+{ 0x95b0,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf4, 0xf5, 0x4c, 0x80, 0x0d, 0x74, 0x8a, 0x2e} },
+{ 0x95c0,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf5, 0x4c, 0xe5, 0x4f, 0x24, 0x07, 0xf5, 0x82} },
+{ 0x95d0,	16,	{0xe4, 0x35, 0x4e, 0xf5, 0x83, 0xe5, 0x4c, 0xf0, 0xe0, 0xf5, 0x4d, 0x65, 0x4c, 0x60, 0x38, 0xe4} },
+{ 0x95e0,	16,	{0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xfd, 0x05, 0x53, 0xe5, 0x53, 0xaa, 0x52, 0x70, 0x02} },
+{ 0x95f0,	16,	{0x05, 0x52, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xed, 0xf0, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52, 0x70} },
+{ 0x9600,	16,	{0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe5, 0x4c, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x9610,	16,	{0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0x0e, 0xbe, 0x24, 0x8f, 0x0f, 0xef, 0x64, 0x02, 0x70} },
+{ 0x9620,	16,	{0x87, 0x05, 0x4b, 0xe5, 0x4b, 0x64, 0x04, 0x60, 0x03, 0x02, 0x95, 0x93, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x9630,	16,	{0xf5, 0x4b, 0xaf, 0x4b, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0x05, 0x4b, 0xe5, 0x4b, 0xd3, 0x94, 0x03} },
+{ 0x9640,	16,	{0x40, 0xf0, 0x90, 0x00, 0x04, 0x74, 0x94, 0xf0, 0xa3, 0x74, 0x5e, 0xf0, 0xe4, 0xf5, 0x4d, 0x7e} },
+{ 0x9650,	16,	{0x20, 0x7f, 0x00, 0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8} },
+{ 0x9660,	16,	{0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x90, 0x01, 0xc4, 0xf0, 0x90, 0x01} },
+{ 0x9670,	16,	{0xc0, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0x74, 0x02} },
+{ 0x9680,	16,	{0xf0, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x4c, 0x34, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0} },
+{ 0x9690,	16,	{0x70, 0xef, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xff, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52} },
+{ 0x96a0,	16,	{0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x96b0,	16,	{0x83, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x01, 0xc4, 0xf0, 0x75, 0x4d, 0xff, 0x90, 0x01, 0xc4, 0xe0} },
+{ 0x96c0,	16,	{0xff, 0x60, 0x37, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xfe, 0x05, 0x53, 0xe5, 0x53} },
+{ 0x96d0,	16,	{0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xee, 0xf0, 0x05, 0x53, 0xe5} },
+{ 0x96e0,	16,	{0x53, 0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x53} },
+{ 0x96f0,	16,	{0x82, 0x85, 0x52, 0x83, 0xe5, 0x4c, 0xf0, 0x75, 0x4d, 0xff, 0xe5, 0x4d, 0x70, 0x16, 0x74, 0x08} },
+{ 0x9700,	16,	{0x25, 0x4f, 0xf5, 0x4f, 0xe4, 0x35, 0x4e, 0xf5, 0x4e, 0x05, 0x4b, 0xe5, 0x4b, 0x64, 0x04, 0x60} },
+{ 0x9710,	16,	{0x03, 0x02, 0x96, 0x5b, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x05, 0x4b} },
+{ 0x9720,	16,	{0xe5, 0x4b, 0xd3, 0x94, 0x03, 0x40, 0xf0, 0x90, 0x00, 0x04, 0x74, 0x13, 0xf0, 0xa3, 0x74, 0x12} },
+{ 0x9730,	16,	{0xf0, 0x02, 0x99, 0x9e, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xa3, 0xe0, 0x14, 0xff, 0x74, 0x01} },
+{ 0x9740,	16,	{0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x90, 0x02, 0xf7, 0xf0, 0x90, 0x01, 0xc4} },
+{ 0x9750,	16,	{0xf0, 0x02, 0x99, 0x9e, 0x90, 0x01, 0xc0, 0x74, 0x03, 0xf0, 0xa3, 0x74, 0xe8, 0xf0, 0xe4, 0xf5} },
+{ 0x9760,	16,	{0x4d, 0x90, 0x02, 0xf7, 0xe0, 0xff, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x07, 0x19, 0x90, 0x01, 0xc0} },
+{ 0x9770,	16,	{0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xea, 0x90, 0x03, 0x38, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x9780,	16,	{0x83, 0x74, 0xff, 0xf0, 0xf5, 0x4d, 0xe5, 0x4d, 0x60, 0x03, 0x02, 0x99, 0x9e, 0x90, 0x01, 0xc0} },
+{ 0x9790,	16,	{0xf0, 0xa3, 0x74, 0x96, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xf6, 0x7f} },
+{ 0x97a0,	16,	{0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xef, 0x54, 0x0f, 0xf5} },
+{ 0x97b0,	16,	{0x4d, 0x90, 0x02, 0xf7, 0xe0, 0x55, 0x4d, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f} },
+{ 0x97c0,	16,	{0x4c, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xe0, 0xb4, 0x05, 0x0c, 0xe5, 0x4c, 0x70, 0x04, 0x7f} },
+{ 0x97d0,	16,	{0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f, 0x4c, 0xe5, 0x4c, 0x70, 0x03, 0x02, 0x99, 0x9e, 0xe4, 0x90} },
+{ 0x97e0,	16,	{0x03, 0x38, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52, 0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x97f0,	16,	{0xff, 0xfd, 0x12, 0x82, 0x50, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0x85} },
+{ 0x9800,	16,	{0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85, 0x4f, 0x82, 0x85} },
+{ 0x9810,	16,	{0x4e, 0x83, 0x74, 0x01, 0xf0, 0xa3, 0xe4, 0xf0, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0xa3} },
+{ 0x9820,	16,	{0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xd2, 0x04, 0x02, 0x99, 0x9e, 0xc2, 0x04, 0x7e, 0x20, 0x7f, 0x00} },
+{ 0x9830,	16,	{0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0xe5, 0x4f, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4e, 0xf5} },
+{ 0x9840,	16,	{0x83, 0xe0, 0x30, 0xe6, 0xf1, 0xe4, 0xff, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x9850,	16,	{0xf5, 0x4d, 0xf5, 0x4b, 0xaf, 0x4b, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0xe5, 0x4b, 0x75, 0xf0, 0x08} },
+{ 0x9860,	16,	{0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x4e, 0x8f, 0x4f, 0xf5, 0x83} },
+{ 0x9870,	16,	{0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf} },
+{ 0x9880,	16,	{0x4b, 0x7d, 0x01, 0x7b, 0x01, 0x75, 0x57, 0x80, 0x75, 0x58, 0x40, 0x12, 0x94, 0xac, 0x8f, 0x4d} },
+{ 0x9890,	16,	{0xe5, 0x4d, 0x70, 0x11, 0xaf, 0x4b, 0x7d, 0x02, 0x7b, 0x01, 0x75, 0x57, 0x10, 0x75, 0x58, 0x20} },
+{ 0x98a0,	16,	{0x12, 0x94, 0xac, 0x8f, 0x4d, 0xe5, 0x4d, 0x70, 0x10, 0xaf, 0x4b, 0x7d, 0x01, 0xfb, 0x75, 0x57} },
+{ 0x98b0,	16,	{0x80, 0x75, 0x58, 0x40, 0x12, 0x94, 0xac, 0x8f, 0x4d, 0xe5, 0x4d, 0x70, 0x10, 0xaf, 0x4b, 0x7d} },
+{ 0x98c0,	16,	{0x02, 0xfb, 0x75, 0x57, 0x10, 0x75, 0x58, 0x20, 0x12, 0x94, 0xac, 0x8f, 0x4d, 0xaf, 0x4b, 0x7d} },
+{ 0x98d0,	16,	{0x01, 0x12, 0x82, 0x50, 0xe5, 0x4d, 0x60, 0x26, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04} },
+{ 0x98e0,	16,	{0xff, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
+{ 0x98f0,	16,	{0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52, 0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0x05, 0x4b} },
+{ 0x9900,	16,	{0xe5, 0x4b, 0xd3, 0x94, 0x03, 0x50, 0x03, 0x02, 0x98, 0x54, 0x02, 0x99, 0x9e, 0xe4, 0x90, 0x03} },
+{ 0x9910,	16,	{0x59, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74} },
+{ 0x9920,	16,	{0x1b, 0xf0, 0xa3, 0x74, 0x29, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08} },
+{ 0x9930,	16,	{0x60, 0x6c, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0x80, 0x65, 0xe4, 0x90, 0x03, 0x59, 0xf0, 0xa3, 0xf0} },
+{ 0x9940,	16,	{0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0xe5, 0x52, 0xf0, 0xa3, 0xe5} },
+{ 0x9950,	16,	{0x53, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x19, 0xc1, 0xef, 0x64, 0x08, 0x60, 0x40, 0xe4, 0x90} },
+{ 0x9960,	16,	{0x03, 0x38, 0xf0, 0x80, 0x39, 0xe4, 0x90, 0x03, 0x59, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0} },
+{ 0x9970,	16,	{0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xe5, 0x51, 0x24, 0x02, 0x90, 0x03, 0x60, 0xf0, 0xe4, 0x35} },
+{ 0x9980,	16,	{0x50, 0x90, 0x03, 0x5f, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08, 0x60} },
+{ 0x9990,	16,	{0x0d, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0x80, 0x06, 0x90, 0x03, 0x38, 0x74, 0x01, 0xf0, 0x90, 0x01} },
+{ 0x99a0,	16,	{0xc0, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70} },
+{ 0x99b0,	16,	{0xf6, 0x7e, 0x03, 0x7f, 0x35, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75, 0x5d} },
+{ 0x99c0,	11,	{0x00, 0x7d, 0x24, 0x12, 0x8e, 0x0c, 0xe4, 0x90, 0x02, 0xaf, 0xf0} },
+{ 0x99cb,	1,	{0x22} },
+{ 0x99cc,	16,	{0xe4, 0xff, 0x74, 0xf8, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02} },
+{ 0x99dc,	16,	{0x9a, 0x6f, 0x74, 0x36, 0x2f, 0xf8, 0xe6, 0x20, 0xe5, 0x03, 0x02, 0x9a, 0x6f, 0xef, 0x75, 0xf0} },
+{ 0x99ec,	16,	{0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xad, 0x82, 0xfc, 0xf5, 0x83, 0xe5, 0x82} },
+{ 0x99fc,	16,	{0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x60, 0x64, 0x60, 0x70, 0x63} },
+{ 0x9a0c,	16,	{0xef, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01} },
+{ 0x9a1c,	16,	{0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0, 0x8d, 0x82, 0x8c, 0x83, 0xf0, 0x74, 0xf8} },
+{ 0x9a2c,	16,	{0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x14, 0xf0, 0x70, 0x36, 0xef, 0x25, 0xe0} },
+{ 0x9a3c,	16,	{0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0xef, 0x25, 0xe0, 0xfe, 0xc3} },
+{ 0x9a4c,	16,	{0x74, 0x0c, 0x9e, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xad} },
+{ 0x9a5c,	16,	{0x82, 0xfc, 0xef, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xec, 0xf0} },
+{ 0x9a6c,	12,	{0xa3, 0xed, 0xf0, 0x0f, 0xef, 0x64, 0x04, 0x60, 0x03, 0x02, 0x99, 0xce} },
+{ 0x9a78,	1,	{0x22} },
+{ 0x9a79,	16,	{0xe7, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e} },
+{ 0x9a89,	16,	{0x88, 0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08} },
+{ 0x9a99,	16,	{0xdf, 0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83} },
+{ 0x9aa9,	16,	{0xe3, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08} },
+{ 0x9ab9,	16,	{0xdf, 0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c} },
+{ 0x9ac9,	16,	{0x80, 0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10} },
+{ 0x9ad9,	16,	{0x80, 0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33} },
+{ 0x9ae9,	16,	{0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83} },
+{ 0x9af9,	16,	{0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80} },
+{ 0x9b09,	16,	{0x0d, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0} },
+{ 0x9b19,	16,	{0xed, 0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc} },
+{ 0x9b29,	16,	{0xc5, 0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde} },
+{ 0x9b39,	16,	{0xe8, 0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc} },
+{ 0x9b49,	16,	{0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xc2, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4} },
+{ 0x9b59,	16,	{0x04, 0x00, 0x50, 0xb8, 0x23, 0x23, 0x45, 0x82, 0xf5, 0x82, 0xef, 0x4e, 0x60, 0xae, 0xef, 0x60} },
+{ 0x9b69,	9,	{0x01, 0x0e, 0xe5, 0x82, 0x23, 0x90, 0x9a, 0xc9, 0x73} },
+{ 0x9b72,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x9b82,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x9b8b,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x9b9b,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x9bab,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x9bb8,	16,	{0xc5, 0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02} },
+{ 0x9bc8,	6,	{0x15, 0x83, 0xe0, 0x38, 0xf0, 0x22} },
+{ 0x9bce,	16,	{0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83} },
+{ 0x9bde,	6,	{0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22} },
+{ 0x9be4,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x9bf4,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x9c04,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x9c14,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x9c1c,	16,	{0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc} },
+{ 0x9c2c,	16,	{0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40} },
+{ 0x9c3c,	16,	{0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6} },
+{ 0x9c4c,	16,	{0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9} },
+{ 0x9c5c,	16,	{0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb} },
+{ 0x9c6c,	16,	{0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb} },
+{ 0x9c7c,	16,	{0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9} },
+{ 0x9c8c,	16,	{0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc} },
+{ 0x9c9c,	16,	{0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a} },
+{ 0x9cac,	16,	{0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f} },
+{ 0x9cbc,	16,	{0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07} },
+{ 0x9ccc,	16,	{0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8} },
+{ 0x9cdc,	14,	{0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22} },
+{ 0x9cea,	16,	{0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x9cfa,	1,	{0x22} },
+{ 0x9cfb,	16,	{0xe8, 0x60, 0x0f, 0xec, 0xc3, 0x13, 0xfc, 0xed, 0x13, 0xfd, 0xee, 0x13, 0xfe, 0xef, 0x13, 0xff} },
+{ 0x9d0b,	3,	{0xd8, 0xf1, 0x22} },
+{ 0x9d0e,	16,	{0x08, 0x08, 0x08, 0xe6, 0xcf, 0x2f, 0xf6, 0x18, 0xe6, 0xce, 0x3e, 0xf6, 0x18, 0xe6, 0xcd, 0x3d} },
+{ 0x9d1e,	7,	{0xf6, 0x18, 0xe6, 0xcc, 0x3c, 0xf6, 0x22} },
+{ 0x9d25,	12,	{0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
+{ 0x9d31,	16,	{0xa8, 0x82, 0x85, 0x83, 0xf0, 0xd0, 0x83, 0xd0, 0x82, 0x12, 0x9d, 0x48, 0x12, 0x9d, 0x48, 0x12} },
+{ 0x9d41,	16,	{0x9d, 0x48, 0x12, 0x9d, 0x48, 0xe4, 0x73, 0xe4, 0x93, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83} },
+{ 0x9d51,	16,	{0xc8, 0xc5, 0x82, 0xc8, 0xf0, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83, 0xc8, 0xc5, 0x82, 0xc8} },
+{ 0x9d61,	1,	{0x22} },
+{ 0xffff,	0,	{0x00} }
+};
+
+#ifdef DEBUG
+static const struct whiteheat_hex_record whiteheat_loader[] = {
+{ 0x0000,	3,	{0x02, 0x09, 0x8d} },
+{ 0x0033,	3,	{0x02, 0x0e, 0x70} },
+{ 0x0043,	3,	{0x02, 0x0b, 0x00} },
+{ 0x004b,	3,	{0x02, 0x05, 0xb3} },
+{ 0x0100,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x54, 0x10, 0xff, 0xc4, 0x54, 0x0f, 0x44, 0x50, 0xf5, 0x0f, 0x13, 0xe4} },
+{ 0x0110,	16,	{0x33, 0xf5, 0x11, 0x90, 0x7f, 0xe9, 0xe0, 0x24, 0x5e, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x03} },
+{ 0x0120,	16,	{0x7c, 0x90, 0x01, 0x28, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x01, 0xbc, 0x02, 0x01, 0xbc, 0x02, 0x01} },
+{ 0x0130,	16,	{0x91, 0x02, 0x01, 0x3d, 0x02, 0x01, 0x53, 0x02, 0x01, 0x6f, 0x02, 0x01, 0x9a, 0x90, 0x7f, 0x00} },
+{ 0x0140,	16,	{0xe5, 0x11, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0150,	16,	{0x02, 0x03, 0x7c, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x90, 0x7f, 0x00, 0xf0, 0x90} },
+{ 0x0160,	16,	{0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03, 0x7c, 0x12} },
+{ 0x0170,	16,	{0x0a, 0x89, 0x50, 0x07, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0x80, 0x06, 0x90, 0x7f, 0x00, 0x74, 0x0f} },
+{ 0x0180,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03} },
+{ 0x0190,	16,	{0x7c, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0f, 0x02, 0x03, 0x7c, 0x90, 0x7f, 0x00, 0x74, 0x07, 0xf0} },
+{ 0x01a0,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xe8, 0x7e} },
+{ 0x01b0,	16,	{0x03, 0x12, 0x0d, 0xd5, 0xd2, 0x06, 0x12, 0x0d, 0x0d, 0x02, 0x03, 0x7c, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x01c0,	16,	{0x75, 0x29, 0x00, 0xf5, 0x2a, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x29, 0x90, 0x7f, 0xee, 0xe0} },
+{ 0x01d0,	16,	{0x75, 0x2b, 0x00, 0xf5, 0x2c, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x2b, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x01e0,	16,	{0x64, 0xc0, 0x60, 0x03, 0x02, 0x02, 0xc9, 0xe5, 0x2c, 0x45, 0x2b, 0x70, 0x03, 0x02, 0x03, 0x7c} },
+{ 0x01f0,	16,	{0xc3, 0xe5, 0x2c, 0x94, 0x40, 0xe5, 0x2b, 0x94, 0x00, 0x50, 0x08, 0x85, 0x2b, 0x2d, 0x85, 0x2c} },
+{ 0x0200,	16,	{0x2e, 0x80, 0x06, 0x75, 0x2d, 0x00, 0x75, 0x2e, 0x40, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70} },
+{ 0x0210,	16,	{0x34, 0xf5, 0x31, 0xf5, 0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5, 0x31, 0x95, 0x2d, 0x50, 0x5c} },
+{ 0x0220,	16,	{0xe5, 0x2a, 0x25, 0x32, 0xf5, 0x82, 0xe5, 0x31, 0x35, 0x29, 0xf5, 0x83, 0xe0, 0xff, 0x74, 0x00} },
+{ 0x0230,	16,	{0x25, 0x32, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70} },
+{ 0x0240,	16,	{0x02, 0x05, 0x31, 0x80, 0xd0, 0xe4, 0xf5, 0x31, 0xf5, 0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5} },
+{ 0x0250,	16,	{0x31, 0x95, 0x2d, 0x50, 0x18, 0x74, 0x00, 0x25, 0x32, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83} },
+{ 0x0260,	16,	{0x74, 0xcd, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70, 0x02, 0x05, 0x31, 0x80, 0xdd, 0xaf, 0x2a, 0xae} },
+{ 0x0270,	16,	{0x29, 0xad, 0x2e, 0x7a, 0x7f, 0x79, 0x00, 0x7b, 0x00, 0x12, 0x0b, 0xf4, 0x90, 0x7f, 0xb5, 0xe5} },
+{ 0x0280,	16,	{0x2e, 0xf0, 0xe5, 0x2e, 0x25, 0x2a, 0xf5, 0x2a, 0xe5, 0x2d, 0x35, 0x29, 0xf5, 0x29, 0xc3, 0xe5} },
+{ 0x0290,	16,	{0x2c, 0x95, 0x2e, 0xf5, 0x2c, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0x90, 0x7f, 0x92, 0xe0, 0xff} },
+{ 0x02a0,	16,	{0xc4, 0x54, 0x0f, 0x75, 0x2f, 0x00, 0xf5, 0x30, 0xd3, 0x94, 0x00, 0xe5, 0x2f, 0x94, 0x00, 0x50} },
+{ 0x02b0,	16,	{0x0c, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe1, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xb4} },
+{ 0x02c0,	16,	{0xe0, 0x20, 0xe2, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xe8, 0xe0, 0x64, 0x40, 0x60} },
+{ 0x02d0,	16,	{0x03, 0x02, 0x03, 0x7c, 0xe5, 0x2c, 0x45, 0x2b, 0x70, 0x03, 0x02, 0x03, 0x7c, 0xe4, 0x90, 0x7f} },
+{ 0x02e0,	16,	{0xc5, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x75, 0x2f, 0x00, 0xf5, 0x30, 0xd3} },
+{ 0x02f0,	16,	{0x94, 0x00, 0xe5, 0x2f, 0x94, 0x00, 0x50, 0x09, 0x90, 0x7f, 0xc4, 0xe0, 0x30, 0xe1, 0x09, 0x80} },
+{ 0x0300,	16,	{0xf7, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe3, 0xf9, 0x90, 0x7f, 0xc5, 0xe0, 0x75, 0x2d, 0x00, 0xf5} },
+{ 0x0310,	16,	{0x2e, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70, 0x38, 0x90, 0x20, 0x6b, 0xf0, 0xf5, 0x31, 0xf5} },
+{ 0x0320,	16,	{0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5, 0x31, 0x95, 0x2d, 0x50, 0x34, 0x74, 0xc0, 0x25, 0x32} },
+{ 0x0330,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x2a, 0x25, 0x32, 0xf5, 0x82, 0xe5} },
+{ 0x0340,	16,	{0x31, 0x35, 0x29, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70, 0x02, 0x05, 0x31, 0x80} },
+{ 0x0350,	16,	{0xd0, 0xaf, 0x2a, 0xae, 0x29, 0xad, 0x2e, 0x7a, 0x7e, 0x79, 0xc0, 0x7b, 0xc0, 0x12, 0x0c, 0x80} },
+{ 0x0360,	16,	{0xe5, 0x2e, 0x25, 0x2a, 0xf5, 0x2a, 0xe5, 0x2d, 0x35, 0x29, 0xf5, 0x29, 0xc3, 0xe5, 0x2c, 0x95} },
+{ 0x0370,	13,	{0x2e, 0xf5, 0x2c, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0x02, 0x02, 0xd4, 0xc3} },
+{ 0x037d,	1,	{0x22} },
+{ 0x037e,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x56, 0x14, 0x70, 0x03, 0x02, 0x04, 0xd2, 0x24} },
+{ 0x038e,	16,	{0xfe, 0x70, 0x03, 0x02, 0x05, 0x46, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x50, 0x14, 0x70, 0x03} },
+{ 0x039e,	16,	{0x02, 0x04, 0x4a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3e, 0x14, 0x70, 0x03, 0x02, 0x04, 0x44, 0x24} },
+{ 0x03ae,	16,	{0x05, 0x60, 0x03, 0x02, 0x05, 0x9a, 0x12, 0x0e, 0x7b, 0x40, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f} },
+{ 0x03be,	16,	{0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02, 0x70, 0x69, 0x74, 0x11, 0x90} },
+{ 0x03ce,	16,	{0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x03de,	16,	{0xff, 0x12, 0x0b, 0x58, 0x8b, 0x26, 0x8a, 0x27, 0x89, 0x28, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02} },
+{ 0x03ee,	16,	{0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90} },
+{ 0x03fe,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0c} },
+{ 0x040e,	16,	{0x3f, 0x8b, 0x26, 0x8a, 0x27, 0x89, 0x28, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f} },
+{ 0x041e,	16,	{0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x042e,	16,	{0x44, 0x01, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xab} },
+{ 0x043e,	16,	{0x12, 0x0e, 0x52, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x60, 0x02, 0x05, 0xab, 0x12, 0x0a, 0xf7, 0x02} },
+{ 0x044e,	16,	{0x05, 0xab, 0x12, 0x08, 0xf1, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x7d, 0x40, 0x03, 0x02, 0x05, 0xab} },
+{ 0x045e,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
+{ 0x046e,	16,	{0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x02, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
+{ 0x047e,	16,	{0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0xe4, 0x90, 0x7f, 0x00} },
+{ 0x048e,	16,	{0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x049e,	16,	{0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x04ae,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
+{ 0x04be,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x04ce,	16,	{0xf0, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x7f, 0x40, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x04de,	16,	{0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0, 0xb4} },
+{ 0x04ee,	16,	{0x01, 0x05, 0xc2, 0x00, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05} },
+{ 0x04fe,	16,	{0xab, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4} },
+{ 0x050e,	16,	{0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f} },
+{ 0x051e,	16,	{0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f} },
+{ 0x052e,	16,	{0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x6e, 0x90} },
+{ 0x053e,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x65, 0x12, 0x0e, 0x81, 0x50, 0x60, 0x90, 0x7f, 0xe8} },
+{ 0x054e,	16,	{0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x54, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
+{ 0x055e,	16,	{0xd2, 0x00, 0x80, 0x49, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x40, 0x90, 0x7f, 0xea} },
+{ 0x056e,	16,	{0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
+{ 0x057e,	16,	{0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
+{ 0x058e,	16,	{0xf0, 0x80, 0x1a, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xe4, 0x90, 0x20, 0x6a} },
+{ 0x059e,	16,	{0xf0, 0x12, 0x01, 0x00, 0x50, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4} },
+{ 0x05ae,	4,	{0xe0, 0x44, 0x02, 0xf0} },
+{ 0x05b2,	1,	{0x22} },
+{ 0x05b3,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x05c3,	16,	{0xd0, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x06, 0xc0, 0x07, 0x90, 0x7f, 0xa5} },
+{ 0x05d3,	16,	{0xe0, 0x30, 0xe2, 0x06, 0x75, 0x0d, 0x06, 0x02, 0x06, 0x7f, 0x90, 0x7f, 0xa5, 0xe0, 0x20, 0xe1} },
+{ 0x05e3,	16,	{0x0c, 0xe5, 0x0d, 0x64, 0x02, 0x60, 0x06, 0x75, 0x0d, 0x07, 0x02, 0x06, 0x7f, 0xaf, 0x0d, 0xef} },
+{ 0x05f3,	16,	{0x24, 0xfe, 0x60, 0x48, 0x14, 0x60, 0x2c, 0x24, 0xfe, 0x60, 0x77, 0x24, 0x04, 0x60, 0x03, 0x02} },
+{ 0x0603,	16,	{0x06, 0x7f, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xaf, 0x0c, 0x05, 0x0c, 0x8f, 0x82, 0x75, 0x83} },
+{ 0x0613,	16,	{0x00, 0x12, 0x07, 0x85, 0x90, 0x7f, 0xa6, 0xf0, 0xe5, 0x0c, 0x65, 0x08, 0x70, 0x5e, 0x75, 0x0d} },
+{ 0x0623,	16,	{0x05, 0x80, 0x59, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e} },
+{ 0x0633,	16,	{0x82, 0x75, 0x83, 0x00, 0x12, 0x07, 0xb2, 0x75, 0x0d, 0x02, 0x80, 0x40, 0xe5, 0x08, 0x24, 0xfe} },
+{ 0x0643,	16,	{0xb5, 0x0c, 0x07, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0xe5, 0x08, 0x14, 0xb5, 0x0c, 0x0a} },
+{ 0x0653,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09} },
+{ 0x0663,	16,	{0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e, 0x82, 0x75, 0x83, 0x00, 0x12, 0x07, 0xb2, 0x05, 0x0c} },
+{ 0x0673,	16,	{0x80, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x53, 0x91, 0xdf, 0xd0} },
+{ 0x0683,	16,	{0x07, 0xd0, 0x06, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x86, 0xd0} },
+{ 0x0693,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x069d,	16,	{0xc2, 0x04, 0xd2, 0x05, 0xe4, 0xf5, 0x25, 0xc2, 0x03, 0xc2, 0x00, 0xc2, 0x02, 0xc2, 0x01, 0x12} },
+{ 0x06ad,	16,	{0x0e, 0x74, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9} },
+{ 0x06bd,	16,	{0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0x90} },
+{ 0x06cd,	16,	{0x7f, 0x93, 0x74, 0x30, 0xf0, 0x12, 0x0a, 0x19, 0x75, 0x24, 0x48, 0x75, 0x23, 0x92, 0x75, 0x22} },
+{ 0x06dd,	16,	{0x00, 0x75, 0x21, 0x00, 0xe4, 0xff, 0xfe, 0x7e, 0x05, 0x90, 0x20, 0x68, 0x74, 0x01, 0xf0, 0xa3} },
+{ 0x06ed,	16,	{0xde, 0xfc, 0x7e, 0x00, 0x7f, 0x05, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae} },
+{ 0x06fd,	16,	{0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0x12, 0x0e, 0x68, 0x30, 0x01, 0x0a, 0xe4, 0x90, 0x20, 0x69} },
+{ 0x070d,	16,	{0xf0, 0x12, 0x03, 0x7e, 0xc2, 0x01, 0x30, 0x04, 0x1a, 0x12, 0x0e, 0x77, 0x50, 0x13, 0x12, 0x09} },
+{ 0x071d,	16,	{0x00, 0x30, 0x00, 0x07, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0xf3, 0x12, 0x0d, 0x8b, 0x12, 0x0e} },
+{ 0x072d,	16,	{0x79, 0xc2, 0x03, 0x7f, 0xff, 0x7e, 0xff, 0x7d, 0xff, 0x7c, 0xff, 0x78, 0x21, 0x12, 0x08, 0x1d} },
+{ 0x073d,	16,	{0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x08, 0x0c, 0x70, 0x1b, 0x75, 0x24} },
+{ 0x074d,	16,	{0x48, 0x75, 0x23, 0x92, 0xf5, 0x22, 0xf5, 0x21, 0x63, 0x25, 0xff, 0x90, 0x20, 0x68, 0xe5, 0x25} },
+{ 0x075d,	14,	{0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0x12, 0x08, 0xff, 0x80, 0x9b} },
+{ 0x076b,	1,	{0x22} },
+{ 0x076c,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x077c,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0785,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x0795,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x07a5,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x07b2,	16,	{0xf8, 0xbb, 0x01, 0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0} },
+{ 0x07c2,	16,	{0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8} },
+{ 0x07d2,	2,	{0xf2, 0x22} },
+{ 0x07d4,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x07e4,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x07f4,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x0804,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x080c,	16,	{0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x081c,	1,	{0x22} },
+{ 0x081d,	16,	{0x08, 0x08, 0x08, 0xe6, 0x2f, 0xff, 0xf6, 0x18, 0xe6, 0x3e, 0xfe, 0xf6, 0x18, 0xe6, 0x3d, 0xfd} },
+{ 0x082d,	7,	{0xf6, 0x18, 0xe6, 0x3c, 0xfc, 0xf6, 0x22} },
+{ 0x0834,	4,	{0x8c, 0x34, 0x8d, 0x35} },
+{ 0x0838,	16,	{0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0xe4, 0xf5, 0x36, 0xf5, 0x37, 0xc3, 0xe5, 0x37, 0x95} },
+{ 0x0848,	16,	{0x35, 0xe5, 0x36, 0x95, 0x34, 0x50, 0x69, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5} },
+{ 0x0858,	16,	{0x83, 0x74, 0xff, 0xf0, 0xf4, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36} },
+{ 0x0868,	16,	{0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36} },
+{ 0x0878,	16,	{0x3e, 0xf5, 0x83, 0x74, 0xaa, 0xf0, 0x64, 0xaa, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5} },
+{ 0x0888,	16,	{0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0x74, 0x55, 0xf0, 0x64, 0x55, 0x60, 0x02, 0xc3, 0x22, 0xad} },
+{ 0x0898,	16,	{0x37, 0xe5, 0x37, 0x2f, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xed, 0xf0, 0xfc, 0xac, 0x05} },
+{ 0x08a8,	16,	{0xed, 0x6c, 0x60, 0x02, 0xc3, 0x22, 0x05, 0x37, 0xe5, 0x37, 0x70, 0x02, 0x05, 0x36, 0x80, 0x8c} },
+{ 0x08b8,	16,	{0xe4, 0xf5, 0x36, 0xf5, 0x37, 0xc3, 0xe5, 0x37, 0x95, 0x35, 0xe5, 0x36, 0x95, 0x34, 0x50, 0x27} },
+{ 0x08c8,	16,	{0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xe0, 0x65, 0x37, 0x60, 0x02, 0xc3} },
+{ 0x08d8,	16,	{0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x37, 0xe5} },
+{ 0x08e8,	8,	{0x37, 0x70, 0x02, 0x05, 0x36, 0x80, 0xce, 0xd3} },
+{ 0x08f0,	1,	{0x22} },
+{ 0x08f1,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x10, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x08ff,	1,	{0x22} },
+{ 0x0900,	9,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x097d,	16,	{0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x098d,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x3a, 0x02, 0x09, 0xd4} },
+{ 0x0999,	16,	{0x02, 0x06, 0x9d, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x09a9,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x09b9,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x09c9,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0e, 0x2d, 0xe4, 0x7e} },
+{ 0x09d9,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x09e9,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x09f9,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x0a09,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x0a19,	16,	{0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0a29,	16,	{0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0d, 0xd5, 0x90, 0x7f} },
+{ 0x0a39,	16,	{0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a49,	16,	{0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02, 0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05} },
+{ 0x0a59,	16,	{0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a69,	16,	{0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d} },
+{ 0x0a79,	16,	{0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x22} },
+{ 0x0a89,	16,	{0x75, 0x33, 0x01, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x01, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x0e} },
+{ 0x0a99,	16,	{0x7d, 0x00, 0x7c, 0x01, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12} },
+{ 0x0aa9,	16,	{0x0e, 0x18, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x02, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x80, 0x7d} },
+{ 0x0ab9,	16,	{0x00, 0x7c, 0x80, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0e} },
+{ 0x0ac9,	16,	{0x18, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x03, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x20, 0x7d, 0x40} },
+{ 0x0ad9,	16,	{0x7c, 0x5b, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0e, 0x18} },
+{ 0x0ae9,	13,	{0xe5, 0x33, 0x60, 0x05, 0xe4, 0xff, 0x12, 0x0e, 0x18, 0xe5, 0x33, 0x24, 0xff} },
+{ 0x0af6,	1,	{0x22} },
+{ 0x0af7,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x10, 0xd3, 0x22} },
+{ 0x0aff,	1,	{0x32} },
+{ 0x0b00,	16,	{0x02, 0x0d, 0xa5, 0x00, 0x02, 0x0d, 0xec, 0x00, 0x02, 0x0d, 0x70, 0x00, 0x02, 0x0d, 0xbd, 0x00} },
+{ 0x0b10,	16,	{0x02, 0x0e, 0x02, 0x00, 0x02, 0x0a, 0xff, 0x00, 0x02, 0x0e, 0x83, 0x00, 0x02, 0x0e, 0x84, 0x00} },
+{ 0x0b20,	16,	{0x02, 0x0e, 0x85, 0x00, 0x02, 0x0e, 0x86, 0x00, 0x02, 0x0e, 0x87, 0x00, 0x02, 0x0e, 0x88, 0x00} },
+{ 0x0b30,	16,	{0x02, 0x0e, 0x89, 0x00, 0x02, 0x0e, 0x8a, 0x00, 0x02, 0x0e, 0x8b, 0x00, 0x02, 0x0e, 0x8c, 0x00} },
+{ 0x0b40,	16,	{0x02, 0x0e, 0x8d, 0x00, 0x02, 0x0e, 0x8e, 0x00, 0x02, 0x0e, 0x8f, 0x00, 0x02, 0x0e, 0x90, 0x00} },
+{ 0x0b50,	8,	{0x02, 0x0e, 0x91, 0x00, 0x02, 0x0e, 0x92, 0x00} },
+{ 0x0b58,	16,	{0xe4, 0xfe, 0x75, 0x2b, 0xff, 0x75, 0x2c, 0x11, 0x75, 0x2d, 0x12, 0xab, 0x2b, 0xaa, 0x2c, 0xa9} },
+{ 0x0b68,	16,	{0x2d, 0x90, 0x00, 0x01, 0x12, 0x07, 0x85, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x0b78,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x07, 0xd4, 0x85, 0xf0, 0x29, 0xf5, 0x2a, 0x62, 0x29} },
+{ 0x0b88,	16,	{0xe5, 0x29, 0x62, 0x2a, 0xe5, 0x2a, 0x62, 0x29, 0x29, 0xfd, 0xe5, 0x29, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x0b98,	14,	{0x2b, 0xff, 0xf5, 0x2c, 0x89, 0x2d, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0ba6,	1,	{0x22} },
+{ 0x0ba7,	6,	{0xab, 0x07, 0xaa, 0x06, 0xac, 0x05} },
+{ 0x0bad,	16,	{0xe4, 0xfd, 0xe5, 0x11, 0x60, 0x11, 0xea, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24, 0x10, 0xf5, 0x82} },
+{ 0x0bbd,	16,	{0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xeb, 0xae, 0x05, 0x0d, 0x74, 0x10, 0x2e, 0xf5, 0x82} },
+{ 0x0bcd,	16,	{0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xeb, 0xf0, 0xaf, 0x05, 0x0d, 0x74, 0x10, 0x2f, 0xf5, 0x82, 0xe4} },
+{ 0x0bdd,	16,	{0x34, 0x0f, 0xf5, 0x83, 0xec, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f, 0x7b, 0x10, 0x12, 0x0d, 0x51, 0x7f} },
+{ 0x0bed,	6,	{0x0a, 0x7e, 0x00, 0x12, 0x0d, 0xd5} },
+{ 0x0bf3,	1,	{0x22} },
+{ 0x0bf4,	10,	{0x8e, 0x33, 0x8f, 0x34, 0x8d, 0x35, 0x8a, 0x36, 0x8b, 0x37} },
+{ 0x0bfe,	16,	{0xe4, 0xfd, 0xf5, 0x38, 0xe5, 0x11, 0x60, 0x12, 0xe5, 0x33, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24} },
+{ 0x0c0e,	16,	{0x13, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x34, 0xae, 0x05, 0x0d, 0x74} },
+{ 0x0c1e,	16,	{0x13, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xe5, 0x34, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f} },
+{ 0x0c2e,	16,	{0x7b, 0x13, 0x12, 0x0d, 0x51, 0xaf, 0x0f, 0xad, 0x35, 0xab, 0x37, 0xaa, 0x36, 0x12, 0x0d, 0x32} },
+{ 0x0c3e,	1,	{0x22} },
+{ 0x0c3f,	2,	{0x8f, 0x29} },
+{ 0x0c41,	16,	{0xe4, 0xf5, 0x2a, 0x75, 0x2b, 0xff, 0x75, 0x2c, 0x11, 0x75, 0x2d, 0x32, 0xab, 0x2b, 0xaa, 0x2c} },
+{ 0x0c51,	16,	{0xa9, 0x2d, 0x90, 0x00, 0x01, 0x12, 0x07, 0x85, 0xb4, 0x03, 0x1d, 0xaf, 0x2a, 0x05, 0x2a, 0xef} },
+{ 0x0c61,	16,	{0xb5, 0x29, 0x01, 0x22, 0x12, 0x07, 0x6c, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x0c71,	14,	{0x2b, 0xff, 0xf5, 0x2c, 0x89, 0x2d, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0c7f,	1,	{0x22} },
+{ 0x0c80,	10,	{0x8e, 0x33, 0x8f, 0x34, 0x8d, 0x35, 0x8a, 0x36, 0x8b, 0x37} },
+{ 0x0c8a,	16,	{0xe4, 0xf5, 0x38, 0xe5, 0x38, 0xc3, 0x95, 0x35, 0x50, 0x20, 0x05, 0x34, 0xe5, 0x34, 0xae, 0x33} },
+{ 0x0c9a,	16,	{0x70, 0x02, 0x05, 0x33, 0x14, 0xff, 0xe5, 0x37, 0x25, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x36, 0xf5} },
+{ 0x0caa,	10,	{0x83, 0xe0, 0xfd, 0x12, 0x0b, 0xa7, 0x05, 0x38, 0x80, 0xd9} },
+{ 0x0cb4,	1,	{0x22} },
+{ 0x0cb5,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x25, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0cc5,	16,	{0x44, 0x01, 0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a} },
+{ 0x0cd5,	13,	{0x0a, 0x89, 0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x03, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0ce2,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0cf2,	16,	{0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a, 0x0a, 0x89} },
+{ 0x0d02,	11,	{0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x01, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0d0d,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x06, 0x04, 0xe0, 0x44} },
+{ 0x0d1d,	16,	{0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x0d2d,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x0d32,	16,	{0x12, 0x0c, 0xb5, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d42,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d51,	16,	{0x12, 0x0c, 0xe2, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d61,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d70,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0d80,	11,	{0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d8b,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x12, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x14, 0x7e, 0x00, 0x12} },
+{ 0x0d9b,	10,	{0x0d, 0xd5, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
+{ 0x0da5,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0db5,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dbd,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x03, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x0dcd,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dd5,	16,	{0x8e, 0x39, 0x8f, 0x3a, 0xe5, 0x3a, 0x15, 0x3a, 0xae, 0x39, 0x70, 0x02, 0x15, 0x39, 0x4e, 0x60} },
+{ 0x0de5,	7,	{0x05, 0x12, 0x0e, 0x41, 0x80, 0xee, 0x22} },
+{ 0x0dec,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0} },
+{ 0x0dfc,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e02,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0e12,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e18,	16,	{0xae, 0x07, 0x7f, 0x21, 0x7d, 0x01, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xab, 0x82} },
+{ 0x0e28,	5,	{0xfa, 0x12, 0x0d, 0x51, 0x22} },
+{ 0x0e2d,	16,	{0x50, 0x0f, 0x00, 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, 0x88, 0x83, 0xc6} },
+{ 0x0e3d,	3,	{0xa1, 0x86, 0x8e} },
+{ 0x0e40,	1,	{0x00} },
+{ 0x0e41,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x0e51,	1,	{0x22} },
+{ 0x0e52,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x0e, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x0e60,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0e, 0xd3, 0x22} },
+{ 0x0e68,	8,	{0xe4, 0xf5, 0x0d, 0xd2, 0xe9, 0xd2, 0xaf, 0x22} },
+{ 0x0e70,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x0e74,	3,	{0xd2, 0x00, 0x22} },
+{ 0x0e77,	2,	{0xd3, 0x22} },
+{ 0x0e79,	2,	{0xd3, 0x22} },
+{ 0x0e7b,	2,	{0xd3, 0x22} },
+{ 0x0e7d,	2,	{0xd3, 0x22} },
+{ 0x0e7f,	2,	{0xd3, 0x22} },
+{ 0x0e81,	2,	{0xd3, 0x22} },
+{ 0x0e83,	1,	{0x32} },
+{ 0x0e84,	1,	{0x32} },
+{ 0x0e85,	1,	{0x32} },
+{ 0x0e86,	1,	{0x32} },
+{ 0x0e87,	1,	{0x32} },
+{ 0x0e88,	1,	{0x32} },
+{ 0x0e89,	1,	{0x32} },
+{ 0x0e8a,	1,	{0x32} },
+{ 0x0e8b,	1,	{0x32} },
+{ 0x0e8c,	1,	{0x32} },
+{ 0x0e8d,	1,	{0x32} },
+{ 0x0e8e,	1,	{0x32} },
+{ 0x0e8f,	1,	{0x32} },
+{ 0x0e90,	1,	{0x32} },
+{ 0x0e91,	1,	{0x32} },
+{ 0x0e92,	1,	{0x32} },
+{ 0x1100,	16,	{0x12, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x47, 0x05, 0x10, 0x27, 0x01, 0x00, 0x01, 0x02} },
+{ 0x1110,	16,	{0x00, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x03, 0xa0, 0x00, 0x09, 0x04, 0x00, 0x00, 0x02} },
+{ 0x1120,	16,	{0xff, 0x00, 0x00, 0x04, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1130,	16,	{0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x26, 0x03, 0x41, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x68, 0x00} },
+{ 0x1140,	16,	{0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x43, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x73, 0x00} },
+{ 0x1150,	16,	{0x2c, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x28, 0x03, 0x46, 0x00} },
+{ 0x1160,	16,	{0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00} },
+{ 0x1170,	16,	{0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00} },
+{ 0x1180,	16,	{0x6b, 0x00, 0x73, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
+{ 0x1190,	16,	{0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
+{ 0x11a0,	16,	{0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
+{ 0x11b0,	16,	{0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
+{ 0x11c0,	16,	{0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
+{ 0x11d0,	2,	{0x00, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
+
+#else
+
+static const struct whiteheat_hex_record whiteheat_loader[] = {
+{ 0x0000,	3,	{0x02, 0x09, 0x8d} },
+{ 0x0033,	3,	{0x02, 0x08, 0xfb} },
+{ 0x0043,	3,	{0x02, 0x0b, 0x00} },
+{ 0x004b,	3,	{0x02, 0x05, 0xaa} },
+{ 0x0100,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x54, 0x10, 0xff, 0xc4, 0x54, 0x0f, 0x44, 0x50, 0xf5, 0x0f, 0x13, 0xe4} },
+{ 0x0110,	16,	{0x33, 0xf5, 0x11, 0x90, 0x7f, 0xe9, 0xe0, 0x24, 0x5e, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x03} },
+{ 0x0120,	16,	{0x78, 0x90, 0x01, 0x28, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x01, 0xbc, 0x02, 0x01, 0xbc, 0x02, 0x01} },
+{ 0x0130,	16,	{0x91, 0x02, 0x01, 0x3d, 0x02, 0x01, 0x53, 0x02, 0x01, 0x6f, 0x02, 0x01, 0x9a, 0x90, 0x7f, 0x00} },
+{ 0x0140,	16,	{0xe5, 0x11, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0150,	16,	{0x02, 0x03, 0x78, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x90, 0x7f, 0x00, 0xf0, 0x90} },
+{ 0x0160,	16,	{0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03, 0x78, 0x12} },
+{ 0x0170,	16,	{0x0a, 0x89, 0x50, 0x07, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0x80, 0x06, 0x90, 0x7f, 0x00, 0x74, 0x0f} },
+{ 0x0180,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03} },
+{ 0x0190,	16,	{0x78, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0f, 0x02, 0x03, 0x78, 0x90, 0x7f, 0x00, 0x74, 0x07, 0xf0} },
+{ 0x01a0,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xe8, 0x7e} },
+{ 0x01b0,	16,	{0x03, 0x12, 0x0d, 0x94, 0xd2, 0x06, 0x12, 0x0c, 0xcc, 0x02, 0x03, 0x78, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x01c0,	16,	{0x75, 0x28, 0x00, 0xf5, 0x29, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x28, 0x90, 0x7f, 0xee, 0xe0} },
+{ 0x01d0,	16,	{0x75, 0x2a, 0x00, 0xf5, 0x2b, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x2a, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x01e0,	16,	{0x64, 0xc0, 0x60, 0x03, 0x02, 0x02, 0xc9, 0xe5, 0x2b, 0x45, 0x2a, 0x70, 0x03, 0x02, 0x03, 0x78} },
+{ 0x01f0,	16,	{0xc3, 0xe5, 0x2b, 0x94, 0x40, 0xe5, 0x2a, 0x94, 0x00, 0x50, 0x08, 0x85, 0x2a, 0x2c, 0x85, 0x2b} },
+{ 0x0200,	16,	{0x2d, 0x80, 0x06, 0x75, 0x2c, 0x00, 0x75, 0x2d, 0x40, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70} },
+{ 0x0210,	16,	{0x34, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31, 0x95, 0x2d, 0xe5, 0x30, 0x95, 0x2c, 0x50, 0x5c} },
+{ 0x0220,	16,	{0xe5, 0x29, 0x25, 0x31, 0xf5, 0x82, 0xe5, 0x30, 0x35, 0x28, 0xf5, 0x83, 0xe0, 0xff, 0x74, 0x00} },
+{ 0x0230,	16,	{0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70} },
+{ 0x0240,	16,	{0x02, 0x05, 0x30, 0x80, 0xd0, 0xe4, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31, 0x95, 0x2d, 0xe5} },
+{ 0x0250,	16,	{0x30, 0x95, 0x2c, 0x50, 0x18, 0x74, 0x00, 0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83} },
+{ 0x0260,	16,	{0x74, 0xcd, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70, 0x02, 0x05, 0x30, 0x80, 0xdd, 0xaf, 0x29, 0xae} },
+{ 0x0270,	16,	{0x28, 0xad, 0x2d, 0x7a, 0x7f, 0x79, 0x00, 0x7b, 0x00, 0x12, 0x0b, 0xf4, 0x90, 0x7f, 0xb5, 0xe5} },
+{ 0x0280,	16,	{0x2d, 0xf0, 0xe5, 0x2d, 0x25, 0x29, 0xf5, 0x29, 0xe5, 0x2c, 0x35, 0x28, 0xf5, 0x28, 0xc3, 0xe5} },
+{ 0x0290,	16,	{0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0xe5, 0x2a, 0x95, 0x2c, 0xf5, 0x2a, 0x90, 0x7f, 0x92, 0xe0, 0xff} },
+{ 0x02a0,	16,	{0xc4, 0x54, 0x0f, 0x75, 0x2e, 0x00, 0xf5, 0x2f, 0xd3, 0x94, 0x00, 0xe5, 0x2e, 0x94, 0x00, 0x50} },
+{ 0x02b0,	16,	{0x0c, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe1, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xb4} },
+{ 0x02c0,	16,	{0xe0, 0x20, 0xe2, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xe8, 0xe0, 0x64, 0x40, 0x60} },
+{ 0x02d0,	16,	{0x03, 0x02, 0x03, 0x78, 0xe5, 0x2b, 0x45, 0x2a, 0x70, 0x03, 0x02, 0x03, 0x78, 0xe4, 0x90, 0x7f} },
+{ 0x02e0,	16,	{0xc5, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x75, 0x2e, 0x00, 0xf5, 0x2f, 0xd3} },
+{ 0x02f0,	16,	{0x94, 0x00, 0xe5, 0x2e, 0x94, 0x00, 0x50, 0x09, 0x90, 0x7f, 0xc4, 0xe0, 0x30, 0xe1, 0x09, 0x80} },
+{ 0x0300,	16,	{0xf7, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe3, 0xf9, 0x90, 0x7f, 0xc5, 0xe0, 0x75, 0x2c, 0x00, 0xf5} },
+{ 0x0310,	16,	{0x2d, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70, 0x34, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31} },
+{ 0x0320,	16,	{0x95, 0x2d, 0xe5, 0x30, 0x95, 0x2c, 0x50, 0x34, 0x74, 0xc0, 0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0330,	1,	{0x7e} },
+{ 0x0331,	16,	{0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x29, 0x25, 0x31, 0xf5, 0x82, 0xe5, 0x30, 0x35, 0x28, 0xf5, 0x83} },
+{ 0x0341,	16,	{0xef, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70, 0x02, 0x05, 0x30, 0x80, 0xd0, 0xaf, 0x29, 0xae, 0x28} },
+{ 0x0351,	16,	{0xad, 0x2d, 0x7a, 0x7e, 0x79, 0xc0, 0x7b, 0xc0, 0x12, 0x0c, 0x3f, 0xe5, 0x2d, 0x25, 0x29, 0xf5} },
+{ 0x0361,	16,	{0x29, 0xe5, 0x2c, 0x35, 0x28, 0xf5, 0x28, 0xc3, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0xe5, 0x2a} },
+{ 0x0371,	9,	{0x95, 0x2c, 0xf5, 0x2a, 0x02, 0x02, 0xd4, 0xc3, 0x22} },
+{ 0x037a,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x52, 0x14, 0x70, 0x03, 0x02, 0x04, 0xce, 0x24} },
+{ 0x038a,	16,	{0xfe, 0x70, 0x03, 0x02, 0x05, 0x42, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x4c, 0x14, 0x70, 0x03} },
+{ 0x039a,	16,	{0x02, 0x04, 0x46, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x40, 0x24} },
+{ 0x03aa,	16,	{0x05, 0x60, 0x03, 0x02, 0x05, 0x96, 0x12, 0x0e, 0x44, 0x40, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f} },
+{ 0x03ba,	16,	{0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02, 0x70, 0x69, 0x74, 0x11, 0x90} },
+{ 0x03ca,	16,	{0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x03da,	16,	{0xff, 0x12, 0x0b, 0x58, 0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02} },
+{ 0x03ea,	16,	{0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90} },
+{ 0x03fa,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x08} },
+{ 0x040a,	16,	{0xba, 0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f} },
+{ 0x041a,	16,	{0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x042a,	16,	{0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2} },
+{ 0x043a,	16,	{0x12, 0x0e, 0x1f, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x2d, 0x02, 0x05, 0xa2, 0x12, 0x0a, 0xf7, 0x02} },
+{ 0x044a,	16,	{0x05, 0xa2, 0x12, 0x0e, 0x11, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x46, 0x40, 0x03, 0x02, 0x05, 0xa2} },
+{ 0x045a,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
+{ 0x046a,	16,	{0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x02, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
+{ 0x047a,	16,	{0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0xe4, 0x90, 0x7f, 0x00} },
+{ 0x048a,	16,	{0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x049a,	16,	{0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x04aa,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
+{ 0x04ba,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x04ca,	16,	{0xf0, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x48, 0x40, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x04da,	16,	{0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0, 0xb4} },
+{ 0x04ea,	16,	{0x01, 0x05, 0xc2, 0x00, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05} },
+{ 0x04fa,	16,	{0xa2, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4} },
+{ 0x050a,	16,	{0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f} },
+{ 0x051a,	16,	{0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f} },
+{ 0x052a,	16,	{0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x69, 0x90} },
+{ 0x053a,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x60, 0x12, 0x0e, 0x4a, 0x50, 0x5b, 0x90, 0x7f, 0xe8} },
+{ 0x054a,	16,	{0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4f, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
+{ 0x055a,	16,	{0xd2, 0x00, 0x80, 0x44, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x3b, 0x90, 0x7f, 0xea} },
+{ 0x056a,	16,	{0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
+{ 0x057a,	16,	{0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
+{ 0x058a,	16,	{0xf0, 0x80, 0x15, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x0c, 0x12, 0x01, 0x00, 0x50} },
+{ 0x059a,	16,	{0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22} },
+{ 0x05aa,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x05ba,	16,	{0xd0, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x06, 0xc0, 0x07, 0x90, 0x7f, 0xa5} },
+{ 0x05ca,	16,	{0xe0, 0x30, 0xe2, 0x06, 0x75, 0x0d, 0x06, 0x02, 0x06, 0x76, 0x90, 0x7f, 0xa5, 0xe0, 0x20, 0xe1} },
+{ 0x05da,	16,	{0x0c, 0xe5, 0x0d, 0x64, 0x02, 0x60, 0x06, 0x75, 0x0d, 0x07, 0x02, 0x06, 0x76, 0xaf, 0x0d, 0xef} },
+{ 0x05ea,	16,	{0x24, 0xfe, 0x60, 0x48, 0x14, 0x60, 0x2c, 0x24, 0xfe, 0x60, 0x77, 0x24, 0x04, 0x60, 0x03, 0x02} },
+{ 0x05fa,	16,	{0x06, 0x76, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xaf, 0x0c, 0x05, 0x0c, 0x8f, 0x82, 0x75, 0x83} },
+{ 0x060a,	16,	{0x00, 0x12, 0x08, 0x22, 0x90, 0x7f, 0xa6, 0xf0, 0xe5, 0x0c, 0x65, 0x08, 0x70, 0x5e, 0x75, 0x0d} },
+{ 0x061a,	16,	{0x05, 0x80, 0x59, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e} },
+{ 0x062a,	16,	{0x82, 0x75, 0x83, 0x00, 0x12, 0x08, 0x4f, 0x75, 0x0d, 0x02, 0x80, 0x40, 0xe5, 0x08, 0x24, 0xfe} },
+{ 0x063a,	16,	{0xb5, 0x0c, 0x07, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0xe5, 0x08, 0x14, 0xb5, 0x0c, 0x0a} },
+{ 0x064a,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09} },
+{ 0x065a,	16,	{0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e, 0x82, 0x75, 0x83, 0x00, 0x12, 0x08, 0x4f, 0x05, 0x0c} },
+{ 0x066a,	16,	{0x80, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x53, 0x91, 0xdf, 0xd0} },
+{ 0x067a,	16,	{0x07, 0xd0, 0x06, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x86, 0xd0} },
+{ 0x068a,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0694,	16,	{0x8c, 0x33, 0x8d, 0x34, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0xe4, 0xf5, 0x35, 0xf5, 0x36} },
+{ 0x06a4,	16,	{0xc3, 0xe5, 0x36, 0x95, 0x34, 0xe5, 0x35, 0x95, 0x33, 0x50, 0x69, 0xef, 0x25, 0x36, 0xf5, 0x82} },
+{ 0x06b4,	16,	{0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0xff, 0xf0, 0xf4, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36} },
+{ 0x06c4,	16,	{0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36} },
+{ 0x06d4,	16,	{0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0xaa, 0xf0, 0x64, 0xaa, 0x60, 0x02, 0xc3, 0x22} },
+{ 0x06e4,	16,	{0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0x55, 0xf0, 0x64, 0x55, 0x60} },
+{ 0x06f4,	16,	{0x02, 0xc3, 0x22, 0xad, 0x36, 0xe5, 0x36, 0x2f, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xed} },
+{ 0x0704,	16,	{0xf0, 0xfc, 0xac, 0x05, 0xed, 0x6c, 0x60, 0x02, 0xc3, 0x22, 0x05, 0x36, 0xe5, 0x36, 0x70, 0x02} },
+{ 0x0714,	16,	{0x05, 0x35, 0x80, 0x8c, 0xe4, 0xf5, 0x35, 0xf5, 0x36, 0xc3, 0xe5, 0x36, 0x95, 0x34, 0xe5, 0x35} },
+{ 0x0724,	16,	{0x95, 0x33, 0x50, 0x27, 0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe0, 0x65} },
+{ 0x0734,	16,	{0x36, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe4} },
+{ 0x0744,	13,	{0xf0, 0x05, 0x36, 0xe5, 0x36, 0x70, 0x02, 0x05, 0x35, 0x80, 0xce, 0xd3, 0x22} },
+{ 0x0751,	16,	{0xc2, 0x04, 0xd2, 0x05, 0xc2, 0x03, 0xc2, 0x00, 0xc2, 0x02, 0xc2, 0x01, 0x12, 0x0e, 0x3d, 0xd2} },
+{ 0x0761,	16,	{0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f} },
+{ 0x0771,	16,	{0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x7f, 0x93, 0x74} },
+{ 0x0781,	16,	{0x30, 0xf0, 0x12, 0x0a, 0x19, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0} },
+{ 0x0791,	16,	{0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0x12, 0x0e, 0x35, 0x20, 0x01, 0x42, 0x75, 0x24, 0x00, 0x75, 0x23} },
+{ 0x07a1,	16,	{0x00, 0x75, 0x22, 0x00, 0x75, 0x21, 0x00, 0x7f, 0x48, 0x7e, 0x92, 0x7d, 0x00, 0x7c, 0x00, 0xab} },
+{ 0x07b1,	16,	{0x24, 0xaa, 0x23, 0xa9, 0x22, 0xa8, 0x21, 0xc3, 0x12, 0x08, 0xa9, 0x50, 0xdb, 0x20, 0x01, 0xd8} },
+{ 0x07c1,	16,	{0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xe5, 0x24, 0x24, 0x01, 0xf5, 0x24, 0xea, 0x35, 0x23, 0xf5} },
+{ 0x07d1,	16,	{0x23, 0xe9, 0x35, 0x22, 0xf5, 0x22, 0xe8, 0x35, 0x21, 0xf5, 0x21, 0x80, 0xca, 0x30, 0x01, 0x05} },
+{ 0x07e1,	16,	{0x12, 0x03, 0x7a, 0xc2, 0x01, 0x30, 0x04, 0x1a, 0x12, 0x0e, 0x40, 0x50, 0x13, 0x12, 0x09, 0x00} },
+{ 0x07f1,	16,	{0x30, 0x00, 0x07, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0xf3, 0x12, 0x0d, 0x4a, 0x12, 0x0e, 0x42} },
+{ 0x0801,	8,	{0xc2, 0x03, 0x12, 0x08, 0xff, 0x80, 0xd6, 0x22} },
+{ 0x0809,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x0819,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0822,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x0832,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x0842,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x084f,	16,	{0xf8, 0xbb, 0x01, 0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0} },
+{ 0x085f,	16,	{0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8} },
+{ 0x086f,	2,	{0xf2, 0x22} },
+{ 0x0871,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x0881,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x0891,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x08a1,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x08a9,	16,	{0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x08b9,	1,	{0x22} },
+{ 0x08ba,	2,	{0x8f, 0x28} },
+{ 0x08bc,	16,	{0xe4, 0xf5, 0x29, 0x75, 0x2a, 0xff, 0x75, 0x2b, 0x11, 0x75, 0x2c, 0x32, 0xab, 0x2a, 0xaa, 0x2b} },
+{ 0x08cc,	16,	{0xa9, 0x2c, 0x90, 0x00, 0x01, 0x12, 0x08, 0x22, 0xb4, 0x03, 0x1d, 0xaf, 0x29, 0x05, 0x29, 0xef} },
+{ 0x08dc,	16,	{0xb5, 0x28, 0x01, 0x22, 0x12, 0x08, 0x09, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x08ec,	14,	{0x2a, 0xff, 0xf5, 0x2b, 0x89, 0x2c, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x08fa,	1,	{0x22} },
+{ 0x08fb,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x08ff,	1,	{0x22} },
+{ 0x0900,	9,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x097d,	16,	{0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x098d,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x39, 0x02, 0x09, 0xd4} },
+{ 0x0999,	16,	{0x02, 0x07, 0x51, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x09a9,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x09b9,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x09c9,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0d, 0xec, 0xe4, 0x7e} },
+{ 0x09d9,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x09e9,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x09f9,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x0a09,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x0a19,	16,	{0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0a29,	16,	{0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0d, 0x94, 0x90, 0x7f} },
+{ 0x0a39,	16,	{0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a49,	16,	{0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02, 0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05} },
+{ 0x0a59,	16,	{0x7e, 0x00, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a69,	16,	{0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d} },
+{ 0x0a79,	16,	{0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x22} },
+{ 0x0a89,	16,	{0x75, 0x32, 0x01, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x01, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x0e} },
+{ 0x0a99,	16,	{0x7d, 0x00, 0x7c, 0x01, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12} },
+{ 0x0aa9,	16,	{0x0d, 0xd7, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x02, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x80, 0x7d} },
+{ 0x0ab9,	16,	{0x00, 0x7c, 0x80, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0d} },
+{ 0x0ac9,	16,	{0xd7, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x03, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x20, 0x7d, 0x40} },
+{ 0x0ad9,	16,	{0x7c, 0x5b, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0d, 0xd7} },
+{ 0x0ae9,	14,	{0xe5, 0x32, 0x60, 0x05, 0xe4, 0xff, 0x12, 0x0d, 0xd7, 0xe5, 0x32, 0x24, 0xff, 0x22} },
+{ 0x0af7,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x10, 0xd3, 0x22} },
+{ 0x0aff,	1,	{0x32} },
+{ 0x0b00,	16,	{0x02, 0x0d, 0x64, 0x00, 0x02, 0x0d, 0xab, 0x00, 0x02, 0x0d, 0x2f, 0x00, 0x02, 0x0d, 0x7c, 0x00} },
+{ 0x0b10,	16,	{0x02, 0x0d, 0xc1, 0x00, 0x02, 0x0a, 0xff, 0x00, 0x02, 0x0e, 0x4c, 0x00, 0x02, 0x0e, 0x4d, 0x00} },
+{ 0x0b20,	16,	{0x02, 0x0e, 0x4e, 0x00, 0x02, 0x0e, 0x4f, 0x00, 0x02, 0x0e, 0x50, 0x00, 0x02, 0x0e, 0x51, 0x00} },
+{ 0x0b30,	16,	{0x02, 0x0e, 0x52, 0x00, 0x02, 0x0e, 0x53, 0x00, 0x02, 0x0e, 0x54, 0x00, 0x02, 0x0e, 0x55, 0x00} },
+{ 0x0b40,	16,	{0x02, 0x0e, 0x56, 0x00, 0x02, 0x0e, 0x57, 0x00, 0x02, 0x0e, 0x58, 0x00, 0x02, 0x0e, 0x59, 0x00} },
+{ 0x0b50,	8,	{0x02, 0x0e, 0x5a, 0x00, 0x02, 0x0e, 0x5b, 0x00} },
+{ 0x0b58,	16,	{0xe4, 0xfe, 0x75, 0x2a, 0xff, 0x75, 0x2b, 0x11, 0x75, 0x2c, 0x12, 0xab, 0x2a, 0xaa, 0x2b, 0xa9} },
+{ 0x0b68,	16,	{0x2c, 0x90, 0x00, 0x01, 0x12, 0x08, 0x22, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x0b78,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x08, 0x71, 0x85, 0xf0, 0x28, 0xf5, 0x29, 0x62, 0x28} },
+{ 0x0b88,	16,	{0xe5, 0x28, 0x62, 0x29, 0xe5, 0x29, 0x62, 0x28, 0x29, 0xfd, 0xe5, 0x28, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x0b98,	14,	{0x2a, 0xff, 0xf5, 0x2b, 0x89, 0x2c, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0ba6,	1,	{0x22} },
+{ 0x0ba7,	16,	{0xab, 0x07, 0xaa, 0x06, 0xac, 0x05, 0xe4, 0xfd, 0xe5, 0x11, 0x60, 0x11, 0xea, 0xff, 0xae, 0x05} },
+{ 0x0bb7,	16,	{0x0d, 0xee, 0x24, 0x10, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xeb, 0xae, 0x05} },
+{ 0x0bc7,	16,	{0x0d, 0x74, 0x10, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xeb, 0xf0, 0xaf, 0x05, 0x0d} },
+{ 0x0bd7,	16,	{0x74, 0x10, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xec, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f} },
+{ 0x0be7,	13,	{0x7b, 0x10, 0x12, 0x0d, 0x10, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x22} },
+{ 0x0bf4,	16,	{0x8e, 0x32, 0x8f, 0x33, 0x8d, 0x34, 0x8a, 0x35, 0x8b, 0x36, 0xe4, 0xfd, 0xf5, 0x37, 0xe5, 0x11} },
+{ 0x0c04,	16,	{0x60, 0x12, 0xe5, 0x32, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24, 0x13, 0xf5, 0x82, 0xe4, 0x34, 0x0f} },
+{ 0x0c14,	16,	{0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x33, 0xae, 0x05, 0x0d, 0x74, 0x13, 0x2e, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0c24,	16,	{0x0f, 0xf5, 0x83, 0xe5, 0x33, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f, 0x7b, 0x13, 0x12, 0x0d, 0x10, 0xaf} },
+{ 0x0c34,	11,	{0x0f, 0xad, 0x34, 0xab, 0x36, 0xaa, 0x35, 0x12, 0x0c, 0xf1, 0x22} },
+{ 0x0c3f,	16,	{0x8e, 0x32, 0x8f, 0x33, 0x8d, 0x34, 0x8a, 0x35, 0x8b, 0x36, 0xe4, 0xf5, 0x37, 0xe5, 0x37, 0xc3} },
+{ 0x0c4f,	16,	{0x95, 0x34, 0x50, 0x20, 0x05, 0x33, 0xe5, 0x33, 0xae, 0x32, 0x70, 0x02, 0x05, 0x32, 0x14, 0xff} },
+{ 0x0c5f,	16,	{0xe5, 0x36, 0x25, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x35, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x0b, 0xa7} },
+{ 0x0c6f,	5,	{0x05, 0x37, 0x80, 0xd9, 0x22} },
+{ 0x0c74,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x25, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0c84,	16,	{0x44, 0x01, 0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a} },
+{ 0x0c94,	13,	{0x0a, 0x89, 0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x03, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0ca1,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0cb1,	16,	{0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a, 0x0a, 0x89} },
+{ 0x0cc1,	11,	{0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x01, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0ccc,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x06, 0x04, 0xe0, 0x44} },
+{ 0x0cdc,	16,	{0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x0cec,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x0cf1,	16,	{0x12, 0x0c, 0x74, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d01,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d10,	16,	{0x12, 0x0c, 0xa1, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d20,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d2f,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0d3f,	11,	{0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d4a,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x12, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x14, 0x7e, 0x00, 0x12} },
+{ 0x0d5a,	10,	{0x0d, 0x94, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
+{ 0x0d64,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0d74,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d7c,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x03, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x0d8c,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d94,	16,	{0x8e, 0x38, 0x8f, 0x39, 0xe5, 0x39, 0x15, 0x39, 0xae, 0x38, 0x70, 0x02, 0x15, 0x38, 0x4e, 0x60} },
+{ 0x0da4,	7,	{0x05, 0x12, 0x0e, 0x00, 0x80, 0xee, 0x22} },
+{ 0x0dab,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0} },
+{ 0x0dbb,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dc1,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0dd1,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dd7,	16,	{0xae, 0x07, 0x7f, 0x21, 0x7d, 0x01, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xab, 0x82} },
+{ 0x0de7,	5,	{0xfa, 0x12, 0x0d, 0x10, 0x22} },
+{ 0x0dec,	16,	{0x50, 0x0f, 0x00, 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, 0x88, 0x83, 0xc6} },
+{ 0x0dfc,	3,	{0xa1, 0x86, 0x8e} },
+{ 0x0dff,	1,	{0x00} },
+{ 0x0e00,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x0e10,	1,	{0x22} },
+{ 0x0e11,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x10, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x0e1f,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x0e, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x0e2d,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0e, 0xd3, 0x22} },
+{ 0x0e35,	8,	{0xe4, 0xf5, 0x0d, 0xd2, 0xe9, 0xd2, 0xaf, 0x22} },
+{ 0x0e3d,	3,	{0xd2, 0x00, 0x22} },
+{ 0x0e40,	2,	{0xd3, 0x22} },
+{ 0x0e42,	2,	{0xd3, 0x22} },
+{ 0x0e44,	2,	{0xd3, 0x22} },
+{ 0x0e46,	2,	{0xd3, 0x22} },
+{ 0x0e48,	2,	{0xd3, 0x22} },
+{ 0x0e4a,	2,	{0xd3, 0x22} },
+{ 0x0e4c,	1,	{0x32} },
+{ 0x0e4d,	1,	{0x32} },
+{ 0x0e4e,	1,	{0x32} },
+{ 0x0e4f,	1,	{0x32} },
+{ 0x0e50,	1,	{0x32} },
+{ 0x0e51,	1,	{0x32} },
+{ 0x0e52,	1,	{0x32} },
+{ 0x0e53,	1,	{0x32} },
+{ 0x0e54,	1,	{0x32} },
+{ 0x0e55,	1,	{0x32} },
+{ 0x0e56,	1,	{0x32} },
+{ 0x0e57,	1,	{0x32} },
+{ 0x0e58,	1,	{0x32} },
+{ 0x0e59,	1,	{0x32} },
+{ 0x0e5a,	1,	{0x32} },
+{ 0x0e5b,	1,	{0x32} },
+{ 0x1100,	16,	{0x12, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x47, 0x05, 0x10, 0x27, 0x01, 0x00, 0x01, 0x02} },
+{ 0x1110,	16,	{0x00, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x03, 0xa0, 0x00, 0x09, 0x04, 0x00, 0x00, 0x02} },
+{ 0x1120,	16,	{0xff, 0x00, 0x00, 0x04, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1130,	16,	{0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x26, 0x03, 0x41, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x68, 0x00} },
+{ 0x1140,	16,	{0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x43, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x73, 0x00} },
+{ 0x1150,	16,	{0x2c, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x28, 0x03, 0x46, 0x00} },
+{ 0x1160,	16,	{0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00} },
+{ 0x1170,	16,	{0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00} },
+{ 0x1180,	16,	{0x6b, 0x00, 0x73, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
+{ 0x1190,	16,	{0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
+{ 0x11a0,	16,	{0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
+{ 0x11b0,	16,	{0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
+{ 0x11c0,	16,	{0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
+{ 0x11d0,	2,	{0x00, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.99-pre3/linux/drivers/usb/uhci.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/uhci.c	Tue Apr 11 09:57:43 2000
@@ -56,11 +56,11 @@
 
 static LIST_HEAD(uhci_list);
 
-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 uhci_get_current_frame_number(struct usb_device *dev);
-static int uhci_unlink_generic(urb_t *urb);
-static int uhci_unlink_urb(urb_t *urb);
+static int uhci_unlink_generic(struct urb *urb);
+static int uhci_unlink_urb(struct urb *urb);
 
 #define min(a,b) (((a)<(b))?(a):(b))
 
@@ -77,9 +77,8 @@
 
 static int uhci_free_dev(struct usb_device *dev)
 {
-	urb_t *u;
 	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-	struct list_head *tmp, *next, *head = &uhci->urb_list;
+	struct list_head *tmp, *head = &uhci->urb_list;
 	unsigned long flags;
 
 	/* Walk through the entire URB list and forcefully remove any */
@@ -87,14 +86,12 @@
 	nested_lock(&uhci->urblist_lock, flags);
 	tmp = head->next;
 	while (tmp != head) {
-		u = list_entry(tmp, urb_t, urb_list);
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
 
-		next = tmp->next;
+		tmp = tmp->next;
 
 		if (u->dev == dev)
 			uhci_unlink_urb(u);
-
-		tmp = next;
 	}
 	nested_unlock(&uhci->urblist_lock, flags);
 
@@ -115,13 +112,31 @@
 	unsigned long flags;
 
 	nested_lock(&uhci->urblist_lock, flags);
-	if (urb->urb_list.next != &urb->urb_list) {
+	if (!list_empty(&urb->urb_list)) {
 		list_del(&urb->urb_list);
 		INIT_LIST_HEAD(&urb->urb_list);
 	}
 	nested_unlock(&uhci->urblist_lock, flags);
 }
 
+void uhci_set_next_interrupt(struct uhci *uhci)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	uhci->skel_term_td.status |= TD_CTRL_IOC;
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+void uhci_clear_next_interrupt(struct uhci *uhci)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	uhci->skel_term_td.status &= ~TD_CTRL_IOC;
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
 static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
 {
 	struct uhci_td *td;
@@ -135,8 +150,8 @@
 
 	td->frameptr = NULL;
 	td->nexttd = td->prevtd = NULL;
-	td->list.next = td->list.prev = NULL;
 	td->dev = dev;
+	INIT_LIST_HEAD(&td->list);
 
 	usb_inc_dev_use(dev);
 
@@ -235,23 +250,32 @@
  */
 static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
 {
+	struct list_head *tmp, *head;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct uhci_td *td, *prevtd;
 
 	if (!urbp)
 		return;
 
-	td = urbp->list.begin;
-	if (!td)
+	head = &urbp->list;
+	tmp = head->next;
+	if (head == tmp)
 		return;
 
+	td = list_entry(tmp, struct uhci_td, list);
+
 	/* Add the first TD to the QH element pointer */
 	qh->element = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
 
 	prevtd = td;
 
 	/* Then link the rest of the TD's */
-	for (td = td->list.next; td; td = td->list.next) {
+	tmp = tmp->next;
+	while (tmp != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
 		prevtd->link = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
 
 		prevtd = td;
@@ -260,9 +284,45 @@
 	prevtd->link = UHCI_PTR_TERM;
 }
 
+/* This function will append one URB's QH to another URB's QH. This is for */
+/*  USB_QUEUE_BULK support */
+static void uhci_append_urb_qh(struct uhci *uhci, struct urb *eurb, struct urb *urb)
+{
+	struct urb *nurb;
+	struct urb_priv *eurbp, *urbp, *nurbp;
+	struct list_head *tmp;
+	struct uhci_td *td, *ntd;
+	unsigned long flags;
+
+	eurbp = eurb->hcpriv;
+	urbp = urb->hcpriv;
+
+	spin_lock_irqsave(&eurb->lock, flags);
+
+	/* Grab the last URB in the queue */
+	tmp = eurbp->urb_queue_list.prev;
+
+	/* Add this one to the end */
+	list_add_tail(&urbp->urb_queue_list, &eurbp->urb_queue_list);
+
+	spin_unlock_irqrestore(&eurb->lock, flags);
+
+	nurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+	nurb = nurbp->urb;
+
+	tmp = nurbp->list.prev;
+	td = list_entry(tmp, struct uhci_td, list);
+
+	tmp = urbp->list.next;
+	ntd = list_entry(tmp, struct uhci_td, list);
+
+	/* No breadth since this will only be called for bulk transfers */
+	td->link = virt_to_bus(ntd);
+}
+
 static void uhci_free_td(struct uhci_td *td)
 {
-	if (td->list.next || td->list.prev)
+	if (!list_empty(&td->list))
 		dbg("td is still in URB list!");
 
 	kmem_cache_free(uhci_td_cachep, td);
@@ -322,6 +382,10 @@
 static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
 {
 	unsigned long flags;
+	int delayed;
+
+	/* If the QH isn't queued, then we don't need to delay unlink it */
+	delayed = (qh->prevqh || qh->nextqh);
 
 	spin_lock_irqsave(&uhci->framelist_lock, flags);
 	if (qh->prevqh) {
@@ -333,9 +397,20 @@
 	qh->prevqh = qh->nextqh = NULL;
 	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 
-	spin_lock_irqsave(&uhci->qh_remove_lock, flags);
-	list_add(&qh->remove_list, &uhci->qh_remove_list);
-	spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
+	if (delayed) {
+		spin_lock_irqsave(&uhci->qh_remove_lock, flags);
+
+		/* Check to see if the remove list is empty */
+		/* Set the IOC bit to force an interrupt so we can remove the QH */
+		if (list_empty(&uhci->qh_remove_list))
+			uhci_set_next_interrupt(uhci);
+
+		/* Add it */
+		list_add(&qh->remove_list, &uhci->qh_remove_list);
+
+		spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
+	} else
+		uhci_free_qh(qh);
 }
 
 struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
@@ -348,91 +423,86 @@
 
 	memset((void *)urbp, 0, sizeof(*urbp));
 
-	urbp->list.begin = urbp->list.end = NULL;
+	urbp->inserttime = jiffies;
+	urbp->urb = urb;
+	
+	INIT_LIST_HEAD(&urbp->list);
+	INIT_LIST_HEAD(&urbp->urb_queue_list);
 
 	urb->hcpriv = urbp;
 
-	urbp->inserttime = jiffies;
-
 	usb_inc_dev_use(urb->dev);
 
 	return urbp;
 }
 
-static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td)
+static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
 {
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
 	td->urb = urb;
 
-	if (!urbp->list.begin)
-		urbp->list.begin = td;
-
-	if (urbp->list.end) {
-		urbp->list.end->list.next = td;
-		td->list.prev = urbp->list.end;
-	}
-	urbp->list.end = td;
+	list_add_tail(&td->list, &urbp->list);
 }
 
-static void uhci_remove_td_from_urb(urb_t *urb, struct uhci_td *td)
+static void uhci_remove_td_from_urb(struct urb *urb, struct uhci_td *td)
 {
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	urb = NULL;	/* No warnings */
 
-	if (!urbp->list.begin && !urbp->list.end)
+	if (list_empty(&td->list))
 		return;
 
-	if (td->list.prev)
-		td->list.prev->list.next = td->list.next;
-	else
-		urbp->list.begin = td->list.next;
-
-	if (td->list.next)
-		td->list.next->list.prev = td->list.prev;
-	else
-		urbp->list.end = td->list.prev;
+	list_del(&td->list);
+	INIT_LIST_HEAD(&td->list);
 
-	td->list.next = td->list.prev = NULL;
 	td->urb = NULL;
 }
 
-static void uhci_destroy_urb_priv(urb_t *urb)
+static void uhci_destroy_urb_priv(struct urb *urb)
 {
+	struct list_head *tmp, *head;
 	struct urb_priv *urbp;
 	struct uhci *uhci;
-	struct uhci_td *td, *nexttd;
+	struct uhci_td *td;
 	unsigned long flags;
 
 	spin_lock_irqsave(&urb->lock, flags);
 
 	urbp = (struct urb_priv *)urb->hcpriv;
 	if (!urbp)
-		return;
+		goto unlock;
 
 	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
-		return;
+		goto unlock;
 
 	uhci = urb->dev->bus->hcpriv;
 
-	td = urbp->list.begin;
-	while (td) {
-		nexttd = td->list.next;
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
 
 		uhci_remove_td_from_urb(urb, td);
 
 		uhci_remove_td(uhci, td);
 
 		uhci_free_td(td);
-		
-		td = nexttd;
+	}
+
+	if (!list_empty(&urbp->urb_queue_list)) {
+		list_del(&urbp->urb_queue_list);
+		INIT_LIST_HEAD(&urbp->urb_queue_list);
 	}
 
 	urb->hcpriv = NULL;
 	kmem_cache_free(uhci_up_cachep, urbp);
 
-	spin_unlock_irqrestore(&urb->lock, flags);
-
 	usb_dec_dev_use(urb->dev);
+
+unlock:
+	spin_unlock_irqrestore(&urb->lock, flags);
 }
 
 static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
@@ -448,7 +518,7 @@
 	if (!urbp->fsbr) {
 		urbp->fsbr = 1;
 		if (!uhci->fsbr++)
-			uhci->skel_term_td.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
+			uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
 	}
 
 	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
@@ -467,7 +537,7 @@
 	if (urbp->fsbr) {
 		urbp->fsbr = 0;
 		if (!--uhci->fsbr)
-			uhci->skel_term_td.link = UHCI_PTR_TERM;
+			uhci->skel_term_qh.link = UHCI_PTR_TERM;
 	}
 
 	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
@@ -508,7 +578,7 @@
 /*
  * Control transfers
  */
-static int uhci_submit_control(urb_t *urb)
+static int uhci_submit_control(struct urb *urb)
 {
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -602,10 +672,12 @@
 	if (urb->pipe & TD_CTRL_LS) {
 		uhci_insert_tds_in_qh(qh, urb, 0);
 		uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh);
+		urbp->queued = 0;
 	} else {
 		uhci_insert_tds_in_qh(qh, urb, 1);
 		uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
 		uhci_inc_fsbr(uhci, urb);
+		urbp->queued = 0;
 	}
 
 	urbp->qh = qh;
@@ -617,10 +689,11 @@
 	return -EINPROGRESS;
 }
 
-static int usb_control_retrigger_status(urb_t *urb);
+static int usb_control_retrigger_status(struct urb *urb);
 
-static int uhci_result_control(urb_t *urb)
+static int uhci_result_control(struct urb *urb)
 {
+	struct list_head *tmp, *head;
 	struct urb_priv *urbp = urb->hcpriv;
 	struct uhci_td *td;
 	unsigned int status;
@@ -628,13 +701,16 @@
 	if (!urbp)
 		return -EINVAL;
 
-	td = urbp->list.begin;
-	if (!td)
+	head = &urbp->list;
+	tmp = head->next;
+	if (head == tmp)
 		return -EINVAL;
 
 	if (urbp->short_control_packet)
 		goto status_phase;
 
+	td = list_entry(tmp, struct uhci_td, list);
+
 	/* The first TD is the SETUP phase, check the status, but skip */
 	/*  the count */
 	status = uhci_status_bits(td->status);
@@ -646,10 +722,13 @@
 
 	urb->actual_length = 0;
 
-	td = td->list.next;
-
 	/* The rest of the TD's (but the last) are data */
-	while (td && td->list.next) {
+	tmp = tmp->next;
+	while (tmp != head && tmp->next != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
 		status = uhci_status_bits(td->status);
 		if (status & TD_CTRL_ACTIVE)
 			return -EINPROGRESS;
@@ -664,18 +743,18 @@
 
 		if (status)
 			goto td_error;
-
-		td = td->list.next;
 	}
 
 status_phase:
+	td = list_entry(tmp, struct uhci_td, list);
+
 	/* Control status phase */
 	status = uhci_status_bits(td->status);
 
 	/* APC BackUPS Pro kludge */
 	/* It tries to send all of the descriptor instead of the amount */
 	/*  we requested */
-	if (td->status & TD_CTRL_IOC &&
+	if (td->status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */
 	    status & TD_CTRL_ACTIVE &&
 	    status & TD_CTRL_NAK)
 		return 0;
@@ -704,34 +783,37 @@
 	return uhci_map_status(status, uhci_packetout(td->info));
 }
 
-static int usb_control_retrigger_status(urb_t *urb)
+static int usb_control_retrigger_status(struct urb *urb)
 {
+	struct list_head *tmp, *head;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct uhci *uhci = urb->dev->bus->hcpriv;
-	struct uhci_td *td, *nexttd;
 
 	urbp->short_control_packet = 1;
 
+	/* Create a new QH to avoid pointer overwriting problems */
+	uhci_remove_qh(uhci, urbp->qh);
+
 	/* Delete all of the TD's except for the status TD at the end */
-	td = urbp->list.begin;
-	while (td && td->list.next) {
-		nexttd = td->list.next;
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head && tmp->next != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
 
 		uhci_remove_td_from_urb(urb, td);
 
 		uhci_remove_td(uhci, td);
 
 		uhci_free_td(td);
-		
-		td = nexttd;
 	}
 
-	/* Create a new QH to avoid pointer overwriting problems */
-	uhci_remove_qh(uhci, urbp->qh);
-
 	urbp->qh = uhci_alloc_qh(urb->dev);
-	if (!urbp->qh)
+	if (!urbp->qh) {
+		err("unable to allocate new QH for control retrigger");
 		return -ENOMEM;
+	}
 
 	/* One TD, who cares about Breadth first? */
 	uhci_insert_tds_in_qh(urbp->qh, urb, 0);
@@ -741,6 +823,7 @@
 		uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, urbp->qh);
 	else
 		uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, urbp->qh);
+	urbp->queued = 0;
 
 	return -EINPROGRESS;
 }
@@ -748,7 +831,7 @@
 /*
  * Interrupt transfers
  */
-static int uhci_submit_interrupt(urb_t *urb)
+static int uhci_submit_interrupt(struct urb *urb)
 {
 	struct uhci_td *td;
 	unsigned long destination, status;
@@ -782,18 +865,25 @@
 	return -EINPROGRESS;
 }
 
-static int uhci_result_interrupt(urb_t *urb)
+static int uhci_result_interrupt(struct urb *urb)
 {
+	struct list_head *tmp, *head;
 	struct urb_priv *urbp = urb->hcpriv;
-	struct uhci_td *td;
 	unsigned int status;
+	struct uhci_td *td;
 
 	if (!urbp)
 		return -EINVAL;
 
 	urb->actual_length = 0;
 
-	for (td = urbp->list.begin; td; td = td->list.next) {
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
 		status = uhci_status_bits(td->status);
 		if (status & TD_CTRL_ACTIVE)
 			return -EINPROGRESS;
@@ -836,15 +926,17 @@
 	return uhci_map_status(status, uhci_packetout(td->info));
 }
 
-static void uhci_reset_interrupt(urb_t *urb)
+static void uhci_reset_interrupt(struct urb *urb)
 {
+	struct list_head *tmp;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct uhci_td *td;
 
 	if (!urbp)
 		return;
 
-	td = urbp->list.begin;
+	tmp = urbp->list.next;
+	td = list_entry(tmp, struct uhci_td, list);
 	if (!td)
 		return;
 
@@ -859,7 +951,7 @@
 /*
  * Bulk transfers
  */
-static int uhci_submit_bulk(urb_t *urb)
+static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
 {
 	struct uhci_td *td;
 	struct uhci_qh *qh;
@@ -881,14 +973,14 @@
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
 
 	/* 3 errors */
-	status = TD_CTRL_ACTIVE | (3 << 27);
+	status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
 	if (!(urb->transfer_flags & USB_DISABLE_SPD))
 		status |= TD_CTRL_SPD;
 
 	/*
 	 * Build the DATA TD's
 	 */
-	while (len > 0) {
+	do {	/* Allow zero length packets */
 		int pktsze = len;
 
 		if (pktsze > maxsze)
@@ -912,16 +1004,24 @@
 
 		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
 			usb_pipeout(urb->pipe));
-	}
+	} while (len > 0);
 
 	qh = uhci_alloc_qh(urb->dev);
 	if (!qh)
 		return -ENOMEM;
 
+	urbp->qh = qh;
+
+	/* Always assume depth first */
 	uhci_insert_tds_in_qh(qh, urb, 1);
 
-	uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
-	urbp->qh = qh;
+	if (urb->transfer_flags & USB_QUEUE_BULK && eurb) {
+		uhci_append_urb_qh(uhci, eurb, urb);
+		urbp->queued = 1;
+	} else {
+		uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
+		urbp->queued = 0;
+	}
 
 	uhci_add_urb_list(uhci, urb);
 
@@ -936,9 +1036,9 @@
 /*
  * Isochronous transfers
  */
-static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int *end)
+static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigned int *end)
 {
-	urb_t *u, *last_urb = NULL;
+	struct urb *last_urb = NULL;
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 	struct list_head *tmp, *head = &uhci->urb_list;
 	int ret = 0;
@@ -947,7 +1047,7 @@
 	nested_lock(&uhci->urblist_lock, flags);
 	tmp = head->next;
 	while (tmp != head) {
-		u = list_entry(tmp, urb_t, urb_list);
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
 
 		/* look for pending URB's with identical pipe handle */
 		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
@@ -970,7 +1070,7 @@
 	return ret;
 }
 
-static int isochronous_find_start(urb_t *urb)
+static int isochronous_find_start(struct urb *urb)
 {
 	int limits;
 	unsigned int start = 0, end = 0;
@@ -996,7 +1096,7 @@
 	return 0;
 }
 
-static int uhci_submit_isochronous(urb_t *urb)
+static int uhci_submit_isochronous(struct urb *urb)
 {
 	struct uhci_td *td;
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1034,10 +1134,10 @@
 	return -EINPROGRESS;
 }
 
-static int uhci_result_isochronous(urb_t *urb)
+static int uhci_result_isochronous(struct urb *urb)
 {
+	struct list_head *tmp, *head;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td;
 	int status;
 	int i, ret = 0;
 
@@ -1046,9 +1146,15 @@
 
 	urb->actual_length = 0;
 
-	for (i = 0, td = urbp->list.begin; td; i++, td = td->list.next) {
+	i = 0;
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
 		int actlength;
 
+		tmp = tmp->next;
+
 		if (td->status & TD_CTRL_ACTIVE)
 			return -EINPROGRESS;
 
@@ -1062,16 +1168,47 @@
 			urb->error_count++;
 			ret = status;
 		}
+
+		i++;
 	}
 
 	return ret;
 }
 
-static int uhci_submit_urb(urb_t *urb)
+static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb)
+{
+	struct list_head *tmp, *head = &uhci->urb_list;
+	unsigned long flags;
+	struct urb *u = NULL;
+
+	if (usb_pipeisoc(urb->pipe))
+		return NULL;
+
+	nested_lock(&uhci->urblist_lock, flags);
+	tmp = head->next;
+	while (tmp != head) {
+		u = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		if (u->dev == urb->dev &&
+		    u->pipe == urb->pipe)
+			goto found;
+	}
+	u = NULL;
+
+found:
+	nested_unlock(&uhci->urblist_lock, flags);
+
+	return u;
+}
+
+static int uhci_submit_urb(struct urb *urb)
 {
 	int ret = -EINVAL;
 	struct uhci *uhci;
 	unsigned long flags;
+	struct urb *u;
 
 	if (!urb)
 		return -EINVAL;
@@ -1085,6 +1222,10 @@
 	if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
 		return rh_submit_urb(urb);
 
+	u = uhci_find_urb_ep(uhci, urb);
+	if (u && !(urb->transfer_flags & USB_QUEUE_BULK))
+		return -ENXIO;
+
 	spin_lock_irqsave(&urb->lock, flags);
 
 	if (!uhci_alloc_urb_priv(urb)) {
@@ -1100,7 +1241,7 @@
 		ret = uhci_submit_interrupt(urb);
 		break;
 	case PIPE_BULK:
-		ret = uhci_submit_bulk(urb);
+		ret = uhci_submit_bulk(urb, u);
 		break;
 	case PIPE_ISOCHRONOUS:
 		ret = uhci_submit_isochronous(urb);
@@ -1124,9 +1265,9 @@
  *
  * Must be called with urblist_lock acquired
  */
-static void uhci_transfer_result(urb_t *urb)
+static void uhci_transfer_result(struct urb *urb)
 {
-	urb_t *turb;
+	struct urb *turb;
 	int proceed = 0, is_ring = 0;
 	int ret = -EINVAL;
 	unsigned long flags;
@@ -1206,7 +1347,7 @@
 	}
 }
 
-static int uhci_unlink_generic(urb_t *urb)
+static int uhci_unlink_generic(struct urb *urb)
 {
 	struct urb_priv *urbp = urb->hcpriv;
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1222,12 +1363,21 @@
 		/* The interrupt loop will reclaim the QH's */
 		uhci_remove_qh(uhci, urbp->qh);
 
+	if (!list_empty(&urbp->urb_queue_list)) {
+		struct list_head *tmp = urbp->urb_queue_list.next;
+		struct urb_priv *nurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+		if (nurbp->queued) {
+			uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh);
+			nurbp->queued = 0;
+		}
+	}
+
 	uhci_destroy_urb_priv(urb);
 
 	return 0;
 }
 
-static int uhci_unlink_urb(urb_t *urb)
+static int uhci_unlink_urb(struct urb *urb)
 {
 	struct uhci *uhci;
 	int ret = 0;
@@ -1252,7 +1402,13 @@
 			urb->status = -ECONNABORTED;
 
 			spin_lock_irqsave(&uhci->urb_remove_lock, flags);
+
+			/* Check to see if the remove list is empty */
+			if (list_empty(&uhci->urb_remove_list))
+				uhci_set_next_interrupt(uhci);
+			
 			list_add(&urb->urb_list, &uhci->urb_remove_list);
+
 			spin_unlock_irqrestore(&uhci->urb_remove_lock, flags);
 		} else {
 			urb->status = -ENOENT;
@@ -1372,7 +1528,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 i, len = 1;
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1399,11 +1555,11 @@
 
 /*-------------------------------------------------------------------------*/
 /* Virtual Root Hub INTs are polled by this timer every "interval" 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)
 {
-	urb_t *urb = (urb_t *)ptr, *u;
+	struct urb *urb = (struct urb *)ptr;
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 	struct list_head *tmp, *head = &uhci->urb_list;
 	struct urb_priv *urbp;
@@ -1422,15 +1578,22 @@
 	nested_lock(&uhci->urblist_lock, flags);
 	tmp = head->next;
 	while (tmp != head) {
-		u = list_entry(tmp, urb_t, urb_list);
+		struct urb *u = list_entry(tmp, urb_t, urb_list);
+
+		tmp = tmp->next;
 
 		urbp = (struct urb_priv *)u->hcpriv;
 		if (urbp) {
-			if (urbp->fsbr && time_after(jiffies, urbp->inserttime + IDLE_TIMEOUT))
+			/* Check if the FSBR timed out */
+			if (urbp->fsbr && time_after(urbp->inserttime + IDLE_TIMEOUT, jiffies))
 				uhci_dec_fsbr(uhci, u);
-		}
 
-		tmp = tmp->next;
+			/* Check if the URB timed out */
+			if (u->timeout && time_after(u->timeout, jiffies)) {
+				u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+				uhci_unlink_urb(u);
+			}
+		}
 	}
 	nested_unlock(&uhci->urblist_lock, flags);
 
@@ -1439,7 +1602,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)
 {
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
@@ -1472,7 +1635,7 @@
  ** Root Hub Control Pipe
  *************************/
 
-static int rh_submit_urb(urb_t *urb)
+static int rh_submit_urb(struct urb *urb)
 {
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 	unsigned int pipe = urb->pipe;
@@ -1588,7 +1751,7 @@
 			OK(0);
 		case RH_PORT_RESET:
 			SET_RH_PORTSTAT(USBPORTSC_PR);
-			wait_ms(10);
+			wait_ms(50);	/* USB v1.1 7.1.7.3 */
 			uhci->rh.c_p_r[wIndex - 1] = 1;
 			CLR_RH_PORTSTAT(USBPORTSC_PR);
 			udelay(10);
@@ -1636,6 +1799,11 @@
 		OK(1);
 	case RH_SET_CONFIGURATION:
 		OK(0);
+	case RH_GET_INTERFACE | RH_INTERFACE:
+		*(__u8 *)data = 0x00;
+		OK(1);
+	case RH_SET_INTERFACE | RH_INTERFACE:
+		OK(0);
 	default:
 		stat = -EPIPE;
 	}
@@ -1649,7 +1817,7 @@
 }
 /*-------------------------------------------------------------------------*/
 
-static int rh_unlink_urb(urb_t *urb)
+static int rh_unlink_urb(struct urb *urb)
 {
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
@@ -1728,6 +1896,8 @@
 	}
 	spin_unlock(&uhci->urb_remove_lock);
 
+	uhci_clear_next_interrupt(uhci);
+
 	/* Walk the list of pending TD's to see which ones completed */
 	nested_lock(&uhci->urblist_lock, flags);
 	head = &uhci->urb_list;
@@ -2137,7 +2307,7 @@
 
 	/* We only want to return an error code if ther was an error */
 	/*  and we didn't find a UHCI controller */
-	if (retval && uhci_list.next == &uhci_list)
+	if (retval && list_empty(&uhci_list))
 		goto init_failed;
 
 	return 0;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.3.99-pre3/linux/drivers/usb/uhci.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/usb/uhci.h	Mon Apr 10 22:57:06 2000
@@ -97,6 +97,10 @@
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
 #define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
 
+struct uhci_framelist {
+	__u32 frame[UHCI_NUMFRAMES];
+} __attribute__((aligned(4096)));
+
 struct uhci_td;
 
 struct uhci_qh {
@@ -106,22 +110,19 @@
 
 	/* Software fields */
 	/* Can't use list_head since we want a specific order */
-	struct uhci_qh *prevqh, *nextqh;
-
 	struct usb_device *dev;			/* The owning device */
 
+	struct uhci_qh *prevqh, *nextqh;
+
 	struct list_head remove_list;
 } __attribute__((aligned(16)));
 
-struct uhci_framelist {
-	__u32 frame[UHCI_NUMFRAMES];
-} __attribute__((aligned(4096)));
-
 /*
  * for TD <status>:
  */
 #define TD_CTRL_SPD		(1 << 29)	/* Short Packet Detect */
 #define TD_CTRL_C_ERR_MASK	(3 << 27)	/* Error Counter bits */
+#define TD_CTRL_C_ERR_SHIFT	27
 #define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
 #define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
 #define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
@@ -184,10 +185,8 @@
 
 	struct usb_device *dev;
 	struct urb *urb;		/* URB this TD belongs to */
-	/* We can't use list_head since we need a specific order */
-	struct ut_list {
-		struct uhci_td *prev, *next;
-	} list;
+
+	struct list_head list;
 } __attribute__((aligned(16)));
 
 /*
@@ -336,9 +335,12 @@
 };
 
 struct urb_priv {
+	struct urb *urb;
+
 	struct uhci_qh *qh;		/* QH for this URB */
 
-	int fsbr;			/* Did this URB turn on FSBR? */
+	int fsbr : 1;			/* Did this URB turn on FSBR? */
+	int queued : 1;			/* 0 if QH was linked in */
 
 	char short_control_packet;	/* If we get a short packet during */
 					/*  a control transfer, retrigger */
@@ -346,15 +348,16 @@
 
 	unsigned long inserttime;	/* In jiffies */
 
-	struct up_list {
-		struct uhci_td *begin, *end;
-	} list;
+	struct list_head list;
+
+	struct list_head urb_queue_list;	/* URB's linked together */
 };
 
 /* -------------------------------------------------------------------------
    Virtual Root HUB
    ------------------------------------------------------------------------- */
 /* destination of request */
+#define RH_DEVICE		0x00
 #define RH_INTERFACE		0x01
 #define RH_ENDPOINT		0x02
 #define RH_OTHER		0x03
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c
--- v2.3.99-pre3/linux/drivers/usb/usb-core.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/usb/usb-core.c	Sun Apr  2 15:20:16 2000
@@ -29,10 +29,10 @@
  */
 
 int usb_audio_init(void);
-int usb_cpia_init(void);
 int usb_ibmcam_init(void);
 int dabusb_init(void);
 int plusb_init(void);
+int dsbr100_init(void);
 
 /*
  * HCI drivers
@@ -70,9 +70,6 @@
 #ifndef CONFIG_USB_MODULE
 #ifdef CONFIG_USB_AUDIO
 	usb_audio_init();
-#endif
-#ifdef CONFIG_USB_CPIA
-	usb_cpia_init();
 #endif
 #ifdef CONFIG_USB_IBMCAM
 	usb_ibmcam_init();
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usb-debug.c linux/drivers/usb/usb-debug.c
--- v2.3.99-pre3/linux/drivers/usb/usb-debug.c	Fri Mar 10 16:40:45 2000
+++ linux/drivers/usb/usb-debug.c	Thu Mar 30 18:00:01 2000
@@ -4,11 +4,16 @@
  * I just want these out of the way where they aren't in your
  * face, but so that you can still use them..
  */
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
-#define DEBUG
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
 #include <linux/usb.h>
 
 static void usb_show_endpoint(struct usb_endpoint_descriptor *endpoint)
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.3.99-pre3/linux/drivers/usb/usb-ohci.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/usb-ohci.c	Mon Apr 10 22:53:24 2000
@@ -49,7 +49,7 @@
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
-#define OHCI_USE_NPS
+#define OHCI_USE_NPS		// force NoPowerSwitching mode
 
 #include "usb-ohci.h"
 
@@ -61,6 +61,12 @@
 #include <linux/pmu.h>
 #endif
 
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define	OHCI_CONTROL_INIT \
+	(OHCI_CTRL_CBSR & 0x3) \
+	| OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
 static DECLARE_WAIT_QUEUE_HEAD (op_wakeup); 
 static LIST_HEAD (ohci_hcd_list);
 static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
@@ -143,16 +149,18 @@
 			printk ("%s stat:%d\n", i < len? "...": "", urb->status);
 		}
 	} 
-	
 }
-/* just for debugging; prints all 32 branches of the int ed tree inclusive iso eds*/
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
 void ep_print_int_eds (ohci_t * ohci, char * str) {
 	int i, j;
 	 __u32 * ed_p;
 	for (i= 0; i < 32; i++) {
 		j = 5;
-		printk (KERN_DEBUG __FILE__ " %s branch int %2d(%2x):", str, i, i);
 		ed_p = &(ohci->hcca.int_table [i]);
+		if (*ed_p == 0)
+		    continue;
+		printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
 		while (*ed_p != 0 && j--) {
 			ed_t *ed = (ed_t *) bus_to_virt(le32_to_cpup(ed_p));
 			printk (" ed: %4x;", ed->hwINFO);
@@ -161,7 +169,161 @@
 		printk ("\n");
 	}
 }
-		
+
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+		label,
+		mask,
+		(mask & OHCI_INTR_MIE) ? " MIE" : "",
+		(mask & OHCI_INTR_OC) ? " OC" : "",
+		(mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+		(mask & OHCI_INTR_FNO) ? " FNO" : "",
+		(mask & OHCI_INTR_UE) ? " UE" : "",
+		(mask & OHCI_INTR_RD) ? " RD" : "",
+		(mask & OHCI_INTR_SF) ? " SF" : "",
+		(mask & OHCI_INTR_WDH) ? " WDH" : "",
+		(mask & OHCI_INTR_SO) ? " SO" : ""
+		);
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+	if (value)
+		dbg ("%s %08x", label, value);
+}
+
+static char *hcfs2string (int state)
+{
+	switch (state) {
+		case OHCI_USB_RESET:	return "reset";
+		case OHCI_USB_RESUME:	return "resume";
+		case OHCI_USB_OPER:	return "operational";
+		case OHCI_USB_SUSPEND:	return "suspend";
+	}
+	return "?";
+}
+
+// dump control and status registers
+static void ohci_dump_status (ohci_t *controller)
+{
+	struct ohci_regs	*regs = controller->regs;
+	__u32			temp;
+
+	temp = readl (&regs->revision) & 0xff;
+	if (temp != 0x10)
+		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+	temp = readl (&regs->control);
+	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+		(temp & OHCI_CTRL_RWE) ? " RWE" : "",
+		(temp & OHCI_CTRL_RWC) ? " RWC" : "",
+		(temp & OHCI_CTRL_IR) ? " IR" : "",
+		hcfs2string (temp & OHCI_CTRL_HCFS),
+		(temp & OHCI_CTRL_BLE) ? " BLE" : "",
+		(temp & OHCI_CTRL_CLE) ? " CLE" : "",
+		(temp & OHCI_CTRL_IE) ? " IE" : "",
+		(temp & OHCI_CTRL_PLE) ? " PLE" : "",
+		temp & OHCI_CTRL_CBSR
+		);
+
+	temp = readl (&regs->cmdstatus);
+	dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+		(temp & OHCI_SOC) >> 16,
+		(temp & OHCI_OCR) ? " OCR" : "",
+		(temp & OHCI_BLF) ? " BLF" : "",
+		(temp & OHCI_CLF) ? " CLF" : "",
+		(temp & OHCI_HCR) ? " HCR" : ""
+		);
+
+	ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+	ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+	// intrdisable always same as intrenable
+	// ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
+
+	maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+	maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+	maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+	maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+	maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+	maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+	struct ohci_regs	*regs = controller->regs;
+	__u32			temp, ndp, i;
+
+	temp = readl (&regs->roothub.a);
+	ndp = (temp & RH_A_NDP);
+
+	if (verbose) {
+		dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+			((temp & RH_A_POTPGT) >> 24) & 0xff,
+			(temp & RH_A_NOCP) ? " NOCP" : "",
+			(temp & RH_A_OCPM) ? " OCPM" : "",
+			(temp & RH_A_DT) ? " DT" : "",
+			(temp & RH_A_NPS) ? " NPS" : "",
+			(temp & RH_A_PSM) ? " PSM" : "",
+			ndp
+			);
+		temp = readl (&regs->roothub.b);
+		dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+			temp,
+			(temp & RH_B_PPCM) >> 16,
+			(temp & RH_B_DR)
+			);
+		temp = readl (&regs->roothub.status);
+		dbg ("roothub.status: %08x%s%s%s%s%s%s",
+			temp,
+			(temp & RH_HS_CRWE) ? " CRWE" : "",
+			(temp & RH_HS_OCIC) ? " OCIC" : "",
+			(temp & RH_HS_LPSC) ? " LPSC" : "",
+			(temp & RH_HS_DRWE) ? " DRWE" : "",
+			(temp & RH_HS_OCI) ? " OCI" : "",
+			(temp & RH_HS_LPS) ? " LPS" : ""
+			);
+	}
+	
+	for (i = 0; i < ndp; i++) {
+		temp = readl (&regs->roothub.portstatus [i]);
+		dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+			i,
+			temp,
+			(temp & RH_PS_PRSC) ? " PRSC" : "",
+			(temp & RH_PS_OCIC) ? " OCIC" : "",
+			(temp & RH_PS_PSSC) ? " PSSC" : "",
+			(temp & RH_PS_PESC) ? " PESC" : "",
+			(temp & RH_PS_CSC) ? " CSC" : "",
+
+			(temp & RH_PS_LSDA) ? " LSDA" : "",
+			(temp & RH_PS_PPS) ? " PPS" : "",
+			(temp & RH_PS_PRS) ? " PRS" : "",
+			(temp & RH_PS_POCI) ? " POCI" : "",
+			(temp & RH_PS_PSS) ? " PSS" : "",
+
+			(temp & RH_PS_PES) ? " PES" : "",
+			(temp & RH_PS_CCS) ? " CCS" : ""
+			);
+	}
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+	dbg ("OHCI controller %p state", controller->regs);
+
+	// dumps some of the state we know about
+	ohci_dump_status (controller);
+	if (verbose)
+		ep_print_int_eds (controller, "hcca");
+	dbg ("hcca frame #%04x", controller->hcca.frame_no);
+	ohci_dump_roothub (controller, 1);
+}
+
 
 #endif
 
@@ -365,12 +527,12 @@
 	if (!urb) /* just to be sure */ 
 		return -EINVAL;
 		
+	ohci = (ohci_t *) urb->dev->bus->hcpriv; 
+
 #ifdef DEBUG
 	urb_print (urb, "UNLINK", 1);
 #endif		  
 
-	ohci = (ohci_t *) urb->dev->bus->hcpriv; 
-
 	if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) 
 		return rh_unlink_urb (urb); /* a request to the virtual root hub */
 	
@@ -448,8 +610,8 @@
   		}
   		spin_unlock_irqrestore (&usb_ed_lock, flags);
   		
-    	if (cnt > 0) { 
-    		dev->wait = &wait;
+		if (cnt > 0) {
+			dev->wait = &wait;
 			current->state = TASK_UNINTERRUPTIBLE;
 			schedule_timeout (HZ / 10);
 			remove_wait_queue (&op_wakeup, &wait);
@@ -673,10 +835,12 @@
 			  		}
 			  }
 		}
-		for (i = int_branch; i < 32; i += interval) ohci->ohci_int_load[i] -= ed->int_load;
+		for (i = int_branch; i < 32; i += interval)
+		    ohci->ohci_int_load[i] -= ed->int_load;
 #ifdef DEBUG
 		ep_print_int_eds (ohci, "UNLINK_INT");
-#endif		break;
+#endif
+		break;
 		
     case ISO:
     	if (ohci->ed_isotail == ed)
@@ -787,10 +951,10 @@
 
 	switch (ed->type) {
 		case CTRL: /* stop CTRL list */
-			writel (ohci->hc_control &= ~(0x01 << 4), &ohci->regs->control); 
+			writel (ohci->hc_control &= ~OHCI_CTRL_CLE, &ohci->regs->control); 
   			break;
 		case BULK: /* stop BULK list */
-			writel (ohci->hc_control &= ~(0x01 << 5), &ohci->regs->control); 
+			writel (ohci->hc_control &= ~OHCI_CTRL_BLE, &ohci->regs->control); 
 			break;
 	}
 }
@@ -1012,8 +1176,10 @@
    	
    	if (ctrl) writel (0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
    	if (bulk) writel (0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
-	if (!ohci->ed_rm_list[!frame]) 		/* start CTRL u. BULK list */ 
-  		writel (ohci->hc_control |= (0x03<<4), &ohci->regs->control);   
+	if (!ohci->ed_rm_list[!frame]) { 		/* enable CTRL and BULK lists */ 
+  		ohci->hc_control |= OHCI_CTRL_CLE | OHCI_CTRL_BLE;
+  		writel (ohci->hc_control, &ohci->regs->control);   
+	}
    	ohci->ed_rm_list[frame] = NULL;
 
    	spin_unlock_irqrestore (&usb_ed_lock, flags);
@@ -1112,6 +1278,7 @@
  * Virtual Root Hub 
  *-------------------------------------------------------------------------*/
  
+/* Device descriptor */
 static __u8 root_hub_dev_des[] =
 {
 	0x12,       /*  __u8  bLength; */
@@ -1170,23 +1337,8 @@
 	0xff        /*  __u8  ep_bInterval; 255 ms */
 };
 
-/* 
-For OHCI we need just the  2nd Byte, so we 
-don't need this constant byte-array 
+/* Hub class-specific descriptor is constructed dynamically */
 
-static __u8 root_hub_hub_des[] =
-{ 
-	0x00,       *  __u8  bLength; *
-	0x29,       *  __u8  bDescriptorType; Hub-descriptor *
-	0x02,       *  __u8  bNbrPorts; *
-	0x00,       * __u16  wHubCharacteristics; *
-	0x00,
-	0x01,       *  __u8  bPwrOn2pwrGood; 2ms * 
- 	0x00,       *  __u8  bHubContrCurrent; 0 mA *
-	0x00,       *  __u8  DeviceRemovable; *** 8 Ports max *** *
-	0xff        *  __u8  PortPwrCtrlMask; *** 8 ports max *** *
-};
-*/
 
 /*-------------------------------------------------------------------------*/
 
@@ -1201,13 +1353,16 @@
 
 	__u8 data[8];
 
-	num_ports = readl (&ohci->regs->roothub.a) & 0xff; 
-	*(__u8 *) data = (readl (&ohci->regs->roothub.status) & 0x00030000) > 0? 1: 0;
+	num_ports = readl (&ohci->regs->roothub.a) & RH_A_NDP; 
+	*(__u8 *) data = (readl (&ohci->regs->roothub.status) & (RH_HS_LPSC | RH_HS_OCIC))
+		? 1: 0;
 	ret = *(__u8 *) data;
 
 	for ( i = 0; i < num_ports; i++) {
 		*(__u8 *) (data + (i + 1) / 8) |= 
-			((readl (&ohci->regs->roothub.portstatus[i]) & 0x001f0000) > 0? 1: 0) << ((i + 1) % 8);
+			((readl (&ohci->regs->roothub.portstatus[i]) &
+				(RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
+			    ? 1: 0) << ((i + 1) % 8);
 		ret += *(__u8 *) (data + (i + 1) / 8);
 	}
 	len = i/8 + 1;
@@ -1221,7 +1376,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
  
 static void rh_int_timer_do (unsigned long ptr)
 {
@@ -1267,10 +1422,10 @@
 
 /*-------------------------------------------------------------------------*/
 
-#define OK(x) 				len = (x); break
+#define OK(x) 			len = (x); break
 #define WR_RH_STAT(x) 		writel((x), &ohci->regs->roothub.status)
 #define WR_RH_PORTSTAT(x) 	writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
-#define RD_RH_STAT			readl(&ohci->regs->roothub.status)
+#define RD_RH_STAT		readl(&ohci->regs->roothub.status)
 #define RD_RH_PORTSTAT		readl(&ohci->regs->roothub.portstatus[wIndex-1])
 
 /* request to virtual root hub */
@@ -1309,6 +1464,10 @@
 	wValue        = le16_to_cpu (cmd->value);
 	wIndex        = le16_to_cpu (cmd->index);
 	wLength       = le16_to_cpu (cmd->length);
+
+	dbg ("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq,
+		bmRType_bReq, wLength);
+
 	switch (bmRType_bReq) {
 	/* Request Destination:
 	   without flags: Device, 
@@ -1325,7 +1484,9 @@
 		case RH_GET_STATUS | RH_ENDPOINT:	 		
 				*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);   
 		case RH_GET_STATUS | RH_CLASS: 				
-				*(__u32 *) data_buf = cpu_to_le32 (RD_RH_STAT & 0x7fff7fff); OK (4);
+				*(__u32 *) data_buf = cpu_to_le32 (
+					RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+				OK (4);
 		case RH_GET_STATUS | RH_OTHER | RH_CLASS: 	
 				*(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
 
@@ -1370,11 +1531,15 @@
 				case (RH_PORT_SUSPEND):			
 						WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); 
 				case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
-						if((RD_RH_PORTSTAT &1) != 0)  WR_RH_PORTSTAT (RH_PS_PRS ); OK (0);
+						if (RD_RH_PORTSTAT & RH_PS_CCS)
+						    WR_RH_PORTSTAT (RH_PS_PRS);
+						OK (0);
 				case (RH_PORT_POWER):			
 						WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); 
 				case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
-						if((RD_RH_PORTSTAT &1) != 0)  WR_RH_PORTSTAT (RH_PS_PES ); OK (0);
+						if (RD_RH_PORTSTAT & RH_PS_CCS)
+						    WR_RH_PORTSTAT (RH_PS_PES );
+						OK (0);
 			}
 			break;
 
@@ -1438,11 +1603,13 @@
 		case RH_SET_CONFIGURATION: 	WR_RH_STAT (0x10000); OK (0);
 
 		default: 
+			dbg ("unsupported root hub command");
 			status = TD_CC_STALL;
 	}
 	
-	dbg("USB HC roothubstat1: %x", readl ( &(ohci->regs->roothub.portstatus[0]) ));
-	dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) ));
+#ifdef	DEBUG
+	ohci_dump_roothub (ohci, 0);
+#endif
 
 	len = min(len, leni);
 	if (data != data_buf)
@@ -1473,39 +1640,44 @@
  * HC functions
  *-------------------------------------------------------------------------*/
 
-/* reset the HC not the BUS */
+/* reset the HC and BUS */
 
-static void hc_reset (ohci_t * ohci)
+static int hc_reset (ohci_t * ohci)
 {
 	int timeout = 30;
 	int smm_timeout = 50; /* 0,5 sec */
 	 	
-	if (readl (&ohci->regs->control) & 0x100) { /* SMM owns the HC */
-		writel (0x08, &ohci->regs->cmdstatus); /* request ownership */
+	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
 		dbg("USB HC TakeOver from SMM");
-		while (readl (&ohci->regs->control) & 0x100) {
+		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
 			wait_ms (10);
 			if (--smm_timeout == 0) {
 				err("USB HC TakeOver failed!");
-				break;
+				return -1;
 			}
 		}
 	}	
 		
-	writel ((1 << 31), &ohci->regs->intrdisable); /* Disable HC interrupts */
+	/* Disable HC interrupts */
+	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
 	dbg("USB HC reset_hc: %x ;", readl (&ohci->regs->control));
-  	/* this seems to be needed for the lucent controller on powerbooks.. */
-	writel (0, &ohci->regs->control);           /* Move USB to reset state */
+
+  	/* Reset USB (needed by some controllers) */
+	writel (0, &ohci->regs->control);
       	
-	writel (1,  &ohci->regs->cmdstatus);	   /* HC Reset */
-	while ((readl (&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */
+	/* 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;
+			return -1;
 		}	
 		udelay (1);
 	}	 
 	ohci->disabled = 0;
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1516,7 +1688,7 @@
 
 static int hc_start (ohci_t * ohci)
 {
-	unsigned int mask;
+  	__u32 mask;
   	unsigned int fminterval;
   	struct usb_device  * usb_dev;
 	struct ohci_device * dev;
@@ -1535,31 +1707,35 @@
 	writel (fminterval, &ohci->regs->fminterval);	
 	writel (0x628, &ohci->regs->lsthresh);
 
+ 	/* start controller operations */
+ 	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ 	writel (ohci->hc_control, &ohci->regs->control);
+ 
 	/* Choose the interrupts we care about now, others later on demand */
 	mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
-	
-	writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */
 	writel (mask, &ohci->regs->intrenable);
 	writel (mask, &ohci->regs->intrstatus);
 
-#ifdef OHCI_USE_NPS
-	writel ((readl(&ohci->regs->roothub.a) | 0x200) & ~0x100,
+#ifdef	OHCI_USE_NPS
+	writel ((readl(&ohci->regs->roothub.a) | RH_A_NPS) & ~RH_A_PSM,
 		&ohci->regs->roothub.a);
-	writel (0x10000, &ohci->regs->roothub.status);
+	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+	// POTPGT delay is bits 24-31, in 2 ms units.
 	mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
-#endif /* OHCI_USE_NPS */
+#endif	/* OHCI_USE_NPS */
  
 	/* connect the virtual root hub */
-	
+	ohci->rh.devnum = 0;
 	usb_dev = usb_alloc_dev (NULL, ohci->bus);
-	if (!usb_dev) return -1;
+	if (!usb_dev)
+	    return -ENOMEM;
 
 	dev = usb_to_ohci (usb_dev);
 	ohci->bus->root_hub = usb_dev;
 	usb_connect (usb_dev);
 	if (usb_new_device (usb_dev) != 0) {
 		usb_free_dev (usb_dev); 
-		return -1;
+		return -ENODEV;
 	}
 	
 	return 0;
@@ -1582,11 +1758,12 @@
 			return;
 	} 
 
-	dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
-	
+	// dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
+
 	if (ints & OHCI_INTR_UE) {
 		ohci->disabled++;
 		err ("OHCI Unrecoverable Error, controller disabled");
+		// e.g. due to PCI Master/Target Abort
 	}
   
 	if (ints & OHCI_INTR_WDH) {
@@ -1661,8 +1838,9 @@
 	dbg("USB HC release ohci");
 
 	/* disconnect all devices */    
-	if (ohci->bus->root_hub) usb_disconnect (&ohci->bus->root_hub);
-	
+	if (ohci->bus->root_hub)
+		usb_disconnect (&ohci->bus->root_hub);
+
 	hc_reset (ohci);
 	writel (OHCI_USB_RESET, &ohci->regs->control);
 	wait_ms (10);
@@ -1698,6 +1876,7 @@
 #endif
 	printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
 		(unsigned long)	mem_base, bufp);
+	printk(KERN_INFO __FILE__ ": %s\n", dev->name);
     
 	ohci = hc_alloc_ohci (mem_base);
 	if (!ohci) {
@@ -1707,12 +1886,16 @@
 	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
 	list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
 
-	hc_reset (ohci);
+	if (hc_reset (ohci) < 0) {
+		hc_release_ohci (ohci);
+		return -ENODEV;
+	}
+
 	writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
 	wait_ms (10);
 	usb_register_bus (ohci->bus);
 	
-	if (request_irq (irq, hc_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) {
+	if (request_irq (irq, hc_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
 		struct pm_dev *pmdev;
 
 		ohci->irq = irq;     
@@ -1724,6 +1907,10 @@
 		if (pmdev)
 			pmdev->data = ohci;
 
+#ifdef	DEBUG
+		ohci_dump (ohci, 1);
+#endif
+
 		return 0;
  	}	
  	err("request interrupt %d failed", irq);
@@ -1787,7 +1974,8 @@
 		case PBOOK_WAKE:
  			writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control);
 			wait_ms (20);
-			writel (ohci->hc_control = 0xBF, &ohci->regs->control);
+			ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+			writel (ohci->hc_control, &ohci->regs->control);
 			enable_irq (ohci->irq);
 			break;
 		}
@@ -1801,22 +1989,24 @@
 #endif /* CONFIG_PMAC_PBOOK */
 
 /*-------------------------------------------------------------------------*/
- 
+
 static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
 {
 	ohci_t * ohci = (ohci_t*) dev->data;
+	int temp = 0;
+
 	if (ohci) {
 		switch (rqst) {
 		case PM_SUSPEND:
-			dbg("USB-Bus suspend: %p", ohci);
-			writel (ohci->hc_control = 0xFF, &ohci->regs->control);
-			wait_ms (10);
+			dbg("USB-Bus suspend: %p", ohci->regs);
+			if (ohci->bus->root_hub)
+				usb_disconnect (&ohci->bus->root_hub);
+			hc_reset (ohci);
 			break;
 		case PM_RESUME:
-			dbg("USB-Bus resume: %p", ohci);
-			writel (ohci->hc_control = 0x7F, &ohci->regs->control);
-			wait_ms (20);
-			writel (ohci->hc_control = 0xBF, &ohci->regs->control);
+			dbg("USB-Bus resume: %p", ohci->regs);
+			if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0)
+				err ("can't restart controller, %d", temp);
 			break;
 		}
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c
--- v2.3.99-pre3/linux/drivers/usb/usb-storage.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/usb-storage.c	Wed Apr  5 17:01:25 2000
@@ -27,7 +27,6 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
-#include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
 
@@ -39,14 +38,6 @@
 #include "usb-storage.h"
 #include "usb-storage-debug.h"
 
-/*
- * This is the size of the structure Scsi_Host_Template.  We create
- * an instance of this structure in this file and this is a check
- * to see if this structure may have changed within the SCSI module.
- * This is by no means foolproof, but it does help us some.
- */
-#define SCSI_HOST_TEMPLATE_SIZE			(104)
-
 /* direction table -- this indicates the direction of the data
  * transfer for each command code -- a 1 indicates input
  */
@@ -76,7 +67,11 @@
 /* we allocate one of these for every device that we remember */
 struct us_data {
 	struct us_data	        *next;	         /* next device */
+
+	/* the device we're working with */
+	struct semaphore	dev_semaphore;   /* protect pusb_dev */
 	struct usb_device	*pusb_dev;       /* this usb_device */
+
 	unsigned int		flags;		 /* from filter initially */
 
 	/* information about the device -- only good if device is attached */
@@ -113,7 +108,7 @@
 	unsigned int		irqpipe;	 /* pipe for release_irq */
 
 	/* mutual exclusion structures */
-	struct semaphore	notify;          /* wait for thread to begin */
+	struct semaphore	notify;          /* thread begin/end */
 	struct semaphore        sleeper;         /* to sleep on */
 	struct semaphore        queue_exclusion; /* to protect data structs */
 };
@@ -131,7 +126,7 @@
 
 /* The list of structures and the protective lock for them */
 static struct us_data *us_list;
-spinlock_t us_list_spinlock = SPIN_LOCK_UNLOCKED;
+struct semaphore us_list_semaphore;
 
 static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
 static void storage_disconnect(struct usb_device *dev, void *ptr);
@@ -249,547 +244,267 @@
 {
 	int i;
 	unsigned int total = 0;
+	struct scatterlist *sg;
 
-	/* always zero for some commands */
-	switch (srb->cmnd[0]) {
-	case SEEK_6:
-	case SEEK_10:
-	case REZERO_UNIT:
-	case ALLOW_MEDIUM_REMOVAL:
-	case START_STOP:
-	case TEST_UNIT_READY:
-		return 0;
-
-		/* FIXME: these should be removed and tested */
-	case REQUEST_SENSE:
-	case INQUIRY:
-	case MODE_SENSE:
-		return srb->cmnd[4];
-
-		/* FIXME: these should be removed and tested */
-	case LOG_SENSE:
-	case MODE_SENSE_10:
-		return (srb->cmnd[7] << 8) + srb->cmnd[8];
-
-	default:
-		break;
-	}
-
+	/* Are we going to scatter gather? */
 	if (srb->use_sg) {
-		struct scatterlist *sg;
-
+		/* Add up the sizes of all the scatter-gather segments */
 		sg = (struct scatterlist *) srb->request_buffer;
-		for (i = 0; i < srb->use_sg; i++) {
+		for (i = 0; i < srb->use_sg; i++)
 			total += sg[i].length;
-		}
+
 		return total;
 	}
 	else
+		/* Just return the length of the buffer */
 		return srb->request_bufflen;
 }
 
 /***********************************************************************
- * Protocol routines
+ * Transport routines
  ***********************************************************************/
 
-static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
+/* Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and recieve the response.
+ */
+static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
-	int old_cmnd = 0;
+	int need_auto_sense;
 	int result;
-  
-	/* Fix some commands -- this is a form of mode translation
-	 * ATAPI devices only accept 12 byte long commands 
-	 *
-	 * NOTE: This only works because a Scsi_Cmnd struct field contains
-	 * a unsigned char cmnd[12], so we know we have storage available
-	 */
-
-	/* set command length to 12 bytes */
-	srb->cmd_len = 12;
-
-	/* determine the correct (or minimum) data length for these commands */
-	switch (us->srb->cmnd[0]) {
-
-		/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
-	case MODE_SENSE:
-	case MODE_SELECT:
-		/* save the command so we can tell what it was */
-		old_cmnd = srb->cmnd[0];
-
-		srb->cmnd[11] = 0;
-		srb->cmnd[10] = 0;
-		srb->cmnd[9] = 0;
-		srb->cmnd[8] = srb->cmnd[4];
-		srb->cmnd[7] = 0;
-		srb->cmnd[6] = 0;
-		srb->cmnd[5] = 0;
-		srb->cmnd[4] = 0;
-		srb->cmnd[3] = 0;
-		srb->cmnd[2] = srb->cmnd[2];
-		srb->cmnd[1] = srb->cmnd[1];
-		srb->cmnd[0] = srb->cmnd[0] | 0x40;
-		break;
 
-		/* change READ_6/WRITE_6 to READ_10/WRITE_10, which 
-		 * are ATAPI commands */
-	case WRITE_6:
-	case READ_6:
-		srb->cmnd[11] = 0;
-		srb->cmnd[10] = 0;
-		srb->cmnd[9] = 0;
-		srb->cmnd[8] = srb->cmnd[4];
-		srb->cmnd[7] = 0;
-		srb->cmnd[6] = 0;
-		srb->cmnd[5] = srb->cmnd[3];
-		srb->cmnd[4] = srb->cmnd[2];
-		srb->cmnd[3] = srb->cmnd[1] & 0x1F;
-		srb->cmnd[2] = 0;
-		srb->cmnd[1] = srb->cmnd[1] & 0xE0;
-		srb->cmnd[0] = srb->cmnd[0] | 0x20;
-		break;
-	} /* end switch on cmnd[0] */
-  
 	/* send the command to the transport layer */
 	result = us->transport(srb, us);
 
-	/* If we got a short transfer, but it was for a command that
-	 * can have short transfers, we're actually okay
+	/* Determine if we need to auto-sense
+	 *
+	 * I normally don't use a flag like this, but it's almost impossible
+	 * to understand what's going on here if I don't.
 	 */
-	if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
-	    ((us->srb->cmnd[0] == REQUEST_SENSE) ||
-	     (us->srb->cmnd[0] == INQUIRY) ||
-	     (us->srb->cmnd[0] == MODE_SENSE) ||
-	     (us->srb->cmnd[0] == LOG_SENSE) ||
-	     (us->srb->cmnd[0] == MODE_SENSE_10))) {
-		us->srb->result = DID_OK;
+	need_auto_sense = 0;
+
+	/*
+	 * If we're running the CB transport, which is incapable
+	 * of determining status on it's own, we need to auto-sense almost
+	 * every time.
+	 */
+	if (us->protocol == US_PR_CB) {
+		US_DEBUGP("-- CB transport device requiring auto-sense\n");
+		need_auto_sense = 1;
+
+		/* There are some exceptions to this.  Notably, if this is
+		 * a UFI device and the command is REQUEST_SENSE or INQUIRY,
+		 * then it is impossible to truly determine status.
+		 */
+		if (us->subclass == US_SC_UFI &&
+		    ((srb->cmnd[0] == REQUEST_SENSE) ||
+		     (srb->cmnd[0] == INQUIRY)))
+			need_auto_sense = 0;
+	}
+
+	/*
+	 * If we have an error, we're going to do a REQUEST_SENSE 
+	 * automatically.  Note that we differentiate between a command
+	 * "failure" and an "error" in the transport mechanism.
+	 */
+	if (result == USB_STOR_TRANSPORT_FAILED) {
+		US_DEBUGP("-- transport indicates command failure\n");
+		need_auto_sense = 1;
+	}
+	if (result == USB_STOR_TRANSPORT_ERROR) {
+		/* FIXME: we need to invoke a transport reset here */
+		US_DEBUGP("-- transport indicates transport failure\n");
+		need_auto_sense = 0;
+		srb->result = DID_ERROR << 16;
+		return;
 	}
 
 	/*
-	 * If we have an error, we're going to do a 
-	 * REQUEST_SENSE automatically
+	 * Also, if we have a short transfer on a command that can't have
+	 * a short transfer, we're going to do this.
 	 */
-	if (result != USB_STOR_TRANSPORT_GOOD) {
+	if ((srb->result == US_BULK_TRANSFER_SHORT) &&
+	    !((srb->cmnd[0] == REQUEST_SENSE) ||
+	      (srb->cmnd[0] == INQUIRY) ||
+	      (srb->cmnd[0] == MODE_SENSE) ||
+	      (srb->cmnd[0] == LOG_SENSE) ||
+	      (srb->cmnd[0] == MODE_SENSE_10))) {
+		US_DEBUGP("-- unexpectedly short transfer\n");
+		need_auto_sense = 1;
+	}
+
+	/* Now, if we need to do the auto-sense, let's do it */
+	if (need_auto_sense) {
 		int temp_result;
 		void* old_request_buffer;
 		int old_sg;
 
 		US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
 
-		us->srb->cmnd[0] = REQUEST_SENSE;
-		us->srb->cmnd[1] = 0;
-		us->srb->cmnd[2] = 0;
-		us->srb->cmnd[3] = 0;
-		us->srb->cmnd[4] = 18;
-		us->srb->cmnd[5] = 0;
+		srb->cmnd[0] = REQUEST_SENSE;
+		srb->cmnd[1] = 0;
+		srb->cmnd[2] = 0;
+		srb->cmnd[3] = 0;
+		srb->cmnd[4] = 18;
+		srb->cmnd[5] = 0;
     
 		/* set the buffer length for transfer */
-		old_request_buffer = us->srb->request_buffer;
-	        old_sg = us->srb->use_sg;
-		us->srb->request_bufflen = 18;
-		us->srb->request_buffer = us->srb->sense_buffer;
+		old_request_buffer = srb->request_buffer;
+	        old_sg = srb->use_sg;
+		srb->request_bufflen = 18;
+		srb->request_buffer = us->srb->sense_buffer;
 
 		/* FIXME: what if this command fails? */
 		temp_result = us->transport(us->srb, us);
 		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
 		US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
-			  us->srb->sense_buffer[2] & 0xf,
-			  us->srb->sense_buffer[12], 
-			  us->srb->sense_buffer[13]);
+			  srb->sense_buffer[2] & 0xf,
+			  srb->sense_buffer[12], 
+			  srb->sense_buffer[13]);
 
 		/* set the result so the higher layers expect this data */
-		us->srb->result = CHECK_CONDITION;
+		srb->result = CHECK_CONDITION;
 
 		/* we're done here */
-		us->srb->request_buffer = old_request_buffer;
-		us->srb->use_sg = old_sg;
-		return;
-	}
-  
-	/* Fix the MODE_SENSE data if we translated the command
-	 */
-	if (old_cmnd == MODE_SENSE) {
-		unsigned char *dta = (unsigned char *)us->srb->request_buffer;
-
-		/* FIXME: we need to compress the entire data structure here
-		 */
-		dta[0] = dta[1];	/* data len */
-		dta[1] = dta[2];	/* med type */
-		dta[2] = dta[3];	/* dev-spec prm */
-		dta[3] = dta[7];	/* block desc len */
-		printk (KERN_DEBUG USB_STORAGE
-			"new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
-			dta[0], dta[1], dta[2], dta[3]);
+		srb->request_buffer = old_request_buffer;
+		srb->use_sg = old_sg;
 	}
 
-	/* Fix-up the return data from an INQUIRY command to show 
-	 * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
-	 */
-	if (us->srb->cmnd[0] == INQUIRY) {
-		((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
-	}
+	/* Set return code, if necessary */
+	if (need_auto_sense && (srb->sense_buffer[0] == 0x0))
+		srb->result = GOOD;
+	if (!need_auto_sense)
+		srb->result = GOOD;
 }
 
-
-static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
+/*
+ * Control/Bulk/Interrupt transport
+ */
+static int CBI_irq(int state, void *buffer, int len, void *dev_id)
 {
-	int old_cmnd = 0;
-	int result;
-  
-	/* fix some commands -- this is a form of mode translation
-	 * UFI devices only accept 12 byte long commands 
-	 *
-	 * NOTE: This only works because a Scsi_Cmnd struct field contains
-	 * a unsigned char cmnd[12], so we know we have storage available
-	 */
-
-	/* set command length to 12 bytes (this affects the transport layer) */
-	srb->cmd_len = 12;
-
-	/* determine the correct (or minimum) data length for these commands */
-	switch (us->srb->cmnd[0]) {
-
-		/* for INQUIRY, UFI devices only ever return 36 bytes */
-	case INQUIRY:
-		us->srb->cmnd[4] = 36;
-		break;
-
-		/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
-	case MODE_SENSE:
-	case MODE_SELECT:
-		/* save the command so we can tell what it was */
-		old_cmnd = srb->cmnd[0];
-
-		srb->cmnd[11] = 0;
-		srb->cmnd[10] = 0;
-		srb->cmnd[9] = 0;
-
-		/* if we're sending data, we send all.  If getting data, 
-		 * get the minimum */
-		if (srb->cmnd[0] == MODE_SELECT)
-			srb->cmnd[8] = srb->cmnd[4];
-		else
-			srb->cmnd[8] = 8;
-
-		srb->cmnd[7] = 0;
-		srb->cmnd[6] = 0;
-		srb->cmnd[5] = 0;
-		srb->cmnd[4] = 0;
-		srb->cmnd[3] = 0;
-		srb->cmnd[2] = srb->cmnd[2];
-		srb->cmnd[1] = srb->cmnd[1];
-		srb->cmnd[0] = srb->cmnd[0] | 0x40;
-		break;
+	struct us_data *us = (struct us_data *)dev_id;
 
-		/* again, for MODE_SENSE_10, we get the minimum (8) */
-	case MODE_SENSE_10:
-		us->srb->cmnd[7] = 0;
-		us->srb->cmnd[8] = 8;
-		break;
- 
-		/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
-	case REQUEST_SENSE:
-		us->srb->cmnd[4] = 18;
-		break;
+	US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
+	US_DEBUGP("-- IRQ data length is %d\n", len);
+	US_DEBUGP("-- IRQ state is %d\n", state);
 
-		/* change READ_6/WRITE_6 to READ_10/WRITE_10, which 
-		 * are UFI commands */
-	case WRITE_6:
-	case READ_6:
-		srb->cmnd[11] = 0;
-		srb->cmnd[10] = 0;
-		srb->cmnd[9] = 0;
-		srb->cmnd[8] = srb->cmnd[4];
-		srb->cmnd[7] = 0;
-		srb->cmnd[6] = 0;
-		srb->cmnd[5] = srb->cmnd[3];
-		srb->cmnd[4] = srb->cmnd[2];
-		srb->cmnd[3] = srb->cmnd[1] & 0x1F;
-		srb->cmnd[2] = 0;
-		srb->cmnd[1] = srb->cmnd[1] & 0xE0;
-		srb->cmnd[0] = srb->cmnd[0] | 0x20;
-		break;
-	} /* end switch on cmnd[0] */
+	/* is the device removed? */
+	if (state != -ENOENT) {
+		/* save the data for interpretation later */
+		us->ip_data = le16_to_cpup((__u16 *)buffer);
+		US_DEBUGP("-- Interrupt Status 0x%x\n", us->ip_data);
   
-	/* send the command to the transport layer */
-	result = us->transport(srb, us);
+		/* was this a wanted interrupt? */
+		if (us->ip_wanted) {
+			us->ip_wanted = 0;
+			up(&(us->ip_waitq));
+		} else
+			US_DEBUGP("ERROR: Unwanted interrupt received!\n");
+	} else
+		US_DEBUGP("-- device has been removed\n");
 
-	/* If we got a short transfer, but it was for a command that
-	 * can have short transfers, we're actually okay
+	/* This return code is truly meaningless -- and I mean truly.  It gets
+	 * ignored by other layers.  It used to indicate if we wanted to get
+	 * another interrupt or disable the interrupt callback
 	 */
-	if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
-	    ((us->srb->cmnd[0] == REQUEST_SENSE) ||
-	     (us->srb->cmnd[0] == INQUIRY) ||
-	     (us->srb->cmnd[0] == MODE_SENSE) ||
-	     (us->srb->cmnd[0] == LOG_SENSE) ||
-	     (us->srb->cmnd[0] == MODE_SENSE_10))) {
-		us->srb->result = DID_OK;
-	}
+	return 0;
+}
 
-	/*
-	 * If we have an error, we're going to do a 
-	 * REQUEST_SENSE automatically
-	 */
-	if (result != USB_STOR_TRANSPORT_GOOD) {
-		int temp_result;
-		void* old_request_buffer;
-		int old_sg;
+static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int result;
 
-		US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
+	/* COMMAND STAGE */
+	/* let's send the command via the control pipe */
+	result = usb_control_msg(us->pusb_dev, 
+				 usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, 
+				 USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
+				 us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
 
-		us->srb->cmnd[0] = REQUEST_SENSE;
-		us->srb->cmnd[1] = 0;
-		us->srb->cmnd[2] = 0;
-		us->srb->cmnd[3] = 0;
-		us->srb->cmnd[4] = 18;
-		us->srb->cmnd[5] = 0;
-    
-		/* set the buffer length for transfer */
-		old_request_buffer = us->srb->request_buffer;
-	        old_sg = us->srb->use_sg;
-		us->srb->request_bufflen = 18;
-		us->srb->request_buffer = us->srb->sense_buffer;
+	/* check the return code for the command */
+	US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
+	if (result < 0) {
+		/* STALL must be cleared when they are detected */
+		if (result == -EPIPE) {
+			US_DEBUGP("-- Stall on control pipe. Clearing\n");
+			result = usb_clear_halt(us->pusb_dev, 	
+						usb_sndctrlpipe(us->pusb_dev,
+								0));
+			US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+			return USB_STOR_TRANSPORT_FAILED;
+		}
 
-		/* FIXME: what if this command fails? */
-		temp_result = us->transport(us->srb, us);
-		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
-		US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
-			  us->srb->sense_buffer[2] & 0xf,
-			  us->srb->sense_buffer[12], 
-			  us->srb->sense_buffer[13]);
+		/* Uh oh... serious problem here */
+		return USB_STOR_TRANSPORT_ERROR;
+	}
 
-		/* set the result so the higher layers expect this data */
-		us->srb->result = CHECK_CONDITION;
+	/* Set up for status notification */
+	us->ip_wanted = 1;
 
-		/* we're done here */
-		us->srb->request_buffer = old_request_buffer;
-		us->srb->use_sg = old_sg;
-		return;
+	/* DATA STAGE */
+	/* transfer the data payload for this command, if one exists*/
+	if (us_transfer_length(srb)) {
+		us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+		US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
 	}
-  
-	/* Fix the MODE_SENSE data here if we had to translate the command
-	 */
-	if (old_cmnd == MODE_SENSE) {
-		unsigned char *dta = (unsigned char *)us->srb->request_buffer;
 
-		/* FIXME: we need to compress the entire data structure here
-		 */
-		dta[0] = dta[1];	/* data len */
-		dta[1] = dta[2];	/* med type */
-		dta[2] = dta[3];	/* dev-spec prm */
-		dta[3] = dta[7];	/* block desc len */
-		printk (KERN_DEBUG USB_STORAGE
-			"new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
-			dta[0], dta[1], dta[2], dta[3]);
-	}
+	/* STATUS STAGE */
 
-	/* Fix-up the return data from an INQUIRY command to show 
-	 * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
-	 */
-	if (us->srb->cmnd[0] == INQUIRY) {
-		((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
-	}
-}
-
-static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
-{
-	unsigned int result = 0;
-
-	/* This code supports devices which do not support {READ|WRITE}_6
-	 * Apparently, neither Windows or MacOS will use these commands,
-	 * so some devices do not support them
-	 */
-	if (us->flags & US_FL_MODE_XLATE) {
-    
-		/* translate READ_6 to READ_10 */
-		if (us->srb->cmnd[0] == 0x08) {
-      
-			/* get the control */
-			us->srb->cmnd[9] = us->srb->cmnd[5];
-      
-			/* get the length */
-			us->srb->cmnd[8] = us->srb->cmnd[6];
-			us->srb->cmnd[7] = 0;
-      
-			/* set the reserved area to 0 */
-			us->srb->cmnd[6] = 0;	    
-      
-			/* get LBA */
-			us->srb->cmnd[5] = us->srb->cmnd[3];
-			us->srb->cmnd[4] = us->srb->cmnd[2];
-			us->srb->cmnd[3] = 0;
-			us->srb->cmnd[2] = 0;
-      
-			/* LUN and other info in cmnd[1] can stay */
-      
-			/* fix command code */
-			us->srb->cmnd[0] = 0x28;
-      
-			US_DEBUGP("Changing READ_6 to READ_10\n");
-			US_DEBUG(us_show_command(us->srb));
-		}
-    
-		/* translate WRITE_6 to WRITE_10 */
-		if (us->srb->cmnd[0] == 0x0A) {
-      
-			/* get the control */
-			us->srb->cmnd[9] = us->srb->cmnd[5];
-      
-			/* get the length */
-			us->srb->cmnd[8] = us->srb->cmnd[4];
-			us->srb->cmnd[7] = 0;
-      
-			/* set the reserved area to 0 */
-			us->srb->cmnd[6] = 0;	    
-      
-			/* get LBA */
-			us->srb->cmnd[5] = us->srb->cmnd[3];
-			us->srb->cmnd[4] = us->srb->cmnd[2];
-			us->srb->cmnd[3] = 0;
-			us->srb->cmnd[2] = 0;
-	    
-			/* LUN and other info in cmnd[1] can stay */
-      
-			/* fix command code */
-			us->srb->cmnd[0] = 0x2A;
-
-			US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
-			US_DEBUG(us_show_command(us->srb));
-		}
-	} /* if (us->flags & US_FL_MODE_XLATE) */
-  
-	/* send the command to the transport layer */
-	result = us->transport(us->srb, us);
-
-	/* If we got a short transfer, but it was for a command that
-	 * can have short transfers, we're actually okay
-	 */
-	if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
-	    ((us->srb->cmnd[0] == REQUEST_SENSE) ||
-	     (us->srb->cmnd[0] == INQUIRY) ||
-	     (us->srb->cmnd[0] == MODE_SENSE) ||
-	     (us->srb->cmnd[0] == LOG_SENSE) ||
-	     (us->srb->cmnd[0] == MODE_SENSE_10))) {
-		us->srb->result = DID_OK;
-	}
-
-	/* if we have an error, we're going to do a REQUEST_SENSE 
-	 * automatically */
-	if (result != USB_STOR_TRANSPORT_GOOD) {
-		int temp_result;
-		int old_sg;
-		void* old_request_buffer;
-
-		US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
-
-		/* set up the REQUEST_SENSE command and parameters */
-		us->srb->cmnd[0] = REQUEST_SENSE;
-		us->srb->cmnd[1] = 0;
-		us->srb->cmnd[2] = 0;
-		us->srb->cmnd[3] = 0;
-		us->srb->cmnd[4] = 18;
-		us->srb->cmnd[5] = 0;
-    
-		/* set the buffer length for transfer */
-		old_request_buffer = us->srb->request_buffer;
-	        old_sg = us->srb->use_sg;
-		us->srb->request_bufflen = 18;
-		us->srb->request_buffer = us->srb->sense_buffer;
-
-		/* FIXME: what if this command fails? */
-		temp_result = us->transport(us->srb, us);
-		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
-		US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
-			  us->srb->sense_buffer[2] & 0xf,
-			  us->srb->sense_buffer[12], 
-			  us->srb->sense_buffer[13]);
-
-		/* set the result so the higher layers expect this data */
-		us->srb->result = CHECK_CONDITION;
-
-		/* we're done here */
-		us->srb->use_sg = old_sg;
-		us->srb->request_buffer = old_request_buffer;
-		return;
-	}
-
-	/* fix the results of an INQUIRY */
-	if (us->srb->cmnd[0] == INQUIRY) {
-		US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
-		((unsigned char*)us->srb->request_buffer)[2] |= 2;
-	}
-}
-
-/***********************************************************************
- * Transport routines
- ***********************************************************************/
-
-static int CBI_irq(int state, void *buffer, int len, void *dev_id)
-{
-	struct us_data *us = (struct us_data *)dev_id;
-
-	US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
-
-	/* save the data for interpretation later */
-	if (state != USB_ST_REMOVED) {
-		us->ip_data = le16_to_cpup((__u16 *)buffer);
-		US_DEBUGP("Interrupt Status 0x%x\n", us->ip_data);
-	}
-  
-	/* was this a wanted interrupt? */
+	/* go to sleep until we get this interrupt */
+	down(&(us->ip_waitq));
+	
+	/* if we were woken up by a reset instead of the actual interrupt */
 	if (us->ip_wanted) {
+		US_DEBUGP("Did not get interrupt on CBI\n");
 		us->ip_wanted = 0;
-		up(&(us->ip_waitq));
-	} else {
-		US_DEBUGP("ERROR: Unwanted interrupt received!\n");
+		return USB_STOR_TRANSPORT_ERROR;
 	}
-
-	/* This return code is truly meaningless -- and I mean truly.  It gets
-	 * ignored by other layers.  It used to indicate if we wanted to get
-	 * another interrupt or disable the interrupt callback
+	
+	US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
+	
+	/* UFI gives us ASC and ASCQ, like a request sense
+	 *
+	 * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI
+	 * devices, so we ignore the information for those commands.  Note
+	 * that this means we could be ignoring a real error on these
+	 * commands, but that can't be helped.
 	 */
-	return 0;
-}
-
-/* This issues a CB[I] Reset to the device in question
- */
-static int CB_reset(struct us_data *us)
-{
-	unsigned char cmd[12];
-	int result;
-
-	US_DEBUGP("CB_reset\n");
-
-	memset(cmd, 0xFF, sizeof(cmd));
-	cmd[0] = SEND_DIAGNOSTIC;
-	cmd[1] = 4;
-	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
-				 US_CBI_ADSC, 
-				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-				 0, us->ifnum, cmd, sizeof(cmd), HZ*5);
-
-	/* long wait for reset */
-	schedule_timeout(HZ*6);
-
-	US_DEBUGP("CB_reset: clearing endpoint halt\n");
-	usb_clear_halt(us->pusb_dev, 
-		       usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
-	usb_clear_halt(us->pusb_dev, 
-		       usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+	if (us->subclass == US_SC_UFI) {
+		if (srb->cmnd[0] == REQUEST_SENSE ||
+		    srb->cmnd[0] == INQUIRY)
+			return USB_STOR_TRANSPORT_GOOD;
+		else
+			if (us->ip_data)
+				return USB_STOR_TRANSPORT_FAILED;
+			else
+				return USB_STOR_TRANSPORT_GOOD;
+	}
+	
+	/* If not UFI, we interpret the data as a result code 
+	 * The first byte should always be a 0x0
+	 * The second byte & 0x0F should be 0x0 for good, otherwise error 
+	 */
+	switch ((us->ip_data & 0xFF0F)) {
+	case 0x0000: 
+		return USB_STOR_TRANSPORT_GOOD;
+	case 0x0001: 
+		return USB_STOR_TRANSPORT_FAILED;
+	default: 
+		return USB_STOR_TRANSPORT_ERROR;
+	}
 
-	US_DEBUGP("CB_reset done\n");
-	return 0;
+	US_DEBUGP("CBI_transport() reached end of function\n");
+	return USB_STOR_TRANSPORT_ERROR;
 }
 
 /*
- * Control/Bulk/Interrupt transport
+ * Control/Bulk transport
  */
-static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
+static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
 	int result;
 
-	US_DEBUGP("CBI gets a command:\n");
-	US_DEBUG(us_show_command(srb));
-
 	/* COMMAND STAGE */
 	/* let's send the command via the control pipe */
 	result = usb_control_msg(us->pusb_dev, 
@@ -798,142 +513,449 @@
 				 us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
 
 	/* check the return code for the command */
-	US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
 	if (result < 0) {
+		US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
+
 		/* a stall is a fatal condition from the device */
 		if (result == -EPIPE) {
 			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			US_DEBUGP("-- Return from usb_clear_halt() is %d\n",
-				  usb_clear_halt(us->pusb_dev, 
-						 usb_sndctrlpipe(us->pusb_dev,
-								 0)));
-			return USB_STOR_TRANSPORT_ERROR;
+			result = usb_clear_halt(us->pusb_dev, 
+						usb_sndctrlpipe(us->pusb_dev,
+								0));
+			US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+			return USB_STOR_TRANSPORT_FAILED;
 		}
 
-		/* FIXME: we need to handle NAKs here */
+		/* Uh oh... serious problem here */
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
-	/* Set up for status notification */
-	us->ip_wanted = 1;
-
 	/* DATA STAGE */
 	/* transfer the data payload for this command, if one exists*/
 	if (us_transfer_length(srb)) {
 		us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
-		US_DEBUGP("CBI data stage result is 0x%x\n", result);
+		US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
 	}
-
+	
+	
 	/* STATUS STAGE */
+	/* NOTE: CB does not have a status stage.  Silly, I know.  So
+	 * we have to catch this at a higher level.
+	 */
+	return USB_STOR_TRANSPORT_GOOD;
+}
 
-	/* go to sleep until we get this interrupt */
-	down(&(us->ip_waitq));
+/*
+ * Bulk only transport
+ */
+static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+	struct bulk_cb_wrap bcb;
+	struct bulk_cs_wrap bcs;
+	int result;
+	int pipe;
+	int partial;
 	
-	/* if we were woken up by a reset instead of the actual interrupt */
-	if (us->ip_wanted) {
-		US_DEBUGP("Did not get interrupt on CBI\n");
-		us->ip_wanted = 0;
-		return USB_STOR_TRANSPORT_ERROR;
+	/* set up the command wrapper */
+	bcb.Signature = US_BULK_CB_SIGN;
+	bcb.DataTransferLength = us_transfer_length(srb);
+	bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
+	bcb.Tag = srb->serial_number;
+	bcb.Lun = srb->cmnd[1] >> 5;
+	bcb.Length = srb->cmd_len;
+	
+	/* construct the pipe handle */
+	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+	
+	/* copy the command payload */
+	memset(bcb.CDB, 0, sizeof(bcb.CDB));
+	memcpy(bcb.CDB, srb->cmnd, bcb.Length);
+	
+	/* send it to out endpoint */
+	US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
+		  bcb.Signature, bcb.Tag, bcb.Lun, bcb.DataTransferLength,
+		  bcb.Flags, bcb.Length);
+	result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
+			      US_BULK_CB_WRAP_LEN, &partial, HZ*5);
+	US_DEBUGP("Bulk command transfer result=%d\n", result);
+	
+	/* if we stall, we need to clear it before we go on */
+	if (result == -EPIPE) {
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+		usb_clear_halt(us->pusb_dev, pipe);
 	}
 	
-	US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
+	/* if the command transfered well, then we go to the data stage */
+	if (result == 0) {
+		/* send/receive data payload, if there is any */
+		if (bcb.DataTransferLength) {
+			us_transfer(srb, bcb.Flags);
+			US_DEBUGP("Bulk data transfer result 0x%x\n", 
+				  srb->result);
+		}
+	}
 	
-	/* UFI gives us ASC and ASCQ, like a request sense
-	 *
-	 * REQUEST_SENSE and INQUIRY don't affect the sense data, so we
-	 * ignore the information for those commands
+	/* See flow chart on pg 15 of the Bulk Only Transport spec for
+	 * an explanation of how this code works.
 	 */
-	if (us->subclass == US_SC_UFI) {
-		if (srb->cmnd[0] == REQUEST_SENSE ||
-		    srb->cmnd[0] == INQUIRY)
-			return USB_STOR_TRANSPORT_GOOD;
-		else
-			if (us->ip_data)
-				return USB_STOR_TRANSPORT_FAILED;
-			else
-				return USB_STOR_TRANSPORT_GOOD;
+	
+	/* construct the pipe handle */
+	pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+	
+	/* get CSW for device status */
+	result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
+			      US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+	
+	/* did the attempt to read the CSW fail? */
+	if (result == -EPIPE) {
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+		usb_clear_halt(us->pusb_dev, pipe);
+		
+		/* get the status again */
+		result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
+				      US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+		
+		/* if it fails again, we need a reset and return an error*/
+		if (result == -EPIPE) {
+			return USB_STOR_TRANSPORT_ERROR;
+		}
 	}
 	
-	/* otherwise, we interpret the data normally */
-	switch (us->ip_data) {
-	case 0x0001: 
+	/* if we still have a failure at this point, we're in trouble */
+	if (result) {
+		US_DEBUGP("Bulk status result = %d\n", result);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	
+	/* check bulk status */
+	US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
+		  bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
+	if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
+	    bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+		US_DEBUGP("Bulk logical error\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	
+	/* based on the status code, we report good or bad */
+	switch (bcs.Status) {
+	case US_BULK_STAT_OK:
+		/* command good -- note that we could be short on data */
 		return USB_STOR_TRANSPORT_GOOD;
-	case 0x0002: 
+
+	case US_BULK_STAT_FAIL:
+		/* command failed */
 		return USB_STOR_TRANSPORT_FAILED;
-	default: 
+		
+	case US_BULK_STAT_PHASE:
+		/* phase error */
 		return USB_STOR_TRANSPORT_ERROR;
 	}
+	
+	/* we should never get here, but if we do, we're in trouble */
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+/***********************************************************************
+ * Protocol routines
+ ***********************************************************************/
+
+static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int old_cmnd = 0;
+  
+	/* Fix some commands -- this is a form of mode translation
+	 * ATAPI devices only accept 12 byte long commands 
+	 *
+	 * NOTE: This only works because a Scsi_Cmnd struct field contains
+	 * a unsigned char cmnd[12], so we know we have storage available
+	 */
+
+	/* set command length to 12 bytes */
+	srb->cmd_len = 12;
+
+	/* determine the correct (or minimum) data length for these commands */
+	switch (srb->cmnd[0]) {
+
+		/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
+	case MODE_SENSE:
+	case MODE_SELECT:
+		/* save the command so we can tell what it was */
+		old_cmnd = srb->cmnd[0];
+
+		srb->cmnd[11] = 0;
+		srb->cmnd[10] = 0;
+		srb->cmnd[9] = 0;
+		srb->cmnd[8] = srb->cmnd[4];
+		srb->cmnd[7] = 0;
+		srb->cmnd[6] = 0;
+		srb->cmnd[5] = 0;
+		srb->cmnd[4] = 0;
+		srb->cmnd[3] = 0;
+		srb->cmnd[2] = srb->cmnd[2];
+		srb->cmnd[1] = srb->cmnd[1];
+		srb->cmnd[0] = srb->cmnd[0] | 0x40;
+		break;
+
+		/* change READ_6/WRITE_6 to READ_10/WRITE_10, which 
+		 * are ATAPI commands */
+	case WRITE_6:
+	case READ_6:
+		srb->cmnd[11] = 0;
+		srb->cmnd[10] = 0;
+		srb->cmnd[9] = 0;
+		srb->cmnd[8] = srb->cmnd[4];
+		srb->cmnd[7] = 0;
+		srb->cmnd[6] = 0;
+		srb->cmnd[5] = srb->cmnd[3];
+		srb->cmnd[4] = srb->cmnd[2];
+		srb->cmnd[3] = srb->cmnd[1] & 0x1F;
+		srb->cmnd[2] = 0;
+		srb->cmnd[1] = srb->cmnd[1] & 0xE0;
+		srb->cmnd[0] = srb->cmnd[0] | 0x20;
+		break;
+	} /* end switch on cmnd[0] */
+  
+	/* send the command to the transport layer */
+	invoke_transport(srb, us);
+  
+	/* Fix the MODE_SENSE data if we translated the command
+	 */
+	if (old_cmnd == MODE_SENSE) {
+		unsigned char *dta = (unsigned char *)us->srb->request_buffer;
+
+		/* FIXME: we need to compress the entire data structure here
+		 */
+		dta[0] = dta[1];	/* data len */
+		dta[1] = dta[2];	/* med type */
+		dta[2] = dta[3];	/* dev-spec prm */
+		dta[3] = dta[7];	/* block desc len */
+		printk (KERN_DEBUG USB_STORAGE
+			"new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
+			dta[0], dta[1], dta[2], dta[3]);
+	}
+
+	/* Fix-up the return data from an INQUIRY command to show 
+	 * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+	 */
+	if (srb->cmnd[0] == INQUIRY) {
+		((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
+	}
+}
+
+
+static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int old_cmnd = 0;
+  
+	/* fix some commands -- this is a form of mode translation
+	 * UFI devices only accept 12 byte long commands 
+	 *
+	 * NOTE: This only works because a Scsi_Cmnd struct field contains
+	 * a unsigned char cmnd[12], so we know we have storage available
+	 */
+
+	/* set command length to 12 bytes (this affects the transport layer) */
+	srb->cmd_len = 12;
+
+	/* determine the correct (or minimum) data length for these commands */
+	switch (srb->cmnd[0]) {
+
+		/* for INQUIRY, UFI devices only ever return 36 bytes */
+	case INQUIRY:
+		srb->cmnd[4] = 36;
+		break;
+
+		/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
+	case MODE_SENSE:
+	case MODE_SELECT:
+		/* save the command so we can tell what it was */
+		old_cmnd = srb->cmnd[0];
+
+		srb->cmnd[11] = 0;
+		srb->cmnd[10] = 0;
+		srb->cmnd[9] = 0;
+
+		/* if we're sending data, we send all.  If getting data, 
+		 * get the minimum */
+		if (srb->cmnd[0] == MODE_SELECT)
+			srb->cmnd[8] = srb->cmnd[4];
+		else
+			srb->cmnd[8] = 8;
+
+		srb->cmnd[7] = 0;
+		srb->cmnd[6] = 0;
+		srb->cmnd[5] = 0;
+		srb->cmnd[4] = 0;
+		srb->cmnd[3] = 0;
+		srb->cmnd[2] = srb->cmnd[2];
+		srb->cmnd[1] = srb->cmnd[1];
+		srb->cmnd[0] = srb->cmnd[0] | 0x40;
+		break;
+
+		/* again, for MODE_SENSE_10, we get the minimum (8) */
+	case MODE_SENSE_10:
+		srb->cmnd[7] = 0;
+		srb->cmnd[8] = 8;
+		break;
+ 
+		/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
+	case REQUEST_SENSE:
+		srb->cmnd[4] = 18;
+		break;
+
+		/* change READ_6/WRITE_6 to READ_10/WRITE_10, which 
+		 * are UFI commands */
+	case WRITE_6:
+	case READ_6:
+		srb->cmnd[11] = 0;
+		srb->cmnd[10] = 0;
+		srb->cmnd[9] = 0;
+		srb->cmnd[8] = srb->cmnd[4];
+		srb->cmnd[7] = 0;
+		srb->cmnd[6] = 0;
+		srb->cmnd[5] = srb->cmnd[3];
+		srb->cmnd[4] = srb->cmnd[2];
+		srb->cmnd[3] = srb->cmnd[1] & 0x1F;
+		srb->cmnd[2] = 0;
+		srb->cmnd[1] = srb->cmnd[1] & 0xE0;
+		srb->cmnd[0] = srb->cmnd[0] | 0x20;
+		break;
+	} /* end switch on cmnd[0] */
+
+	/* send the command to the transport layer */
+	invoke_transport(srb, us);
+	
+	/* Fix the MODE_SENSE data here if we had to translate the command
+	 */
+	if (old_cmnd == MODE_SENSE) {
+		unsigned char *dta = (unsigned char *)us->srb->request_buffer;
+
+		/* FIXME: we need to compress the entire data structure here
+		 */
+		dta[0] = dta[1];	/* data len */
+		dta[1] = dta[2];	/* med type */
+		dta[2] = dta[3];	/* dev-spec prm */
+		dta[3] = dta[7];	/* block desc len */
+		printk (KERN_DEBUG USB_STORAGE
+			"new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
+			dta[0], dta[1], dta[2], dta[3]);
+	}
+
+	/* Fix-up the return data from an INQUIRY command to show 
+	 * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+	 */
+	if (srb->cmnd[0] == INQUIRY) {
+		((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
+	}
+}
+
+static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+	/* This code supports devices which do not support {READ|WRITE}_6
+	 * Apparently, neither Windows or MacOS will use these commands,
+	 * so some devices do not support them
+	 */
+	if (us->flags & US_FL_MODE_XLATE) {
+    
+		/* translate READ_6 to READ_10 */
+		if (srb->cmnd[0] == 0x08) {
+      
+			/* get the control */
+			srb->cmnd[9] = us->srb->cmnd[5];
+      
+			/* get the length */
+			srb->cmnd[8] = us->srb->cmnd[6];
+			srb->cmnd[7] = 0;
+      
+			/* set the reserved area to 0 */
+			srb->cmnd[6] = 0;	    
+      
+			/* get LBA */
+			srb->cmnd[5] = us->srb->cmnd[3];
+			srb->cmnd[4] = us->srb->cmnd[2];
+			srb->cmnd[3] = 0;
+			srb->cmnd[2] = 0;
+      
+			/* LUN and other info in cmnd[1] can stay */
+      
+			/* fix command code */
+			srb->cmnd[0] = 0x28;
+      
+			US_DEBUGP("Changing READ_6 to READ_10\n");
+			US_DEBUG(us_show_command(srb));
+		}
+    
+		/* translate WRITE_6 to WRITE_10 */
+		if (srb->cmnd[0] == 0x0A) {
+      
+			/* get the control */
+			srb->cmnd[9] = us->srb->cmnd[5];
+      
+			/* get the length */
+			srb->cmnd[8] = us->srb->cmnd[4];
+			srb->cmnd[7] = 0;
+      
+			/* set the reserved area to 0 */
+			srb->cmnd[6] = 0;	    
+      
+			/* get LBA */
+			srb->cmnd[5] = us->srb->cmnd[3];
+			srb->cmnd[4] = us->srb->cmnd[2];
+			srb->cmnd[3] = 0;
+			srb->cmnd[2] = 0;
+	    
+			/* LUN and other info in cmnd[1] can stay */
+      
+			/* fix command code */
+			srb->cmnd[0] = 0x2A;
 
-	US_DEBUGP("CBI_transport() reached end of function\n");
-	return USB_STOR_TRANSPORT_ERROR;
+			US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
+			US_DEBUG(us_show_command(us->srb));
+		}
+	} /* if (us->flags & US_FL_MODE_XLATE) */
+
+	/* send the command to the transport layer */
+	invoke_transport(srb, us);
+
+	/* fix the results of an INQUIRY */
+	if (srb->cmnd[0] == INQUIRY) {
+		US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
+		((unsigned char*)us->srb->request_buffer)[2] |= 2;
+	}
 }
 
-/*
- * Control/Bulk transport
+/***********************************************************************
+ * Reset routines
+ ***********************************************************************/
+
+/* This issues a CB[I] Reset to the device in question
  */
-static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
+static int CB_reset(struct us_data *us)
 {
+	unsigned char cmd[12];
 	int result;
-	__u8 status[2];
-
-	US_DEBUGP("CBC gets a command:\n");
-	US_DEBUG(us_show_command(srb));
-
-	/* COMMAND STAGE */
-	/* let's send the command via the control pipe */
-	result = usb_control_msg(us->pusb_dev, 
-				 usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, 
-				 USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
-				 us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
-
-	/* check the return code for the command */
-	if (result < 0) {
-		US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
 
-		/* a stall is a fatal condition from the device */
-		if (result == -EPIPE) {
-			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			US_DEBUGP("-- Return from usb_clear_halt() is %d\n",
-				  usb_clear_halt(us->pusb_dev, 
-						 usb_sndctrlpipe(us->pusb_dev,
-								 0)));
-			return USB_STOR_TRANSPORT_ERROR;
-		}
+	US_DEBUGP("CB_reset() called\n");
 
-		/* FIXME: we need to handle NAKs here */
-		return USB_STOR_TRANSPORT_ERROR;
-	}
+	memset(cmd, 0xFF, sizeof(cmd));
+	cmd[0] = SEND_DIAGNOSTIC;
+	cmd[1] = 4;
+	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+				 US_CBI_ADSC, 
+				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				 0, us->ifnum, cmd, sizeof(cmd), HZ*5);
 
-	/* DATA STAGE */
-	/* transfer the data payload for this command, if one exists*/
-	if (us_transfer_length(srb)) {
-		us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
-		US_DEBUGP("CBC data stage result is 0x%x\n", result);
-	}
-	
-	
-	/* STATUS STAGE */
-	/* FIXME: this is wrong */
-	result = usb_control_msg(us->pusb_dev, 
-				 usb_rcvctrlpipe(us->pusb_dev,0),
-				 USB_REQ_GET_STATUS, USB_DIR_IN |
-				 USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-				 0, us->ifnum, status, sizeof(status), HZ*5);
+	/* long wait for reset */
+	schedule_timeout(HZ*6);
 
-	if (result < 0) {
-		US_DEBUGP("CBC Status stage returns %d\n", result);
-		return USB_STOR_TRANSPORT_ERROR;
-	}
+	US_DEBUGP("CB_reset: clearing endpoint halt\n");
+	usb_clear_halt(us->pusb_dev, 
+		       usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+	usb_clear_halt(us->pusb_dev, 
+		       usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
 
-	US_DEBUGP("Got CB status 0x%x 0x%x\n", status[0], status[1]);
-	if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY &&
-	    ( (status[0] & ~3) || status[1]))
-		return USB_STOR_TRANSPORT_FAILED;
-	else
-		return USB_STOR_TRANSPORT_GOOD;
-	
-	US_DEBUGP("CB_transport() reached end of function\n");
-	return USB_STOR_TRANSPORT_ERROR;
+	US_DEBUGP("CB_reset done\n");
+	return 0;
 }
 
 /* FIXME: Does this work? */
@@ -961,135 +983,31 @@
 	return result;
 }
 
-/*
- * Bulk only transport
- */
-static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
-	struct bulk_cb_wrap bcb;
-	struct bulk_cs_wrap bcs;
-	int result;
-	int pipe;
-	int partial;
-	
-	/* set up the command wrapper */
-	bcb.Signature = US_BULK_CB_SIGN;
-	bcb.DataTransferLength = us_transfer_length(srb);
-	bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
-	bcb.Tag = srb->serial_number;
-	bcb.Lun = 0;
-	bcb.Length = srb->cmd_len;
-	
-	/* construct the pipe handle */
-	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
-	
-	/* copy the command payload */
-	memset(bcb.CDB, 0, sizeof(bcb.CDB));
-	memcpy(bcb.CDB, srb->cmnd, bcb.Length);
-	
-	/* send it to out endpoint */
-	US_DEBUGP("Bulk command S 0x%x T 0x%x L %d F %d CL %d\n",
-		  bcb.Signature, bcb.Tag, bcb.DataTransferLength,
-		  bcb.Flags, bcb.Length);
-	result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
-			      US_BULK_CB_WRAP_LEN, &partial, HZ*5);
-	US_DEBUGP("Bulk command transfer result=%d\n", result);
-	
-	/* if we stall, we need to clear it before we go on */
-	if (result == -EPIPE) {
-		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		usb_clear_halt(us->pusb_dev, pipe);
-	}
-	
-	/* if the command transfered well, then we go to the data stage */
-	if (result == 0) {
-		/* send/receive data payload, if there is any */
-		if (bcb.DataTransferLength) {
-			us_transfer(srb, bcb.Flags);
-			US_DEBUGP("Bulk data transfer result 0x%x\n", 
-				  srb->result);
-		}
-	}
-	
-	/* See flow chart on pg 15 of the Bulk Only Transport spec for
-	 * an explanation of how this code works.
-	 */
-	
-	/* construct the pipe handle */
-	pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
-	
-	/* get CSW for device status */
-	result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
-			      US_BULK_CS_WRAP_LEN, &partial, HZ*5);
-	
-	/* did the attempt to read the CSW fail? */
-	if (result == -EPIPE) {
-		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		usb_clear_halt(us->pusb_dev, pipe);
-		
-		/* get the status again */
-		result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
-				      US_BULK_CS_WRAP_LEN, &partial, HZ*5);
-		
-		/* if it fails again, we need a reset and return an error*/
-		if (result == -EPIPE) {
-			Bulk_reset(us);
-			return USB_STOR_TRANSPORT_ERROR;
-		}
-	}
-	
-	/* if we still have a failure at this point, we're in trouble */
-	if (result) {
-		US_DEBUGP("Bulk status result = %d\n", result);
-		return USB_STOR_TRANSPORT_ERROR;
-	}
-	
-	/* check bulk status */
-	US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
-		  bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
-	if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
-	    bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
-		US_DEBUGP("Bulk logical error\n");
-		return USB_STOR_TRANSPORT_ERROR;
-	}
-	
-	/* based on the status code, we report good or bad */
-	switch (bcs.Status) {
-	case US_BULK_STAT_OK:
-		/* command good -- note that we could be short on data */
-		return USB_STOR_TRANSPORT_GOOD;
-
-	case US_BULK_STAT_FAIL:
-		/* command failed */
-		return USB_STOR_TRANSPORT_FAILED;
-		
-	case US_BULK_STAT_PHASE:
-		/* phase error */
-		Bulk_reset(us);
-		return USB_STOR_TRANSPORT_ERROR;
-	}
-	
-	/* we should never get here, but if we do, we're in trouble */
-	return USB_STOR_TRANSPORT_ERROR;
-}
-
 /***********************************************************************
  * Host functions 
  ***********************************************************************/
 
-/* detect adapter (always true ) */
+static const char* us_info(struct Scsi_Host *host)
+{
+	return "SCSI emulation for USB Mass Storage devices\n";
+}
+
+/* detect a virtual adapter (always works) */
 static int us_detect(struct SHT *sht)
 {
-	/* FIXME - not nice at all, but how else ? */
-	struct us_data *us = (struct us_data *)sht->proc_dir;
-	char name[32];
-
-	/* set up our name */
-	sprintf(name, "usbscsi%d", us->host_number);
-	sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL);
+	struct us_data *us;
+	char local_name[32];
+
+	/* This is not nice at all, but how else are we to get the
+	 * data here? */
+	us = (struct us_data *)sht->proc_dir;
+
+	/* set up the name of our subdirectory under /proc/scsi/ */
+	sprintf(local_name, "usb-storage-%d", us->host_number);
+	sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
 	if (!sht->proc_name)
 		return 0;
-	strcpy(sht->proc_name, name);
+	strcpy(sht->proc_name, local_name);
 
 	/* we start with no /proc directory entry */
 	sht->proc_dir = NULL;
@@ -1105,36 +1023,34 @@
 	/* odd... didn't register properly.  Abort and free pointers */
 	kfree(sht->proc_name);
 	sht->proc_name = NULL;
-	sht->name = NULL;
 	return 0;
 }
 
-/* release - must be here to stop scsi
- *	from trying to release IRQ etc.
- *	Kill off our data
+/* Release all resources used by the virtual host
+ *
+ * NOTE: There is no contention here, because we're allready deregistered
+ * the driver and we're doing each virtual host in turn, not in parallel
  */
 static int us_release(struct Scsi_Host *psh)
 {
 	struct us_data *us = (struct us_data *)psh->hostdata[0];
-	unsigned long flags;
-	int result;
-
-	/* lock the data structures */
-	spin_lock_irqsave(&us_list_spinlock, flags);
 
 	US_DEBUGP("us_release() called for host %s\n", us->htmplt.name);
 
-	/* release the interrupt handler, if necessary */
-	if (us->irq_handle) {
-		US_DEBUGP("-- releasing irq\n");
-		result = usb_release_irq(us->pusb_dev, us->irq_handle, 
-					 us->irqpipe);
-		US_DEBUGP("-- usb_release_irq() returned %d\n", result);
-		us->irq_handle = NULL;
-	}
-
-	/* lock the data structures */
-	spin_unlock_irqrestore(&us_list_spinlock, flags);
+	/* Kill the control threads
+	 *
+	 * Enqueue the command, wake up the thread, and wait for 
+	 * notification that it's exited.
+	 */
+	US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");
+	us->action = US_ACT_EXIT;
+	up(&(us->sleeper));
+	down(&(us->notify));
+	
+	/* free the data structure we were using */
+	US_DEBUGP("-- freeing private host data structure\n");
+	kfree(us);
+	(struct us_data*)psh->hostdata[0] = NULL;
 
 	/* we always have a successful release */
 	return 0;
@@ -1171,20 +1087,38 @@
 	return 0;
 }
 
-/* FIXME: This doesn't actually abort anything */
+/***********************************************************************
+ * Error handling functions
+ ***********************************************************************/
+
+/* Command abort
+ *
+ * Note that this is really only meaningful right now for CBI transport
+ * devices which have failed to give us the command completion interrupt
+ */
 static int us_abort( Scsi_Cmnd *srb )
 {
-	return 0;
+	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+	US_DEBUGP("us_abort() called\n");
+
+	/* if we're stuck waiting for an IRQ, simulate it */
+	if (us->ip_wanted) {
+		US_DEBUGP("-- simulating missing IRQ\n");
+		up(&(us->ip_waitq));
+		return SUCCESS;
+	}
+
+	return FAILED;
 }
 
 /* FIXME: this doesn't do anything right now */
 static int us_bus_reset( Scsi_Cmnd *srb )
 {
-	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+	// struct us_data *us = (struct us_data *)srb->host->hostdata[0];
 
+	printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" );
 	US_DEBUGP("Bus reset requested\n");
-	if (us->ip_wanted)
-		up(&(us->ip_waitq));
 	//  us->transport_reset(us);
 	return SUCCESS;
 }
@@ -1192,6 +1126,7 @@
 /* FIXME: This doesn't actually reset anything */
 static int us_host_reset( Scsi_Cmnd *srb )
 {
+	printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
 	return 0;
 }
 
@@ -1209,14 +1144,13 @@
 	struct us_data *us;
 	char *pos = buffer;
 	char *tmp_ptr;
-	unsigned long flags;
 
 	/* if someone is sending us data, just throw it away */
 	if (inout)
 		return length;
 
 	/* lock the data structures */
-	spin_lock_irqsave(&us_list_spinlock, flags);
+	down(&us_list_semaphore);
 
 	/* find our data from hostno */
 	us = us_list;
@@ -1228,7 +1162,7 @@
 
 	/* if we couldn't find it, we return an error */
 	if (!us) {
-		spin_unlock_irqrestore(&us_list_spinlock, flags);
+		up(&us_list_semaphore);
 		return -ESRCH;
 	}
 	
@@ -1274,11 +1208,42 @@
 		break;
 	}
 
+	SPRINTF(" Transport: ");
+	switch (us->subclass) {
+	case US_SC_RBC:
+		SPRINTF("Reduced Block Commands\n");
+		break;
+
+	case US_SC_8020:
+		SPRINTF("8020i\n");
+		break;
+
+	case US_SC_QIC:
+		SPRINTF("QIC-157\n");
+		break;
+    
+	case US_SC_8070:
+		SPRINTF("8070i\n");
+		break;
+
+	case US_SC_SCSI:
+		SPRINTF("Transparent SCSI\n");
+		break;
+    
+	case US_SC_UFI:
+		SPRINTF("Uniform Floppy Interface\n");
+		break;
+    
+	default:
+		SPRINTF("Unknown Transport\n");
+		break;
+	}
+
 	/* show the GUID of the device */
 	SPRINTF("      GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
 
 	/* release our lock on the data structures */
-	spin_unlock_irqrestore(&us_list_spinlock, flags);
+	up(&us_list_semaphore);
 
 	/*
 	 * Calculate start of next buffer, and return value.
@@ -1298,36 +1263,30 @@
  */
 
 static Scsi_Host_Template my_host_template = {
-	NULL,			    /* next */
-	NULL,			    /* module */
-	NULL,			    /* proc_dir */
-	usb_stor_proc_info,
-	NULL,			    /* name - points to unique */
-	us_detect,
-	us_release,
-	NULL,			    /* info */
-	NULL,			    /* ioctl */
-	us_command,
-	us_queuecommand,
-	NULL,			    /* eh_strategy */
-	us_abort,
-	us_bus_reset,
-	us_bus_reset,
-	us_host_reset,
-	NULL,			    /* abort */
-	NULL,			    /* reset */
-	NULL,			    /* slave_attach */
-	NULL,			    /* bios_param */
-	NULL,			    /* select_queue_depths */
-	1,			    /* can_queue */
-	-1,			    /* this_id */
-	SG_ALL, 		    /* sg_tablesize */
-	1,			    /* cmd_per_lun */
-	0,			    /* present */
-	FALSE,		            /* unchecked_isa_dma */
-	TRUE,  		            /* use_clustering */
-	TRUE,			    /* use_new_eh_code */
-	TRUE			    /* emulated */
+	name:           "usb-storage",
+	proc_info:	usb_stor_proc_info,
+	info:           us_info,
+
+	detect:		us_detect,
+	release:	us_release,
+	command:	us_command,
+	queuecommand:	us_queuecommand,
+
+	eh_abort_handler:	us_abort,
+	eh_device_reset_handler:us_bus_reset,
+	eh_bus_reset_handler:	us_bus_reset,
+	eh_host_reset_handler:	us_host_reset,
+
+	can_queue:	1,
+	this_id:	-1,
+
+	sg_tablesize:	   SG_ALL,
+	cmd_per_lun:	   1,
+	present:	   0,
+	unchecked_isa_dma: FALSE,
+	use_clustering:	   TRUE,
+	use_new_eh_code:   TRUE,
+	emulated:	   TRUE,
 };
 
 static unsigned char sense_notready[] = {
@@ -1362,10 +1321,11 @@
 	 */
 	daemonize();
 
-	sprintf(current->comm, "usbscsi%d", us->host_number);
+	sprintf(current->comm, "usb-storage-%d", us->host_number);
 
 	unlock_kernel();
 
+	/* signal that we've started the thread */
 	up(&(us->notify));
 
 	for(;;) {
@@ -1382,14 +1342,10 @@
 		/* release the queue lock as fast as possible */
 		up(&(us->queue_exclusion));
 
-		/* FIXME: we need to examine placment of break; and 
-		 * scsi_done() calls */
-
 		switch (action) {
 		case US_ACT_COMMAND:
 			/* bad device */
-			/* FIXME: we need to enable and test multiple LUNs */
-			if (us->srb->target || us->srb->lun) {
+			if (us->srb->target) {
 				US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n",
 					   us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
 				us->srb->result = DID_BAD_TARGET << 16;
@@ -1399,6 +1355,9 @@
 				break;
 			}
 
+			/* lock the device pointers */
+			down(&(us->dev_semaphore));
+
 			/* our device has gone - pretend not ready */
 			/* FIXME: we also need to handle INQUIRY here, 
 			 * probably */
@@ -1414,6 +1373,10 @@
 					us->srb->result = (DID_OK << 16) | 2;
 				}
 
+				/* unlock the device pointers */
+				up(&(us->dev_semaphore));
+
+				/* indicate that the command is done */
 				us->srb->scsi_done(us->srb);
 				us->srb = NULL;
 				break;
@@ -1434,6 +1397,11 @@
       
 			US_DEBUGP("scsi cmd done, result=0x%x\n", 
 				  us->srb->result);
+
+			/* unlock the device pointers */
+			up(&(us->dev_semaphore));
+
+			/* indicate that the command is done */
 			us->srb->scsi_done(us->srb);
 			us->srb = NULL;
 			break;
@@ -1453,11 +1421,15 @@
 		} /* end switch on action */
 
 		/* exit if we get a signal to exit */
-		if (action == US_ACT_EXIT)
+		if (action == US_ACT_EXIT) {
+			US_DEBUGP("-- US_ACT_EXIT command recieved\n");
 			break;
+		}
 	} /* for (;;) */
   
-	printk("usb_stor_control_thread exiting\n");
+	/* notify the exit routine that we're actually exiting now */
+	up(&(us->notify));
+
 	return 0;
 }	
 
@@ -1471,7 +1443,6 @@
 	struct us_data *ss = NULL;
 	GUID(guid);		     /* Global Unique Identifier */
 	int result;
-	unsigned long flags;
 
 	/* these are temporary copies -- we test on these, then put them
 	 * in the us-data structure 
@@ -1531,9 +1502,6 @@
 					 &ss->irq_handle);
 		if (result < 0)
 			return NULL;
-		
-		/* FIXME: what is this?? */
-		down(&(ss->ip_waitq));
 	}
 			
 	/*
@@ -1613,7 +1581,7 @@
 	}
 
 	/* lock access to the data structures */
-	spin_lock_irqsave(&us_list_spinlock, flags);
+	down(&us_list_semaphore);
 
 	/*
 	 * Now check if we have seen this GUID before
@@ -1655,7 +1623,7 @@
 		if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data), 
 						    GFP_KERNEL)) == NULL) {
 			printk(KERN_WARNING USB_STORAGE "Out of memory\n");
-			spin_unlock_irqrestore(&us_list_spinlock, flags);
+			up(&us_list_semaphore);
 			return NULL;
 		}
 		memset(ss, 0, sizeof(struct us_data));
@@ -1664,6 +1632,7 @@
 		init_MUTEX_LOCKED(&(ss->sleeper));
 		init_MUTEX_LOCKED(&(ss->notify));
 		init_MUTEX(&(ss->queue_exclusion));
+		init_MUTEX(&(ss->dev_semaphore));
 
 		/* copy over the subclass and protocol data */
 		ss->subclass = subclass;
@@ -1725,7 +1694,7 @@
 			break;
 
 		case US_SC_QIC:
-			US_DEBUGPX("QIC157\n");
+			US_DEBUGPX("QIC-157\n");
 			break;
 
 		case US_SC_8070:
@@ -1774,9 +1743,9 @@
 		/* Grab the next host number */
 		ss->host_number = my_host_number++;
 			
-		/* FIXME: this is bad.  We abuse this pointer so we
-		 * can pass the ss pointer to the host controler thread
-		 * in us_detect
+		/* We abuse this pointer so we can pass the ss pointer to 
+		 * the host controler thread in us_detect.  But how else are
+		 * we to do it?
 		 */
 		(struct us_data *)ss->htmplt.proc_dir = ss; 
 		
@@ -1795,7 +1764,7 @@
 		down(&(ss->notify));
 			
 		/* now register - our detect function will be called */
-		ss->htmplt.module = &__this_module;
+		ss->htmplt.module = THIS_MODULE;
 		scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt));
 		
 		/* put us in the list */
@@ -1804,7 +1773,7 @@
 	}
 
 	/* release the data structure lock */
-	spin_unlock_irqrestore(&us_list_spinlock, flags);
+	up(&us_list_semaphore);
 
 	printk(KERN_DEBUG 
 	       "WARNING: USB Mass Storage data integrity not assured\n");
@@ -1829,6 +1798,9 @@
 		return;
 	}
 
+	/* lock access to the device data structure */
+	down(&(ss->dev_semaphore));
+
 	/* release the IRQ, if we have one */
 	if (ss->irq_handle) {
 		US_DEBUGP("-- releasing irq handle\n");
@@ -1840,6 +1812,9 @@
 
 	/* mark the device as gone */
 	ss->pusb_dev = NULL;
+
+	/* lock access to the device data structure */
+	up(&(ss->dev_semaphore));
 }
 
 
@@ -1849,18 +1824,10 @@
 
 int __init usb_stor_init(void)
 {
-	/* 
-	 * Check to see if the host template is a different size from
-	 * what we're expected -- people have updated this in the past
-	 * and forgotten about this driver.
-	 */
-	if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) {
-		printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE bad\n");
-		printk(KERN_ERR 
-		       "usb-storage: expected %d bytes, got %d bytes\n", 
-		       SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ;
-		return -1 ;
-	}
+	/* initialize internal global data elements */
+	us_list = NULL;
+	init_MUTEX(&us_list_semaphore);
+	my_host_number = 0;
 
 	/* register the driver, return -1 if error */
 	if (usb_register(&storage_driver) < 0)
@@ -1873,36 +1840,38 @@
 
 void __exit usb_stor_exit(void)
 {
-	static struct us_data *ptr;
-	static struct us_data *next;
-	unsigned long flags;
+	struct us_data *next;
 	
-	/*
-	 * deregister the driver -- this eliminates races with probes and
-	 * disconnects 
+	US_DEBUGP("usb_stor_exit() called\n");
+
+	/* Deregister the driver
+	 * This eliminates races with probes and disconnects 
 	 */
+	US_DEBUGP("-- calling usb_deregister()\n");
 	usb_deregister(&storage_driver) ;
 	
 	/* lock access to the data structures */
-	spin_lock_irqsave(&us_list_spinlock, flags);
-	
-	/* unregister all the virtual hosts */
-	for (ptr = us_list; ptr != NULL; ptr = ptr->next)
-		scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt));
-	
-	/* kill the threads */
-	/* FIXME: we can do this by sending them a signal to die */
-
-	/* free up the data structures */
-	/* FIXME: we need to eliminate the host structure also */
-	while (ptr) {
-		next = ptr->next;
-		kfree(ptr);
-		ptr = next;
+	down(&us_list_semaphore);
+
+	/* While there are still virtual hosts, unregister them
+	 *
+	 * Note that the us_release() routine will destroy the local data
+	 * structure.  So we have to peel these off the top of the list
+	 * and keep updating the head pointer as we go.
+	 */
+	while (us_list) {
+		/* keep track of where the next one is */
+		next = us_list->next;
+
+		US_DEBUGP("-- calling scsi_unregister_module()\n");
+		scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt));
+
+		/* advance the list pointer */
+		us_list = next;
 	}
 	
 	/* unlock the data structures */
-	spin_unlock_irqrestore(&us_list_spinlock, flags);
+	up(&us_list_semaphore);
 }
 
 module_init(usb_stor_init) ;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usb-storage.h linux/drivers/usb/usb-storage.h
--- v2.3.99-pre3/linux/drivers/usb/usb-storage.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/usb/usb-storage.h	Wed Apr  5 17:01:25 2000
@@ -129,8 +129,8 @@
 }
 
 /* Flag definitions */
-#define US_FL_IP_STATUS	      0x00000001         /* status uses interrupt */
-#define US_FL_FIXED_COMMAND   0x00000002 /* expand commands to fixed size */
+#define US_FL_IP_STATUS	      0x00000001 /* status uses interrupt           */
+#define US_FL_FIXED_COMMAND   0x00000002 /* expand commands to fixed size   */
 #define US_FL_MODE_XLATE      0x00000004 /* translate _6 to _10 comands for
-					    Win/MacOS compatibility */
-
+					            Win/MacOS compatibility */
+#define US_FL_CBI_AS_CB       0x00000008 /* treat a CBI dev as a CB dev     */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- v2.3.99-pre3/linux/drivers/usb/usb-uhci.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/usb-uhci.c	Wed Apr  5 17:01:25 2000
@@ -12,7 +12,7 @@
  * (C) Copyright 1999 Johannes Erdfelt
  * (C) Copyright 1999 Randy Dunlap
  *
- * $Id: usb-uhci.c,v 1.222 2000/03/13 21:18:02 fliegl Exp $
+ * $Id: usb-uhci.c,v 1.228 2000/04/02 19:55:51 acher Exp $
  */
 
 #include <linux/config.h>
@@ -50,6 +50,8 @@
 /* This enables an extra UHCI slab for memory debugging */
 #define DEBUG_SLAB
 
+#define VERSTR "$Revision: 1.228 $ time " __TIME__ " " __DATE__
+
 #include <linux/usb.h>
 #include "usb-uhci.h"
 #include "usb-uhci-debug.h"
@@ -116,6 +118,26 @@
 	}
 }
 /*-------------------------------------------------------------------*/
+_static void uhci_switch_timer_int(uhci_t *s)
+{
+
+	if (!list_empty(&s->urb_unlinked)) {
+		s->td1ms->hw.td.status |= TD_CTRL_IOC;
+	}
+	else {
+		s->td1ms->hw.td.status &= ~TD_CTRL_IOC;
+	}
+
+	if (s->timeout_urbs) {
+		s->td32ms->hw.td.status |= TD_CTRL_IOC;
+	}
+	else {
+		s->td32ms->hw.td.status &= ~TD_CTRL_IOC;
+	}
+
+	wmb();
+}
+/*-------------------------------------------------------------------*/
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 _static void enable_desc_loop(uhci_t *s, urb_t *urb)
 {
@@ -162,6 +184,9 @@
 #endif
 	((urb_priv_t*)urb->hcpriv)->started=jiffies;
 	list_add (p, &s->urb_list);
+	if (urb->timeout)
+		s->timeout_urbs++;
+	uhci_switch_timer_int(s);
 }
 /*-------------------------------------------------------------------*/
 _static void queue_urb (uhci_t *s, urb_t *urb)
@@ -185,6 +210,9 @@
 #endif
 
 	list_del (&urb->urb_list);
+	if (urb->timeout && s->timeout_urbs)
+		s->timeout_urbs--;
+
 }
 /*-------------------------------------------------------------------*/
 _static int alloc_td (uhci_desc_t ** new, int flags)
@@ -439,6 +467,13 @@
 
 	clean_descs(s,1);
 
+	
+	if (s->td32ms) {
+	
+		unlink_td(s,s->td32ms,1);
+		delete_desc(s->td32ms);
+	}
+
 	for (n = 0; n < 8; n++) {
 		td = s->int_chain[n];
 		clean_td_chain (td);
@@ -531,8 +566,9 @@
 	if (ret)
 		goto init_skel_cleanup;
 	
-	fill_td (td, TD_CTRL_IOC, 0, 0); // generate 1ms interrupt
+	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
 	insert_td (s, qh, td, 0);
+	s->td1ms=td;
 
 	dbg("allocating qh: bulk_chain");
 	ret = alloc_qh (&qh);
@@ -597,6 +633,16 @@
 					((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus (s->int_chain[o]);
 	}
 
+	ret = alloc_td (&td, 0);
+
+	if (ret)
+		goto init_skel_cleanup;
+	
+	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt
+	s->td32ms=td;
+
+	insert_td_horizontal (s, s->int_chain[5], td);
+
 	mb();
 	//uhci_show_queue(s->control_chain);   
 	dbg("init_skel exit");
@@ -995,6 +1041,7 @@
 	if (urb->status == -EINPROGRESS) {
 		// URB probably still in work
 		dequeue_urb (s, urb);
+		uhci_switch_timer_int(s);
 		s->unlink_urb_done=1;
 		spin_unlock_irqrestore (&s->urb_list_lock, flags);		
 		
@@ -1125,9 +1172,11 @@
 
 	if (urb->status == -EINPROGRESS) {
 		((urb_priv_t*)urb->hcpriv)->started = ~0;
+
 		dequeue_urb (s, urb);
 		list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
-
+		uhci_switch_timer_int(s);
+			
 		s->unlink_urb_done = 1;
 		
 		urb->status = -ECONNABORTED;	// mark urb as "waiting to be killed"	
@@ -1495,7 +1544,7 @@
 		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(bulk_urb->transfer_flags & USB_QUEUE_BULK)))) {
 			spin_unlock_irqrestore (&s->urb_list_lock, flags);
 			usb_dec_dev_use (urb->dev);
-			err("ENXIO1 %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,bulk_urb);
+			err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,bulk_urb);
 			return -ENXIO;	// urb already queued
 		}
 	}
@@ -1599,6 +1648,7 @@
 #endif
 
 	}
+	s->timeout_check=jiffies;
 }
 
 /*-------------------------------------------------------------------
@@ -1922,7 +1972,7 @@
 			OK (len);
 		case (0x03):	/* string descriptors */
 			len = usb_root_hub_string (wValue & 0xff,
-				uhci->io_addr, "UHCI",
+			        uhci->io_addr, "UHCI",
 				data, wLength);
 			if (len > 0) {
 				OK (min (leni, len));
@@ -2481,15 +2531,15 @@
 			goto restart;
 		}
 	}
-	if ((s->frame_counter & 63) == 0)
+	if ((jiffies - s->timeout_check) > (HZ/30)) 
 		uhci_check_timeouts(s);
 
 	clean_descs(s,0);
 	uhci_cleanup_unlink(s, 0);
-	
+	uhci_switch_timer_int(s);
+							
 	spin_unlock (&s->urb_list_lock);
 	
-	s->frame_counter++;
 	outw (status, io_addr + USBSTS);
 
 	//dbg("uhci_interrupt: done");
@@ -2630,12 +2680,14 @@
 	spin_lock_init (&s->qh_lock);
 	spin_lock_init (&s->td_lock);
 	atomic_set(&s->avoid_bulk, 0);
+	s->timeout_urbs = 0;	
 	s->irq = -1;
 	s->io_addr = io_addr;
 	s->io_size = io_size;
 	s->next = devs;	//chain new uhci device into global list	
-	s->frame_counter = 0;
-	
+	s->timeout_check = 0;
+	s->uhci_pci=dev;
+
 	bus = usb_alloc_bus (&uhci_device_operations);
 	if (!bus) {
 		kfree (s);
@@ -2739,6 +2791,7 @@
 			info("Intel USB controller: setting latency timer to %d", UHCI_LATENCY_TIMER);
 			pci_write_config_byte(dev, PCI_LATENCY_TIMER, UHCI_LATENCY_TIMER);
 		}
+	
 		return alloc_uhci(dev, dev->irq, io_addr, io_size);
 	}
 	return -1;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usb-uhci.h linux/drivers/usb/usb-uhci.h
--- v2.3.99-pre3/linux/drivers/usb/usb-uhci.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/usb/usb-uhci.h	Wed Apr  5 17:01:25 2000
@@ -2,10 +2,9 @@
 #define __LINUX_UHCI_H
 
 /*
-   $Id: usb-uhci.h,v 1.50 2000/03/13 21:18:04 fliegl Exp $
+   $Id: usb-uhci.h,v 1.54 2000/04/02 19:55:53 acher Exp $
  */
 #define MODNAME "usb-uhci"
-#define VERSTR "$Revision: 1.50 $ time " __TIME__ " " __DATE__
 #define UHCI_LATENCY_TIMER 0
 
 static __inline__ void uhci_wait_ms(unsigned int ms)
@@ -202,6 +201,8 @@
 	uhci_desc_t *control_chain;
 	uhci_desc_t *bulk_chain;
 	uhci_desc_t *chain_end;
+	uhci_desc_t *td1ms;
+	uhci_desc_t *td32ms;
 	struct list_head free_desc;
 	spinlock_t qh_lock;
 	spinlock_t td_lock;
@@ -209,7 +210,9 @@
 	int loop_usage;            // URBs using bandwidth reclamation
 
 	struct list_head urb_unlinked;	// list of all unlinked  urbs
-	int frame_counter;
+	long timeout_check;
+	int timeout_urbs;
+	struct pci_dev *uhci_pci;
 } uhci_t, *puhci_t;
 
 
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.99-pre3/linux/drivers/usb/usb.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/usb/usb.c	Tue Apr 11 09:57:43 2000
@@ -24,7 +24,11 @@
 #include <linux/bitops.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>  /* for in_interrupt() */
-#define DEBUG
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
 #include <linux/usb.h>
 
 /*
@@ -1080,7 +1084,7 @@
 	int size;
 	struct usb_descriptor_header *header;
 
-	memcpy(config, buffer, USB_DT_INTERFACE_SIZE);
+	memcpy(config, buffer, USB_DT_CONFIG_SIZE);
 	le16_to_cpus(&config->wTotalLength);
 	size = config->wTotalLength;
 
@@ -1419,32 +1423,28 @@
 
 static void usb_set_maxpacket(struct usb_device *dev)
 {
-	int i, j, b;
-	struct usb_interface *ifp;
+	int i, b;
 
 	for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
-		ifp = dev->actconfig->interface + i;
-
-		for (j = 0; j < ifp->num_altsetting; j++) {
-			struct usb_interface_descriptor *as = ifp->altsetting + j;
-			struct usb_endpoint_descriptor *ep = as->endpoint;
-			int e;
-
-			for (e=0; e<as->bNumEndpoints; e++) {
-				b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-				if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-					USB_ENDPOINT_XFER_CONTROL) {	/* Control => bidirectional */
+		struct usb_interface *ifp = dev->actconfig->interface + i;
+		struct usb_interface_descriptor *as = ifp->altsetting + ifp->act_altsetting;
+		struct usb_endpoint_descriptor *ep = as->endpoint;
+		int e;
+
+		for (e=0; e<as->bNumEndpoints; e++) {
+			b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+			if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+				USB_ENDPOINT_XFER_CONTROL) {	/* Control => bidirectional */
+				dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
+				dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
+				}
+			else if (usb_endpoint_out(ep[e].bEndpointAddress)) {
+				if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b])
 					dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
+			}
+			else {
+				if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b])
 					dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
-					}
-				else if (usb_endpoint_out(ep[e].bEndpointAddress)) {
-					if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b])
-						dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
-				}
-				else {
-					if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b])
-						dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
-				}
 			}
 		}
 	}
@@ -1512,6 +1512,8 @@
 		return ret;
 
 	iface->act_altsetting = alternate;
+	dev->toggle[0] = 0;	/* 9.1.1.5 says to do this */
+	dev->toggle[1] = 0;
 	usb_set_maxpacket(dev);
 	return 0;
 }
@@ -1624,7 +1626,7 @@
 			err("config descriptor too short (expected %i, got %i)",tmp,result);
 			kfree(bigbuffer);
 			goto err;
-		}		
+		}
 		result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
 		kfree(bigbuffer);
 
@@ -1638,8 +1640,8 @@
 	}
 
 	return 0;
-	err:
-	dev->descriptor.bNumConfigurations=cfgno;
+err:
+	dev->descriptor.bNumConfigurations = cfgno;
 	return result;
 }
 
@@ -1674,7 +1676,7 @@
 			dev->have_langid = -1;
 			dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
 				/* always use the first langid listed */
-			info("USB device number %d default language ID 0x%x",
+			dbg("USB device number %d default language ID 0x%x",
 				dev->devnum, dev->string_langid);
 		}
 	}
@@ -1789,14 +1791,16 @@
 		return -1;
 	}
 
-	info("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
+	dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
 		dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
+#ifdef DEBUG
 	if (dev->descriptor.iManufacturer)
 		usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
 	if (dev->descriptor.iProduct)
 		usb_show_string(dev, "Product", dev->descriptor.iProduct);
 	if (dev->descriptor.iSerialNumber)
 		usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
+#endif
 
 	/* now that the basic setup is over, add a /proc/bus/usb entry */
         usbdevfs_add_device(dev);
@@ -1874,6 +1878,7 @@
 EXPORT_SYMBOL(usb_init_root_hub);
 EXPORT_SYMBOL(usb_root_hub_string);
 EXPORT_SYMBOL(usb_new_device);
+EXPORT_SYMBOL(usb_reset_device);
 EXPORT_SYMBOL(usb_connect);
 EXPORT_SYMBOL(usb_disconnect);
 EXPORT_SYMBOL(usb_release_bandwidth);
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usbdevice_fs.h linux/drivers/usb/usbdevice_fs.h
--- v2.3.99-pre3/linux/drivers/usb/usbdevice_fs.h	Thu Mar  2 14:36:23 2000
+++ linux/drivers/usb/usbdevice_fs.h	Wed Dec 31 16:00:00 1969
@@ -1,170 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	usbdevice_fs.h  --  USB device file system.
- *
- *	Copyright (C) 2000
- *          Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You should have received a copy of the GNU General Public License
- *	along with this program; if not, write to the Free Software
- *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  History:
- *   0.1  04.01.2000  Created
- *
- *  $Id: usbdevice_fs.h,v 1.1 2000/01/06 18:40:41 tom Exp $
- */
-
-/*****************************************************************************/
-
-#ifndef _LINUX_USBDEVICE_FS_H
-#define _LINUX_USBDEVICE_FS_H
-
-/* --------------------------------------------------------------------- */
-
-#define USBDEVICE_SUPER_MAGIC 0x9fa2
-
-/* usbdevfs ioctl codes */
-
-struct usbdevfs_ctrltransfer {
-	__u8 requesttype;
-	__u8 request;
-	__u16 value;
-	__u16 index;
-	__u16 length;
-	__u32 timeout;  /* in milliseconds */
- 	void *data;
-};
-
-struct usbdevfs_bulktransfer {
-	unsigned int ep;
-	unsigned int len;
-	unsigned int timeout; /* in milliseconds */
-	void *data;
-};
-
-struct usbdevfs_setinterface {
-	unsigned int interface;
-	unsigned int altsetting;
-};
-
-struct usbdevfs_disconnectsignal {
-	unsigned int signr;
-	void *context;
-};
-
-#define USBDEVFS_URB_DISABLE_SPD           1
-#define USBDEVFS_URB_ISO_ASAP              2
-
-#define USBDEVFS_URB_TYPE_ISO		   0
-#define USBDEVFS_URB_TYPE_INTERRUPT	   1
-#define USBDEVFS_URB_TYPE_CONTROL	   2
-#define USBDEVFS_URB_TYPE_BULK		   3
-
-struct usbdevfs_iso_packet_desc {
-	unsigned int length;
-	unsigned int actual_length;
-	unsigned int status;
-};
-
-struct usbdevfs_urb {
-	unsigned char type;
-	unsigned char endpoint;
-	int status;
-	unsigned int flags;
-	void *buffer;
-	int buffer_length;
-	int actual_length;
-	int start_frame;
-	int number_of_packets;
-	int error_count;
-	unsigned int signr;  /* signal to be sent on error, -1 if none should be sent */
-	void *usercontext;
-	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
-};
-
-#define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
-#define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
-#define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
-#define USBDEVFS_SETINTERFACE      _IOR('U', 4, struct usbdevfs_setinterface)
-#define USBDEVFS_SETCONFIGURATION  _IOR('U', 5, unsigned int)
-#define USBDEVFS_SUBMITURB         _IOR('U', 10, struct usbdevfs_urb)
-#define USBDEVFS_DISCARDURB        _IO('U', 11)
-#define USBDEVFS_REAPURB           _IOW('U', 12, void *)
-#define USBDEVFS_REAPURBNDELAY     _IOW('U', 13, void *)
-#define USBDEVFS_DISCSIGNAL        _IOR('U', 14, struct usbdevfs_disconnectsignal)
-#define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
-#define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
-
-/* --------------------------------------------------------------------- */
-
-#ifdef __KERNEL__
-
-#include <linux/list.h>
-#include <asm/semaphore.h>
-
-/*
- * inode number macros
- */
-#define ITYPE(x)   ((x)&(0xf<<28))
-#define ISPECIAL   (0<<28)
-#define IBUS       (1<<28)
-#define IDEVICE    (2<<28)
-#define IBUSNR(x)  (((x)>>8)&0xff)
-#define IDEVNR(x)  ((x)&0xff)
-
-#define IROOT      1
-
-/*
- * sigh. rwsemaphores do not (yet) work from modules
- */
-
-#define rw_semaphore semaphore
-#define init_rwsem init_MUTEX
-#define down_read down
-#define down_write down
-#define up_read up
-#define up_write up
-
-
-struct dev_state {
-	struct list_head list;      /* state list */
-	struct rw_semaphore devsem; /* protects modifications to dev (dev == NULL indicating disconnect) */ 
-	struct usb_device *dev;
-	struct file *file;
-	spinlock_t lock;            /* protects the async urb lists */
-	struct list_head async_pending;
-	struct list_head async_completed;
-	wait_queue_head_t wait;     /* wake up if a request completed */
-	unsigned int discsignr;
-	struct task_struct *disctask;
-	void *disccontext;
-	unsigned long ifclaimed;
-};
-
-/* internal methods & data */
-extern struct usb_driver usbdevfs_driver;
-extern struct file_operations usbdevfs_drivers_fops;
-extern struct file_operations usbdevfs_devices_fops;
-extern struct file_operations usbdevfs_device_file_operations;
-extern struct inode_operations usbdevfs_device_inode_operations;
-extern struct inode_operations usbdevfs_bus_inode_operations;
-extern struct file_operations usbdevfs_bus_file_operations;
-extern void usbdevfs_conn_disc_event(void);
-
-
-#endif /* __KERNEL__ */
-
-/* --------------------------------------------------------------------- */
-#endif /* _LINUX_USBDEVICE_FS_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.3.99-pre3/linux/drivers/video/Config.in	Fri Mar 10 16:40:45 2000
+++ linux/drivers/video/Config.in	Mon Mar 27 10:48:23 2000
@@ -33,6 +33,9 @@
    if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
       tristate '  Cyber2000 support' CONFIG_FB_CYBER2000
    fi
+   if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+      bool '  SA-1100 LCD support' CONFIG_FB_SA1100
+   fi
    if [ "$CONFIG_APOLLO" = "y" ]; then
       define_bool CONFIG_FB_APOLLO y
    fi
@@ -193,12 +196,12 @@
 	 fi
       fi
       if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
-	   "$CONFIG_FB_VIRTUAL" = "y" ]; then
+	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB2 y
 	 define_tristate CONFIG_FBCON_CFB4 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
-	      "$CONFIG_FB_VIRTUAL" = "m" ]; then
+	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB2 m
 	    define_tristate CONFIG_FBCON_CFB4 m
 	 fi
@@ -217,7 +220,7 @@
 	   "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o \
 	   "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
-	   "$CONFIG_FB_3DFX" = "y" ]; then
+	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -232,7 +235,8 @@
               "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
 	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
-	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then
+	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
+	      "$CONFIG_FB_SA1100" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
       fi
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.99-pre3/linux/drivers/video/Makefile	Mon Mar 27 08:08:28 2000
+++ linux/drivers/video/Makefile	Mon Apr 10 23:00:08 2000
@@ -46,7 +46,8 @@
 obj-$(CONFIG_FONT_PEARL_8x8)      += font_pearl_8x8.o
 obj-$(CONFIG_FONT_ACORN_8x8)      += font_acorn_8x8.o
 
-obj-$(CONFIG_FB)                  += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o fbmon.o 
+# Add fbmon.o back into obj-$(CONFIG_FB) in 2.5.x
+obj-$(CONFIG_FB)                  += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o
 obj-$(CONFIG_FB_COMPAT_XPMAC)     += macmodes.o
 
 obj-$(CONFIG_FB_ACORN)            += acornfb.o
@@ -111,6 +112,7 @@
 obj-$(CONFIG_FB_SUN3)             += sun3fb.o
 obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o
 obj-$(CONFIG_FB_HGA)              += hgafb.o  
+obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
 
 # Generic Low Level Drivers
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/video/amifb.c linux/drivers/video/amifb.c
--- v2.3.99-pre3/linux/drivers/video/amifb.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/video/amifb.c	Mon Apr 10 23:00:08 2000
@@ -2415,11 +2415,13 @@
 	par->crsr.spot_x = par->crsr.spot_y = 0;
 	par->crsr.height = par->crsr.width = 0;
 
+#if 0	/* fbmon not done.  uncomment for 2.5.x -brad */
 	if (!fbmon_valid_timings(pixclock[clk_shift], htotal, vtotal,
 				 &fb_info)) {
 		DPRINTK("mode doesn't fit for monitor\n");
 		return -EINVAL;
 	}
+#endif
 
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- v2.3.99-pre3/linux/drivers/video/aty128fb.c	Sun Mar 19 18:35:31 2000
+++ linux/drivers/video/aty128fb.c	Mon Mar 27 22:30:29 2000
@@ -1210,7 +1210,7 @@
     if (par->accel_flags & FB_ACCELF_TEXT)
         aty128_init_engine(par, info);
 
-#ifdef CONFIG_FB_COMPAT_XPMAC
+#if 0/*def CONFIG_FB_COMPAT_XPMAC*/
 #if 0 /* use this when macmodes gets updated */
     if (!console_fb_info || console_fb_info == &info->fb_info) {
 	disp_info.width = ((par->crtc.v_total >> 16) & 0x7ff)+1;
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.3.99-pre3/linux/drivers/video/atyfb.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/video/atyfb.c	Mon Apr 10 23:00:08 2000
@@ -2539,7 +2539,7 @@
     else
 	par->accel_flags = 0;
 
-#if 0
+#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */
     if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info))
 	return -EINVAL;
 #endif
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.3.99-pre3/linux/drivers/video/fbmem.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/video/fbmem.c	Mon Mar 27 10:48:23 2000
@@ -98,6 +98,8 @@
 extern int control_init(void);
 extern int control_setup(char*);
 extern int g364fb_init(void);
+extern void sa1100fb_init(void);
+extern void sa1100fb_setup(char*);
 extern int fm2fb_init(void);
 extern int fm2fb_setup(char*);
 extern int q40fb_init(void);
@@ -215,6 +217,9 @@
 #endif
 #ifdef CONFIG_FB_G364
 	{ "g364", g364fb_init, NULL },
+#endif
+#ifdef CONFIG_FB_SA1100
+	{ "sa1100", sa1100fb_init, sa1100fb_setup },
 #endif
 #ifdef CONFIG_FB_FM2
 	{ "fm2fb", fm2fb_init, fm2fb_setup },
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/video/sa1100fb.c linux/drivers/video/sa1100fb.c
--- v2.3.99-pre3/linux/drivers/video/sa1100fb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/sa1100fb.c	Mon Mar 27 10:48:23 2000
@@ -0,0 +1,1147 @@
+/*
+ * linux/drivers/video/sa1100fb.c -- StrongARM 1100 LCD Controller Frame Buffer Device
+ *
+ *  Copyright (C) 1999 Eric A. Thomas
+ *  
+ * 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.
+ *
+ */
+
+
+/*
+ *   Code Status:
+ *	4/1/99 - Driver appears to be working for Brutus 320x200x8bpp mode.  Other
+ *               resolutions are working, but only the 8bpp mode is supported.
+ *               Changes need to be made to the palette encode and decode routines
+ *               to support 4 and 16 bpp modes.  
+ *               Driver is not designed to be a module.  The FrameBuffer is statically
+ *               allocated since dynamic allocation of a 300k buffer cannot be guaranteed. 
+ *
+ *     6/17/99 - FrameBuffer memory is now allocated at run-time when the
+ *               driver is initialized.    
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/proc/pgtable.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+
+
+/*
+ *  Debug macros 
+ */
+// #define DEBUG 
+#ifdef DEBUG
+#  define DPRINTK(fmt, args...)	printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#  define DPRINTK(fmt, args...)
+#endif
+
+
+/* 
+ *  The MAX_x defines are used to specify the maximum ranges for 
+ *  parameters that affect the size of the frame buffer memory
+ *  region.  Since the frame buffer memory is not dynamically 
+ *  alocated, the maximum size that will be used is allocated.
+ */
+#if defined (CONFIG_SA1100_PENNY)
+
+#define MAX_BITS_PER_PIXEL   		8
+#define MAX_SCREEN_SIZE_H   		640
+#define MAX_SCREEN_SIZE_V    		480
+
+#elif defined(CONFIG_SA1100_BRUTUS)
+
+#define MAX_BITS_PER_PIXEL   		8
+#define MAX_SCREEN_SIZE_H   		320
+#define MAX_SCREEN_SIZE_V    		240
+
+#elif defined (CONFIG_SA1100_THINCLIENT)
+
+#define MAX_BITS_PER_PIXEL   		8 
+/*#define MAX_BITS_PER_PIXEL   		16*/
+
+#define MAX_SCREEN_SIZE_H   		640
+#define MAX_SCREEN_SIZE_V    		480
+
+#elif defined(CONFIG_SA1100_TIFON)
+
+#define MAX_BITS_PER_PIXEL   		4
+#define MAX_SCREEN_SIZE_H   		640
+#define MAX_SCREEN_SIZE_V    		200
+
+#define REVERSE_VIDEO_4BIT
+
+#elif defined(CONFIG_SA1100_LART)
+
+#define MAX_BITS_PER_PIXEL     		4
+#define MAX_SCREEN_SIZE_H      		320
+#define MAX_SCREEN_SIZE_V      		240
+
+#endif
+
+/* Default resolutions */
+#if defined(CONFIG_SA1100_PENNY) 
+#define DEFAULT_XRES	640
+#define DEFAULT_YRES	480
+#define DEFAULT_BPP	8
+#else
+#define DEFAULT_XRES	MAX_SCREEN_SIZE_H
+#define DEFAULT_YRES	MAX_SCREEN_SIZE_V
+#define DEFAULT_BPP	MAX_BITS_PER_PIXEL
+#endif
+
+/* Memory size macros for determining required FrameBuffer size */
+#define MAX_PALETTE_NUM_ENTRIES         256
+#define ADJUSTED_MAX_BITS_PER_PIXEL     (MAX_BITS_PER_PIXEL > 8 ? 16 : MAX_BITS_PER_PIXEL)
+#define MAX_PALETTE_MEM_SIZE            (MAX_PALETTE_NUM_ENTRIES * 2)
+#define MAX_PIXEL_MEM_SIZE              ((MAX_SCREEN_SIZE_H * MAX_SCREEN_SIZE_V * ADJUSTED_MAX_BITS_PER_PIXEL ) / 8)
+#define MAX_FRAMEBUFFER_MEM_SIZE   	(MAX_PIXEL_MEM_SIZE + MAX_PALETTE_MEM_SIZE + 32)
+#define ALLOCATED_FB_MEM_SIZE           (PAGE_ALIGN (MAX_FRAMEBUFFER_MEM_SIZE + PAGE_SIZE * 2))
+
+#define SA1100_PALETTE_MEM_SIZE(bpp)	(((bpp)==8?256:16)*2)
+#define SA1100_PALETTE_MODE_VAL(bpp)    (((bpp) & 0x018) << 9)
+
+/* Minimum X and Y resolutions */
+#define MIN_XRES	64
+#define MIN_YRES	64
+
+/* Possible controller_state modes */
+#define LCD_MODE_DISABLED		0    // Controller is disabled and Disable Done received
+#define LCD_MODE_DISABLE_BEFORE_ENABLE	1    // Re-enable after Disable Done IRQ is received
+#define LCD_MODE_ENABLED		2    // Controller is enabled
+
+#define SA1100_NAME	"SA1100"
+#define NR_MONTYPES	1
+
+static u_char *VideoMemRegion = NULL;
+static u_char *VideoMemRegion_phys = NULL;
+
+/* Local LCD controller parameters */
+/* These can be reduced by making better use of fb_var_screeninfo parameters.  */
+/* Several duplicates exist in the two structures. */
+struct sa1100fb_par {
+	u_char         	*p_screen_base;
+	u_char         	*v_screen_base;
+	u_short        	*p_palette_base;
+	u_short        	*v_palette_base;
+	unsigned long	 screen_size;
+	unsigned int	 palette_size;
+        unsigned int   	 xres;
+        unsigned int   	 yres;
+        unsigned int   	 xres_virtual;
+        unsigned int   	 yres_virtual;
+        unsigned int   	 bits_per_pixel;
+	  signed int	 montype;
+	unsigned int	 currcon;
+        unsigned int   	 visual;
+	unsigned int	 allow_modeset	: 1;
+	unsigned int   	 active_lcd     : 1;
+	volatile u_char	 controller_state;
+};
+
+/* Shadows for LCD controller registers */
+struct sa1100fb_lcd_reg {
+	Address	dbar1;
+	Word	lccr0;
+	Word	lccr1;
+	Word	lccr2;
+	Word	lccr3;
+};
+
+/* Fake monspecs to fill in fbinfo structure */
+static struct fb_monspecs monspecs __initdata = {
+	 30000, 70000, 50, 65, 0 	/* Generic */
+};
+
+static struct display global_disp;            /* Initial (default) Display Settings */
+static struct fb_info fb_info;
+static struct sa1100fb_par current_par;
+static struct fb_var_screeninfo __initdata init_var = {};
+static struct sa1100fb_lcd_reg lcd_shadow;
+
+
+static int  sa1100fb_open(struct fb_info *info, int user);
+static int  sa1100fb_release(struct fb_info *info, int user);
+static int  sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);
+static int  sa1100fb_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
+	       		  unsigned long arg, int con, struct fb_info *info);
+static int  sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
+static int  sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
+static int  sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
+static int  sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
+static int  sa1100fb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info);
+ 
+static int  sa1100fb_switch(int con, struct fb_info *info);
+static void sa1100fb_blank(int blank, struct fb_info *info);
+static int  sa1100fb_map_video_memory(void);
+static int  sa1100fb_activate_var(struct fb_var_screeninfo *var);
+static void sa1100fb_enable_lcd_controller(void);
+static void sa1100fb_disable_lcd_controller(void);
+
+static struct fb_ops sa1100fb_ops = {
+	sa1100fb_open,
+	sa1100fb_release,
+	sa1100fb_get_fix,		      
+	sa1100fb_get_var,		      
+	sa1100fb_set_var,		      
+	sa1100fb_get_cmap,		      
+	sa1100fb_set_cmap,		      
+	sa1100fb_pan_display,		      
+	sa1100fb_ioctl			      
+};
+
+
+
+/*
+ * sa1100fb_palette_write:
+ *    Write palette data to the LCD frame buffer's palette area
+ */
+static inline void
+sa1100fb_palette_write(u_int regno, u_short pal)
+{
+	current_par.v_palette_base[regno] = (regno ? pal : pal | 
+	                                     SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel));
+}
+
+
+static inline u_short
+sa1100fb_palette_encode(u_int regno, u_int red, u_int green, u_int blue, u_int trans)
+{
+	u_short pal;
+
+
+	if(current_par.bits_per_pixel == 4){
+		/*
+		 * RGB -> luminance is defined to be
+		 * Y =  0.299 * R + 0.587 * G + 0.114 * B
+		 */
+		pal = ((19595 * red + 38470 * green + 7471 * blue) >> 28) & 0x00f;
+#ifdef REVERSE_VIDEO_4BIT
+		pal = 15 - pal;
+#endif
+	}
+	else{
+		pal   = ((red   >>  4) & 0xf00);
+		pal  |= ((green >>  8) & 0x0f0);
+		pal  |= ((blue  >> 12) & 0x00f);
+	}
+
+	return pal;
+}
+	    
+static inline u_short
+sa1100fb_palette_read(u_int regno)
+{
+	return (current_par.v_palette_base[regno] & 0x0FFF);
+}
+
+
+static void
+sa1100fb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans)
+{
+	u_short pal;
+
+	pal = sa1100fb_palette_read(regno);
+
+	if( current_par.bits_per_pixel == 4){
+#ifdef REVERSE_VIDEO_4BIT
+		pal = 15 - pal;
+#endif
+		pal &= 0x000f;
+		pal |= pal << 4;
+		pal |= pal << 8;
+		*blue = *green = *red = pal;
+	}
+	else{
+		*blue   = (pal & 0x000f) << 12;
+		*green  = (pal & 0x00f0) << 8;
+		*red    = (pal & 0x0f00) << 4;
+	}
+        *trans  = 0;
+}
+
+static int
+sa1100fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info)
+{
+	if (regno >= current_par.palette_size)
+		return 1;
+	
+	sa1100fb_palette_decode(regno, red, green, blue, trans);
+
+	return 0;
+}
+
+
+static int
+sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info)
+{
+	u_short pal;
+
+	if (regno >= current_par.palette_size)
+		return 1;
+
+	pal = sa1100fb_palette_encode(regno, red, green, blue, trans);
+
+	sa1100fb_palette_write(regno, pal);
+
+	return 0;
+}
+
+static int
+sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+		 struct fb_info *info)
+{
+	int err = 0;
+
+	if (con == current_par.currcon)
+		err = fb_get_cmap(cmap, kspc, sa1100fb_getcolreg, info);
+	else if (fb_display[con].cmap.len)
+		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+	else
+		fb_copy_cmap(fb_default_cmap(current_par.palette_size),
+			     cmap, kspc ? 0 : 2);
+	return err;
+}
+
+static int
+sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+		 struct fb_info *info)
+{
+	int err = 0;
+
+	if (!fb_display[con].cmap.len)
+		err = fb_alloc_cmap(&fb_display[con].cmap,
+
+				    current_par.palette_size, 0);
+	if (!err) {
+		if (con == current_par.currcon)
+			err = fb_set_cmap(cmap, kspc, sa1100fb_setcolreg,
+					  info);
+		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+	}
+	return err;
+}
+
+static void inline
+sa1100fb_get_par(struct sa1100fb_par *par)
+{
+	*par = current_par;
+}
+
+
+/*
+ * sa1100fb_encode_var():
+ * 	Modify var structure using values in par
+ */
+static int 
+sa1100fb_encode_var(struct fb_var_screeninfo *var,
+                    struct sa1100fb_par *par)
+{
+        // Don't know if really want to var on entry.
+        // Look at set_var to see.  If so, may need to add extra params to par     
+//	memset(var, 0, sizeof(struct fb_var_screeninfo));
+ 
+	var->xres = par->xres;
+	var->yres = par->yres;
+	var->xres_virtual = par->xres_virtual;
+	var->yres_virtual = par->yres_virtual;
+
+	var->bits_per_pixel = par->bits_per_pixel;
+
+	switch(var->bits_per_pixel) {
+	case 2:
+	case 4:
+	case 8:
+		var->red.length	   = 4;
+		var->green         = var->red;
+		var->blue          = var->red;
+		var->transp.length = 0;
+		break;
+	case 12:          // This case should differ for Active/Passive mode  
+	case 16:
+        	var->red.length    = 
+        	var->blue.length   =
+        	var->green.length  = 5;
+        	var->transp.length = 0;
+        	var->red.offset    = 10;
+        	var->green.offset  = 5;
+        	var->blue.offset   = 0;
+        	var->transp.offset = 0;
+		break;
+	}
+	return 0;
+}
+ 
+/*
+ *  sa1100fb_decode_var():
+ *    Get the video params out of 'var'. If a value doesn't fit, round it up,
+ *    if it's too big, return -EINVAL.
+ *
+ *    Suggestion: Round up in the following order: bits_per_pixel, xres,
+ *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+ *    bitfields, horizontal timing, vertical timing.
+ */
+static int
+sa1100fb_decode_var(struct fb_var_screeninfo *var, 
+                    struct sa1100fb_par *par)
+{
+	u_long palette_mem_phys;
+	u_long palette_mem_size;
+
+	*par = current_par;
+
+	if ((par->xres = var->xres) < MIN_XRES)
+		par->xres = MIN_XRES; 
+	if ((par->yres = var->yres) < MIN_YRES)
+		par->yres = MIN_YRES;
+        if (par->xres > MAX_SCREEN_SIZE_H)
+        	par->xres = MAX_SCREEN_SIZE_H;
+        if (par->yres > MAX_SCREEN_SIZE_V)
+                par->yres = MAX_SCREEN_SIZE_V; 
+        par->xres_virtual = 
+		var->xres_virtual < par->xres ? par->xres : var->xres_virtual;
+        par->yres_virtual = 
+		var->yres_virtual < par->yres ? par->yres : var->yres_virtual;
+        par->bits_per_pixel = var->bits_per_pixel;
+
+	switch (par->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+        case 4:
+		par->visual = FB_VISUAL_PSEUDOCOLOR;
+		par->palette_size = 16; 
+                break;
+#endif
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		par->visual = FB_VISUAL_PSEUDOCOLOR;
+		par->palette_size = 256; 
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:  /* RGB 555 */
+		par->visual = FB_VISUAL_TRUECOLOR;
+		par->palette_size = -1; 
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+	palette_mem_size  = SA1100_PALETTE_MEM_SIZE(par->bits_per_pixel);
+	palette_mem_phys  = (u_long)VideoMemRegion_phys + PAGE_SIZE - 
+	                    palette_mem_size;
+	par->p_palette_base  = (u_short *)palette_mem_phys;
+        par->v_palette_base  = (u_short *)((u_long)VideoMemRegion + PAGE_SIZE - palette_mem_size);
+	par->p_screen_base   = (u_char *)((u_long)VideoMemRegion_phys + PAGE_SIZE); 
+	par->v_screen_base   = (u_char *)((u_long)VideoMemRegion      + PAGE_SIZE); 
+ 
+        DPRINTK("p_palette_base = 0x%08lx\n",(u_long)par->p_palette_base);
+        DPRINTK("v_palette_base = 0x%08lx\n",(u_long)par->v_palette_base);
+        DPRINTK("p_screen_base  = 0x%08lx\n",(u_long)par->p_screen_base);
+        DPRINTK("v_screen_base  = 0x%08lx\n",(u_long)par->v_screen_base);
+        DPRINTK("VideoMemRegion = 0x%08lx\n",(u_long)VideoMemRegion);
+        DPRINTK("VideoMemRegion_phys = 0x%08lx\n",(u_long)VideoMemRegion_phys);
+	return 0;
+}
+
+static int
+sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+ 	struct sa1100fb_par par;
+
+	if (con == -1) {
+                sa1100fb_get_par(&par);
+                sa1100fb_encode_var(var, &par);
+	} else
+		*var = fb_display[con].var;
+
+	return 0;
+}
+
+/*
+ * sa1100fb_set_var():
+ *	Set the user defined part of the display for the specified console
+ */
+static int
+sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct display *display;
+	int err, chgvar = 0;
+        struct sa1100fb_par par;
+
+	if (con >= 0)
+		display = &fb_display[con]; /* Display settings for console */
+	else
+		display = &global_disp;     /* Default display settings */
+
+
+	DPRINTK("xres = %d, yres = %d\n",var->xres, var->yres);
+        // Decode var contents into a par structure, adjusting any
+        // out of range values.  
+	if ((err = sa1100fb_decode_var(var, &par)))
+		return err;
+        // Store adjusted par values into var structure
+        sa1100fb_encode_var(var, &par);
+       
+        if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
+		return 0;
+        else if (((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) && 
+                 ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NXTOPEN))
+             	return -EINVAL;
+
+	if (con >= 0) {
+		if ((display->var.xres != var->xres) ||
+		    (display->var.yres != var->yres) ||
+		    (display->var.xres_virtual != var->xres_virtual) ||
+		    (display->var.yres_virtual != var->yres_virtual) ||
+		    (display->var.sync != var->sync)                 ||
+                    (display->var.bits_per_pixel != var->bits_per_pixel) ||
+		    (memcmp(&display->var.red, &var->red, sizeof(var->red))) ||
+		    (memcmp(&display->var.green, &var->green, sizeof(var->green))) ||
+		    (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))) 
+			chgvar = 1;
+	}
+
+	display->var = *var;
+	display->screen_base	= par.v_screen_base;
+	display->visual		= par.visual;
+	display->type		= FB_TYPE_PACKED_PIXELS;
+	display->type_aux	= 0;
+	display->ypanstep	= 0;
+	display->ywrapstep	= 0;
+	display->line_length	= 
+	display->next_line      = (var->xres * var->bits_per_pixel) / 8;
+
+	display->can_soft_blank	= 1;
+	display->inverse	= 0;
+
+	switch (display->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+        case 4:
+		display->dispsw = &fbcon_cfb4;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB8
+	case 8: 
+		display->dispsw = &fbcon_cfb8;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		display->dispsw = &fbcon_cfb16;
+		break;
+#endif
+	default:
+		display->dispsw = &fbcon_dummy;
+		break;
+	}
+
+        // If the console has changed and the console has defined
+        // a changevar function, call that function.
+	if (chgvar && info && info->changevar)
+		info->changevar(con);
+
+        // If the current console is selected, update the palette 
+	if (con == current_par.currcon) 
+        {
+		struct fb_cmap *cmap;
+
+		current_par = par;
+		if (display->cmap.len)
+			cmap = &display->cmap;
+		else
+			cmap = fb_default_cmap(current_par.palette_size);
+
+		fb_set_cmap(cmap, 1, sa1100fb_setcolreg, info);
+
+               	sa1100fb_activate_var(var);
+	}
+	return 0;
+}
+
+static int
+sa1100fb_updatevar(int con, struct fb_info *info)
+{
+	DPRINTK("entered\n");
+	return 0;
+}
+
+static int
+sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+	struct display *display;
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, SA1100_NAME);
+
+	if (con >= 0)
+	{
+		DPRINTK("Using console specific display for con=%d\n",con);
+		display = &fb_display[con];  /* Display settings for console */
+	}
+	else
+		display = &global_disp;      /* Default display settings */
+
+	fix->smem_start	 = current_par.p_screen_base;
+	fix->smem_len	 = current_par.screen_size;
+	fix->type	 = display->type;
+	fix->type_aux	 = display->type_aux;
+	fix->xpanstep	 = 0;
+	fix->ypanstep	 = display->ypanstep;
+	fix->ywrapstep	 = display->ywrapstep;
+	fix->visual	 = display->visual;
+	fix->line_length = display->line_length;
+	fix->accel	 = FB_ACCEL_NONE;
+
+	return 0;
+}
+
+
+static void
+__init sa1100fb_init_fbinfo(void)
+{
+	strcpy(fb_info.modename, SA1100_NAME);
+	strcpy(fb_info.fontname, "Acorn8x8");
+
+	fb_info.node		   = -1;
+	fb_info.flags		   = FBINFO_FLAG_DEFAULT;
+	fb_info.fbops		   = &sa1100fb_ops;
+        fb_info.monspecs           = monspecs;
+	fb_info.disp		   = &global_disp;
+	fb_info.changevar	   = NULL;
+	fb_info.switch_con	   = sa1100fb_switch;
+	fb_info.updatevar	   = sa1100fb_updatevar;
+	fb_info.blank		   = sa1100fb_blank;
+
+	/*
+	 * setup initial parameters
+	 */
+	memset(&init_var, 0, sizeof(init_var));
+
+	init_var.xres		   = DEFAULT_XRES;		
+	init_var.yres		   = DEFAULT_YRES;              
+	init_var.xres_virtual      = init_var.xres;
+	init_var.yres_virtual      = init_var.yres;
+	init_var.xoffset           = 0;
+	init_var.yoffset           = 0;
+	init_var.bits_per_pixel	   = DEFAULT_BPP;
+			
+	init_var.transp.length	   = 0;
+	init_var.nonstd		   = 0;
+	init_var.activate	   = FB_ACTIVATE_NOW;
+	init_var.height		   = -1;
+	init_var.width		   = -1;
+	init_var.vmode		   = FB_VMODE_NONINTERLACED;
+
+#if defined(CONFIG_SA1100_PENNY)
+	init_var.red.length	   = 4;				
+	init_var.green		   = init_var.red;
+	init_var.blue		   = init_var.red;
+	init_var.sync              = 0;
+#elif defined(CONFIG_SA1100_BRUTUS)
+	init_var.red.length	   = 4;				
+	init_var.green		   = init_var.red;
+	init_var.blue		   = init_var.red;
+	init_var.sync              = 0;
+#elif defined(CONFIG_SA1100_THINCLIENT)
+	init_var.red.length	   = 4;				
+	init_var.green		   = init_var.red;
+	init_var.blue		   = init_var.red;
+	init_var.sync              = 0;
+#elif defined(CONFIG_SA1100_TIFON)
+	init_var.red.length	   = 4;				
+	init_var.green		   = init_var.red;
+	init_var.blue		   = init_var.red;
+	init_var.grayscale         = 1;
+        init_var.pixclock	   = 150000;	
+        init_var.left_margin	   = 20;
+        init_var.right_margin	   = 255;
+        init_var.upper_margin	   = 20;
+        init_var.lower_margin	   = 0;
+        init_var.hsync_len	   = 2;
+        init_var.vsync_len	   = 1;
+	init_var.sync              = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
+        init_var.vmode		   = 0;
+#elif defined(CONFIG_SA1100_LART)
+	init_var.red.length	   = 4;				
+	init_var.green		   = init_var.red;
+	init_var.blue		   = init_var.red;
+	init_var.grayscale	   = 1;
+	init_var.pixclock	   = 150000;	
+	init_var.sync		   = 0;
+#endif
+
+	current_par.montype	   = -1;
+	current_par.currcon	  = -1;
+	current_par.allow_modeset =  1;
+	current_par.controller_state = LCD_MODE_DISABLED;
+}
+
+
+
+/*
+ * sa1100fb_map_video_memory():
+ *      Allocates the DRAM memory for the frame buffer.  This buffer is  
+ *	remapped into a non-cached, non-buffered, memory region to  
+ *      allow palette and pixel writes to occur without flushing the 
+ *      cache.  Once this area is remapped, all virtual memory
+ *      access to the video memory should occur at the new region.
+ */
+static int
+__init sa1100fb_map_video_memory(void)
+{
+	u_int  required_pages;
+	u_int  extra_pages;
+	u_int  order;
+        u_int  i;
+        char   *allocated_region;
+
+	if (VideoMemRegion != NULL)
+		return -EINVAL;
+
+	/* Find order required to allocate enough memory for framebuffer */
+	required_pages = ALLOCATED_FB_MEM_SIZE >> PAGE_SHIFT;
+        for (order = 0 ; required_pages >> order ; order++) {;}
+        extra_pages = (1 << order) - required_pages;
+
+        if ((allocated_region = 
+             (char *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)) == NULL)
+           return -ENOMEM;
+
+        VideoMemRegion = (u_char *)allocated_region + (extra_pages << PAGE_SHIFT); 
+        VideoMemRegion_phys = (u_char *)__virt_to_phys((u_long)VideoMemRegion);
+
+	/* Free all pages that we don't need but were given to us because */
+	/* __get_free_pages() works on powers of 2. */
+	for (;extra_pages;extra_pages--)
+          free_page((u_int)allocated_region + ((extra_pages-1) << PAGE_SHIFT));
+
+        /* Set reserved flag for fb memory to allow it to be remapped into */
+        /* user space by the common fbmem driver using remap_page_range(). */                             
+        for(i = MAP_NR(VideoMemRegion);                                  
+            i < MAP_NR(VideoMemRegion + ALLOCATED_FB_MEM_SIZE); i++) 
+          set_bit(PG_reserved, &mem_map[i].flags);
+
+	/* Remap the fb memory to a non-buffered, non-cached region */
+	VideoMemRegion = (u_char *)__ioremap((u_long)VideoMemRegion_phys,
+					     ALLOCATED_FB_MEM_SIZE,
+					     L_PTE_PRESENT  |
+					     L_PTE_YOUNG    |
+					     L_PTE_DIRTY    |
+					     L_PTE_WRITE);
+	return (VideoMemRegion == NULL ? -EINVAL : 0);
+}
+
+static const int frequency[16] = {
+	59000000,
+        73700000,
+        88500000,
+        103200000,
+        118000000,
+        132700000,
+        147500000,
+        162200000,
+        176900000,
+        191700000,
+        206400000, 
+	230000000,
+	245000000,
+	260000000,
+	275000000,
+	290000000
+};
+
+
+static int get_pcd(unsigned int pixclock)
+{
+	unsigned int pcd;
+	pcd = frequency[PPCR &0xf] / 1000;
+	pcd *= pixclock/1000;
+	return pcd / 10000000 * 12;
+	/* the last multiplication by 1.2 is to handle */
+	/* sync problems */
+}
+
+/*
+ * sa1100fb_activate_var():
+ *	Configures LCD Controller based on entries in var parameter.  Settings are      
+ *      only written to the controller if changes were made.  
+ */
+static int
+sa1100fb_activate_var(struct fb_var_screeninfo *var)
+{						       
+	u_long	flags;
+	int pcd = get_pcd(var->pixclock);
+
+	if (current_par.p_palette_base == NULL)
+		return -EINVAL;
+
+	/* Disable interrupts and save status */
+	save_flags_cli(flags);		// disable the interrupts and save flags
+
+	/* Reset the LCD Controller's DMA address if it has changed */
+  	lcd_shadow.dbar1 = (Address)current_par.p_palette_base;
+
+#if defined(CONFIG_SA1100_PENNY) 
+	DPRINTK("Configuring  SA1100 LCD\n");
+
+	DPRINTK("Configuring xres = %d, yres = %d\n",var->xres, var->yres);
+
+  	lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act + 
+  	                   LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
+  	                   LCCR0_DMADel(0); 
+  	lcd_shadow.lccr1 = LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth (65) +
+  	                   LCCR1_EndLnDel (43) + LCCR1_BegLnDel(43) ;
+  	lcd_shadow.lccr2 = LCCR2_DisHght (var->yres) + LCCR2_VrtSnchWdth (35) + 
+  	                   LCCR2_EndFrmDel (0) + LCCR2_BegFrmDel (0) ;
+  	lcd_shadow.lccr3 = LCCR3_PixClkDiv(16) +
+  	                   LCCR3_ACBsDiv (2) + LCCR3_ACBsCntOff +
+		           ((var->sync & FB_SYNC_HOR_HIGH_ACT) ?LCCR3_HorSnchH:LCCR3_HorSnchL) +
+		           ((var->sync & FB_SYNC_VERT_HIGH_ACT)?LCCR3_VrtSnchH:LCCR3_VrtSnchL);
+       
+#elif defined(CONFIG_SA1100_BRUTUS) 
+  	DPRINTK("Configuring  BRUTUS LCD\n");
+	lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas + 
+	                   LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
+	                   LCCR0_DMADel(0);
+  	lcd_shadow.lccr1 = LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) + 
+  	                   LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
+  	lcd_shadow.lccr2 = LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + 
+  	                   LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
+  	lcd_shadow.lccr3 = LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + LCCR3_HorSnchH +
+  	                    LCCR3_ACBsCntOff + LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44);
+#elif defined(CONFIG_SA1100_THINCLIENT) 
+	DPRINTK("Configuring ThinClient LCD\n");
+	DPRINTK("Configuring xres = %d, yres = %d\n",var->xres, var->yres);
+
+        lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + 
+                           LCCR0_Act;
+  	lcd_shadow.lccr1 = LCCR1_DisWdth(var->xres) +LCCR1_HorSnchWdth(10)+
+  	                   LCCR1_EndLnDel (81) + LCCR1_BegLnDel(81) ;
+  	lcd_shadow.lccr2 = LCCR2_DisHght (var->yres) +LCCR2_VrtSnchWdth(9) + 
+  	                   LCCR2_EndFrmDel (20) + LCCR2_BegFrmDel (20) ;
+  	lcd_shadow.lccr3 = LCCR3_PixClkDiv(6) +
+  	                   LCCR3_ACBsDiv (2) + LCCR3_ACBsCntOff +
+                           LCCR3_HorSnchL + LCCR3_VrtSnchL;
+              
+#elif defined(CONFIG_SA1100_TIFON) 
+	DPRINTK("Configuring TIFON LCD\n");
+
+	lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
+		           LCCR0_BigEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
+		           LCCR0_8PixMono + LCCR0_DMADel(0);
+	lcd_shadow.lccr1 = LCCR1_DisWdth( var->xres ) +
+		           LCCR1_HorSnchWdth( var->hsync_len) +
+		           LCCR1_BegLnDel( var->left_margin) +
+		           LCCR1_EndLnDel( var->right_margin);
+	lcd_shadow.lccr2 = LCCR2_DisHght( var->yres ) +
+		           LCCR2_VrtSnchWdth( var->vsync_len )+
+		           LCCR2_BegFrmDel( var->upper_margin ) +
+		           LCCR2_EndFrmDel( var->lower_margin );
+	lcd_shadow.lccr3 = LCCR3_PixClkDiv( pcd ) +
+		           LCCR3_ACBsDiv( 512 ) +
+		           LCCR3_ACBsCnt(0) +
+			   LCCR3_HorSnchH + LCCR3_VrtSnchH;
+	/*
+		           ((current_var.sync & FB_SYNC_HOR_HIGH_ACT) ?
+		           LCCR3_HorSnchH : LCCR3_HorSnchL) +
+		           ((current_var.sync & FB_SYNC_VERT_HIGH_ACT) ?
+		           LCCR3_VrtSnchH : LCCR3_VrtSnchL);
+	*/
+#elif defined(CONFIG_SA1100_LART) 
+  	DPRINTK("Configuring LART LCD\n");
+
+	lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
+		           LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
+		           LCCR0_DMADel(0);
+	lcd_shadow.lccr1 = LCCR1_DisWdth( var->xres ) +
+		           LCCR1_HorSnchWdth( 2 ) +
+		           LCCR1_BegLnDel( 4 ) +
+		           LCCR1_EndLnDel( 2 );
+	lcd_shadow.lccr2 = LCCR2_DisHght( var->yres ) +
+		           LCCR2_VrtSnchWdth( 1 )+
+		           LCCR2_BegFrmDel( 0 ) +
+		           LCCR2_EndFrmDel( 0 );
+	lcd_shadow.lccr3 = LCCR3_PixClkDiv( 34 ) +
+		           LCCR3_ACBsDiv( 512 ) +
+		           LCCR3_ACBsCntOff +
+		           LCCR3_HorSnchH +
+		           LCCR3_VrtSnchH;
+#endif
+
+       /* Restore status of interrupts */
+       restore_flags(flags);
+
+
+	if (( LCCR0 != lcd_shadow.lccr0 ) ||
+	    ( LCCR1 != lcd_shadow.lccr1 ) ||
+	    ( LCCR2 != lcd_shadow.lccr2 ) ||
+            ( LCCR3 != lcd_shadow.lccr3 ) ||
+	    ( DBAR1 != lcd_shadow.dbar1 ))
+	{
+		sa1100fb_enable_lcd_controller();
+	}
+
+  	return 0;
+}
+
+
+/*
+ *  sa1100fb_inter_handler():
+ *	Interrupt handler for LCD controller.  Processes disable done interrupt (LDD)
+ *      to reenable controller if controller was disabled to change register values.
+ */
+static void sa1100fb_inter_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+        if (LCSR & LCSR_LDD) {
+	        /* Disable Done Flag is set */
+		LCCR0 |= LCCR0_LDM;	      /* Mask LCD Disable Done Interrupt */
+		current_par.controller_state = LCD_MODE_DISABLED;
+		if (current_par.controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) {
+			sa1100fb_enable_lcd_controller();
+		}
+	}
+	LCSR = 0;		      /* Clear LCD Status Register */
+}
+
+
+/*
+ *  sa1100fb_disable_lcd_controller():
+ *    	Disables LCD controller by and enables LDD interrupt.  The controller_state
+ *      is not changed until the LDD interrupt is received to indicate the current
+ *      frame has completed.  Platform specific hardware disabling is also included.
+ */
+static void sa1100fb_disable_lcd_controller(void)
+{
+	DPRINTK("sa1100fb:  Disabling LCD controller\n");
+
+	/* Exit if already LCD disabled, or LDD IRQ unmasked */
+	if ((current_par.controller_state == LCD_MODE_DISABLED) ||
+	    (!(LCCR0 & LCCR0_LDM))) {
+		DPRINTK("sa1100fb: LCD already disabled\n");
+		return;
+	}
+
+#if defined(CONFIG_SA1100_PENNY)
+  	FpgaLcdCS1 = 0x000;	      /* LCD Backlight to 0%    */
+  	FpgaPortI  &= ~LCD_ON;        /* Turn off LCD Backlight */
+#elif defined(CONFIG_SA1100_TIFON)
+	GPCR = GPIO_GPIO(24);         /* turn off display */
+#endif
+	
+	LCSR = 0;		      /* Clear LCD Status Register */
+	LCCR0 &= ~(LCCR0_LDM);	      /* Enable LCD Disable Done Interrupt */
+	enable_irq(IRQ_LCD);	      /* Enable LCD IRQ */
+	LCCR0 &= ~(LCCR0_LEN);	      /* Disable LCD Controller */
+
+}
+
+/*
+ *  sa1100fb_enable_lcd_controller():
+ *    	Enables LCD controller.  If the controller is already enabled, it is first disabled.
+ *      This forces all changes to the LCD controller registers to be done when the 
+ *      controller is disabled.  Platform specific hardware enabling is also included.
+ */
+static void sa1100fb_enable_lcd_controller(void)
+{
+	u_long	flags;
+
+	save_flags_cli(flags);		
+
+        /* Disable controller before changing parameters */
+	if (current_par.controller_state == LCD_MODE_ENABLED) 	{
+		current_par.controller_state = LCD_MODE_DISABLE_BEFORE_ENABLE;
+		sa1100fb_disable_lcd_controller();
+	} else {
+		DPRINTK("sa1100fb: Enabling LCD controller\n");
+
+		/* Make sure the mode bits are present in the first palette entry */
+		current_par.v_palette_base[0] &= 0x0FFF; 	           
+		current_par.v_palette_base[0] |= SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel); 	 
+
+		/* disable the interrupts and save flags */
+		save_flags_cli(flags);		
+
+		DBAR1 = lcd_shadow.dbar1;
+		LCCR3 = lcd_shadow.lccr3;
+		LCCR2 = lcd_shadow.lccr2;
+		LCCR1 = lcd_shadow.lccr1;
+		LCCR0 = lcd_shadow.lccr0;
+
+#if defined(CONFIG_SA1100_PENNY)
+		FpgaLcdCS1 = 0x0FF;	       /* LCD Backlight to 100% */
+		FpgaPortI  |= LCD_ON;          /* Turn on LCD Backlight */
+#elif defined(CONFIG_SA1100_TIFON)
+		GPCR = GPIO_GPIO(24);          /* cycle on/off-switch */
+		udelay(150);
+		GPSR = GPIO_GPIO(24);          /* turn on display */
+		udelay(150);
+		GPSR = GPIO_GPIO(24);          /* turn on display */
+#endif
+		current_par.controller_state = LCD_MODE_ENABLED;
+
+       		/* Restore status of interrupts */
+       }
+       restore_flags(flags);
+}
+
+
+
+static int
+sa1100fb_open(struct fb_info *info, int user)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int
+sa1100fb_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+static int
+sa1100fb_pan_display(struct fb_var_screeninfo *var, int con,
+		    struct fb_info *info)
+{
+	DPRINTK("entered\n");
+	return -EINVAL;
+}
+
+
+/*
+ * sa1100fb_blank():
+ *	Blank the display by setting all palette values to zero.  Note, the 
+ * 	12 and 16 bpp modes don't really use the palette, so this will not
+ *      blank the display in all modes.  
+ */
+static void
+sa1100fb_blank(int blank, struct fb_info *info)
+{
+	int i;
+
+	if (blank) {
+		for (i = 0; i < current_par.palette_size; i++)
+			sa1100fb_palette_write(i, sa1100fb_palette_encode(i, 0, 0, 0, 0));
+		sa1100fb_disable_lcd_controller();
+	}
+	else {
+		sa1100fb_set_cmap(&fb_display[current_par.currcon].cmap, 1, 
+		                  current_par.currcon, info); 
+		sa1100fb_enable_lcd_controller();
+	}
+}
+
+
+/*
+ *  sa1100fb_switch():       
+ *	Change to the specified console.  Palette and video mode
+ *      are changed to the console's stored parameters. 
+ */
+static int
+sa1100fb_switch(int con, struct fb_info *info)
+{
+	struct fb_cmap *cmap;
+
+	if (current_par.currcon >= 0) {
+                // Get the colormap for the selected console 
+		cmap = &fb_display[current_par.currcon].cmap;
+
+		if (cmap->len)
+			fb_get_cmap(cmap, 1, sa1100fb_getcolreg, info);
+	}
+
+	current_par.currcon = con;
+	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+	sa1100fb_set_var(&fb_display[con].var, con, info);
+	return 0;
+}
+
+
+void __init sa1100fb_init(void)
+{
+        current_par.p_palette_base  = NULL;
+        current_par.v_palette_base  = NULL;
+        current_par.p_screen_base   = NULL;
+        current_par.v_screen_base   = NULL;
+        current_par.palette_size    = MAX_PALETTE_NUM_ENTRIES;
+        current_par.screen_size     = MAX_PIXEL_MEM_SIZE;
+
+#if defined(CONFIG_SA1100_PENNY)
+  	GPDR |= GPIO_GPDR_GFX;     /* GPIO Data Direction register for LCD data bits 8-11     */
+  	GAFR |= GPIO_GAFR_GFX;     /* GPIO Alternate Function register for LCD data bits 8-11 */
+#elif defined(CONFIG_SA1100_TIFON) 
+
+	GPDR = GPDR | GPIO_GPIO(24);  /* set GPIO24 to output */
+#endif
+
+	/* Initialize video memory */
+	if (sa1100fb_map_video_memory())
+	    return;
+
+	sa1100fb_init_fbinfo();
+	if (current_par.montype < 0 || current_par.montype > NR_MONTYPES)
+		current_par.montype = 1;
+
+	/* Request the interrupt in the init routine only because */ 
+	/* this driver will not be used as a module.              */ 
+	if (request_irq(IRQ_LCD, sa1100fb_inter_handler, SA_INTERRUPT, "SA1100 LCD", NULL)!= 0) {
+		DPRINTK("sa1100fb: failed in request_irq\n");
+	}
+	DPRINTK("sa1100fb: request_irq succeeded\n");
+	disable_irq(IRQ_LCD);
+
+	if (sa1100fb_set_var(&init_var, -1, &fb_info))
+		current_par.allow_modeset = 0;
+	sa1100fb_decode_var(&init_var, &current_par);
+
+	register_framebuffer(&fb_info);
+
+	/* This driver cannot be unloaded */
+	MOD_INC_USE_COUNT;
+}
+
+void __init sa1100fb_setup(char *options)
+{
+	if (!options || !*options)
+		return;
+
+	return; 
+}
+
+
+
+static int
+sa1100fb_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
+	      unsigned long arg, int con, struct fb_info *info)
+{
+	return -ENOIOCTLCMD;
+}
+
+
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c
--- v2.3.99-pre3/linux/drivers/video/tgafb.c	Wed Dec 15 10:43:17 1999
+++ linux/drivers/video/tgafb.c	Mon Apr 10 23:00:08 2000
@@ -362,7 +362,7 @@
 	var->yres_virtual != var->yres ||
 	var->nonstd || (1000000000/var->pixclock) > TGA_PLL_MAX_FREQ ||
 	(var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED
-#if 0	
+#if 0	/* fbmon not done.  uncomment for 2.5.x -brad */
 	|| !fbmon_valid_timings(var->pixclock, var->htotal, var->vtotal, info))
 #else
 	)
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/Config.in linux/fs/Config.in
--- v2.3.99-pre3/linux/fs/Config.in	Tue Mar 14 19:10:40 2000
+++ linux/fs/Config.in	Tue Apr 11 10:57:21 2000
@@ -10,9 +10,7 @@
 
 
 dep_tristate 'ADFS file system support' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_ADFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool '  ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW
-fi
+dep_mbool '  ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW $CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
 
 tristate 'Amiga FFS file system support' CONFIG_AFFS_FS
 
@@ -28,21 +26,15 @@
 dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
 
 tristate 'Compressed ROM file system support' CONFIG_CRAMFS
+tristate 'Simple RAM-based file system support' CONFIG_RAMFS
 
 tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS
-if [ "$CONFIG_ISO9660_FS" != "n" ]; then
-   bool '  Microsoft Joliet CDROM extensions' CONFIG_JOLIET
-else
-   # needed by nls/Config.in
-   define_bool CONFIG_JOLIET n
-fi
+dep_mbool '  Microsoft Joliet CDROM extensions' CONFIG_JOLIET $CONFIG_ISO9660_FS
 
 tristate 'Minix fs support' CONFIG_MINIX_FS
 
 tristate 'NTFS file system support (read only)' CONFIG_NTFS_FS
-if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool '  NTFS write support (DANGEROUS)' CONFIG_NTFS_RW
-fi
+dep_mbool '  NTFS write support (DANGEROUS)' CONFIG_NTFS_RW $CONFIG_NTFS_FS $CONFIG_EXPERIMENTAL
 
 tristate 'OS/2 HPFS file system support' CONFIG_HPFS_FS
 
@@ -58,44 +50,33 @@
 dep_bool '/dev/pts file system for Unix98 PTYs' CONFIG_DEVPTS_FS $CONFIG_UNIX98_PTYS
 
 dep_tristate 'QNX4 file system support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_QNX4FS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool '  QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW
-fi
+dep_mbool '  QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW $CONFIG_QNX4FS_FS $CONFIG_EXPERIMENTAL
 
 tristate 'ROM file system support' CONFIG_ROMFS_FS
 
 tristate 'Second extended fs support' CONFIG_EXT2_FS
 
 tristate 'System V and Coherent file system support (read only)' CONFIG_SYSV_FS
-if [ "$CONFIG_SYSV_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool '  SYSV file system write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE
-fi
+dep_mbool '  SYSV file system write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE $CONFIG_SYSV_FS $CONFIG_EXPERIMENTAL
 
 tristate 'UDF file system support (read only)' CONFIG_UDF_FS
-if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool '  UDF write support (DANGEROUS)' CONFIG_UDF_RW
-fi
+dep_mbool '  UDF write support (DANGEROUS)' CONFIG_UDF_RW $CONFIG_UDF_FS $CONFIG_EXPERIMENTAL
 
 tristate 'UFS file system support (read only)' CONFIG_UFS_FS
-if [ "$CONFIG_UFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool '  UFS file system write support (DANGEROUS)' CONFIG_UFS_FS_WRITE
-fi
+dep_mbool '  UFS file system write support (DANGEROUS)' CONFIG_UFS_FS_WRITE $CONFIG_UFS_FS $CONFIG_EXPERIMENTAL
 
 if [ "$CONFIG_NET" = "y" ]; then
 
-mainmenu_option next_comment
-comment 'Network File Systems'
-
-if [ "$CONFIG_INET" = "y" ]; then
-   tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS
+   mainmenu_option next_comment
+   comment 'Network File Systems'
 
-   tristate 'NFS file system support' CONFIG_NFS_FS
+   dep_tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS $CONFIG_INET
+   dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET
+   dep_mbool '  Provide NFSv3 client support (EXPERIMENTAL)' CONFIG_NFS_V3 $CONFIG_NFS_FS
    dep_bool '  Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
 
-   tristate 'NFS server support' CONFIG_NFSD
-   if [ "$CONFIG_NFSD" != "n" ]; then
-      bool '  Provide NFSv3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3
-   fi
+   dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
+   dep_mbool '  Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD
 
    if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
       define_tristate CONFIG_SUNRPC y
@@ -109,19 +90,24 @@
 	 define_tristate CONFIG_LOCKD n
       fi
    fi
-   if [ "$CONFIG_NFSD_V3" = "y" ]; then
+   if [ "$CONFIG_NFSD_V3" = "y" -o "$CONFIG_NFS_V3" = "y" ]; then
      define_bool CONFIG_LOCKD_V4 y
    fi
-   tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS
-fi
-if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
-   tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS
-   if [ "$CONFIG_NCP_FS" != "n" ]; then
+
+   dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET
+
+   if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
+      tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS
       source fs/ncpfs/Config.in
+   else
+      # for fs/nls/Config.in
+      define_bool CONFIG_NCPFS_NLS n
    fi
-fi
+   endmenu
 
-endmenu
+else
+   # for fs/nls/Config.in
+   define_bool CONFIG_NCPFS_NLS n
 fi
 
 mainmenu_option next_comment
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/Makefile linux/fs/Makefile
--- v2.3.99-pre3/linux/fs/Makefile	Wed Feb 16 17:03:52 2000
+++ linux/fs/Makefile	Tue Apr 11 10:57:00 2000
@@ -19,7 +19,7 @@
 ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
 		hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
 		nfsd nls devpts devfs adfs partitions qnx4 udf bfs cramfs \
-		openpromfs autofs4
+		openpromfs autofs4 ramfs
 
 SUB_DIRS := partitions
 
@@ -42,6 +42,14 @@
 else
   ifeq ($(CONFIG_CRAMFS),m)
   MOD_SUB_DIRS += cramfs
+  endif
+endif
+
+ifeq ($(CONFIG_RAMFS),y)
+SUB_DIRS += ramfs
+else
+  ifeq ($(CONFIG_RAMFS),m)
+  MOD_SUB_DIRS += ramfs
   endif
 endif
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/adfs/dir.c linux/fs/adfs/dir.c
--- v2.3.99-pre3/linux/fs/adfs/dir.c	Tue Mar 14 19:10:40 2000
+++ linux/fs/adfs/dir.c	Sun Apr  2 15:53:28 2000
@@ -30,7 +30,7 @@
 adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
-	struct super_block *sb = filp->f_dentry->d_sb;
+	struct super_block *sb = inode->i_sb;
 	struct adfs_dir_ops *ops = sb->u.adfs_sb.s_dir;
 	struct object_info obj;
 	struct adfs_dir dir;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/autofs/dirhash.c linux/fs/autofs/dirhash.c
--- v2.3.99-pre3/linux/fs/autofs/dirhash.c	Thu Jan 14 11:43:07 1999
+++ linux/fs/autofs/dirhash.c	Sun Apr  2 15:49:07 2000
@@ -78,8 +78,7 @@
 
 		/* Make sure entry is mounted and unused; note that dentry will
 		   point to the mounted-on-top root. */
-		if ( !S_ISDIR(dentry->d_inode->i_mode)
-		     || dentry->d_mounts == dentry ) {
+		if (!S_ISDIR(dentry->d_inode->i_mode)||!d_mountpoint(dentry)) {
 			DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
 			continue;
 		}
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.3.99-pre3/linux/fs/autofs/root.c	Fri Mar 10 16:40:46 2000
+++ linux/fs/autofs/root.c	Sun Apr  2 15:49:07 2000
@@ -63,7 +63,7 @@
 		/* fall through */
 	default:
 		while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
-			if ( !ent->dentry || ent->dentry->d_mounts != ent->dentry ) {
+			if ( !ent->dentry || d_mountpoint(ent->dentry) ) {
 				if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0)
 					return 0;
 				filp->f_pos = nr;
@@ -117,7 +117,7 @@
 
 	/* If this is a directory that isn't a mount point, bitch at the
 	   daemon and fix it in user space */
-	if ( S_ISDIR(dentry->d_inode->i_mode) && dentry->d_mounts == dentry ) {
+	if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
 		return !autofs_wait(sbi, &dentry->d_name);
 	}
 
@@ -157,7 +157,7 @@
 		return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
 		
 	/* Check for a non-mountpoint directory */
-	if ( S_ISDIR(dentry->d_inode->i_mode) && dentry->d_mounts == dentry ) {
+	if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
 		if (autofs_oz_mode(sbi))
 			return 1;
 		else
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/autofs/symlink.c linux/fs/autofs/symlink.c
--- v2.3.99-pre3/linux/fs/autofs/symlink.c	Tue Dec 14 01:27:24 1999
+++ linux/fs/autofs/symlink.c	Fri Apr  7 13:38:00 2000
@@ -18,10 +18,10 @@
 	return vfs_readlink(dentry, buffer, buflen, s);
 }
 
-static struct dentry *autofs_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags)
+static int autofs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data;
-	return vfs_follow_link(dentry, base, flags, s);
+	return vfs_follow_link(nd, s);
 }
 
 struct inode_operations autofs_symlink_inode_operations = {
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/autofs4/expire.c linux/fs/autofs4/expire.c
--- v2.3.99-pre3/linux/fs/autofs4/expire.c	Fri Jan 28 15:09:08 2000
+++ linux/fs/autofs4/expire.c	Tue Apr  4 14:51:21 2000
@@ -47,8 +47,7 @@
 	}
 
 	/* Mountpoints don't count */
-	if (root->d_mounts != root ||
-	    root->d_covers != root) {
+	if (d_mountpoint(root)) {
 		DPRINTK(("is_tree_busy: mountpoint\n"));
 		count--;
 	}
@@ -77,8 +76,7 @@
 		count += (dentry->d_count - 1);
 
 		/* Mountpoints don't count */
-		if (dentry->d_mounts != dentry ||
-		    dentry->d_covers != dentry) {
+		if (d_mountpoint(dentry)) {
 			DPRINTK(("is_tree_busy: mountpoint\n"));
 			adj++;
 		}
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/autofs4/root.c linux/fs/autofs4/root.c
--- v2.3.99-pre3/linux/fs/autofs4/root.c	Fri Mar 10 16:40:46 2000
+++ linux/fs/autofs4/root.c	Sun Apr  2 15:49:07 2000
@@ -181,7 +181,7 @@
 	/* If this is an unused directory that isn't a mount point,
 	   bitch at the daemon and fix it in user space */
 	if (S_ISDIR(dentry->d_inode->i_mode) &&
-	    dentry->d_mounts == dentry && 
+	    !d_mountpoint(dentry) && 
 	    list_empty(&dentry->d_subdirs)) {
 		DPRINTK(("try_to_fill_entry: mounting existing dir\n"));
 		return autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT) == 0;
@@ -226,7 +226,7 @@
 
 	/* Check for a non-mountpoint directory with no contents */
 	if (S_ISDIR(dentry->d_inode->i_mode) &&
-	    dentry->d_mounts == dentry && 
+	    !d_mountpoint(dentry) && 
 	    list_empty(&dentry->d_subdirs)) {
 		DPRINTK(("autofs_root_revalidate: dentry=%p %.*s, emptydir\n",
 			 dentry, dentry->d_name.len, dentry->d_name.name));
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/autofs4/symlink.c linux/fs/autofs4/symlink.c
--- v2.3.99-pre3/linux/fs/autofs4/symlink.c	Fri Jan 28 15:09:08 2000
+++ linux/fs/autofs4/symlink.c	Fri Apr  7 13:38:00 2000
@@ -19,13 +19,11 @@
 	return vfs_readlink(dentry, buffer, buflen, ino->u.symlink);
 }
 
-static struct dentry * autofs4_follow_link(struct dentry *dentry,
-					  struct dentry *base,
-					  unsigned int flags)
+static int autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
 
-	return vfs_follow_link(dentry, base, flags, ino->u.symlink);
+	return vfs_follow_link(nd, ino->u.symlink);
 }
 
 struct inode_operations autofs4_symlink_inode_operations = {
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/bad_inode.c linux/fs/bad_inode.c
--- v2.3.99-pre3/linux/fs/bad_inode.c	Sat Feb 26 22:31:51 2000
+++ linux/fs/bad_inode.c	Fri Apr  7 13:38:00 2000
@@ -15,10 +15,11 @@
  * so that a bad root inode can at least be unmounted. To do this
  * we must dput() the base and return the dentry with a dget().
  */
-static struct dentry * bad_follow_link(struct dentry *dent, struct dentry *base, unsigned int follow)
+static int bad_follow_link(struct dentry *dent, struct nameidata *nd)
 {
-	dput(base);
-	return dget(dent);
+	dput(nd->dentry);
+	nd->dentry = dget(dent);
+	return 0;
 }
 
 static int return_EIO(void)
@@ -64,7 +65,7 @@
 };
 
 
-/* 
+/*
  * When a filesystem is unable to read an inode due to an I/O error in
  * its read_inode() function, it can call make_bad_inode() to return a
  * set of stubs which will return EIO errors as required. 
@@ -72,6 +73,16 @@
  * We only need to do limited initialisation: all other fields are
  * preinitialised to zero automatically.
  */
+ 
+/**
+ *	make_bad_inode - mark an inode bad due to an I/O error
+ *	@inode: Inode to mark bad
+ *
+ *	When an inode cannot be read due to a media or remote network
+ *	failure this function makes the inode 'bad' and causes I/O operations
+ *	on it to fail from this point on
+ */
+ 
 void make_bad_inode(struct inode * inode) 
 {
 	inode->i_mode = S_IFREG;
@@ -85,6 +96,14 @@
  * &bad_inode_ops to cover the case of invalidated inodes as well as
  * those created by make_bad_inode() above.
  */
+ 
+/**
+ *	is_bad_inode - is an inode errored
+ *	@inode: inode to test
+ *
+ *	Returns true if the inode in question has been marked as bad
+ */
+ 
 int is_bad_inode(struct inode * inode) 
 {
 	return (inode->i_op == &bad_inode_ops);	
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/dcache.c linux/fs/dcache.c
--- v2.3.99-pre3/linux/fs/dcache.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/dcache.c	Sun Apr  2 15:54:44 2000
@@ -30,11 +30,6 @@
 /* Right now the dcache depends on the kernel lock */
 #define check_lock()	if (!kernel_locked()) BUG()
 
-/* For managing the dcache */
-extern unsigned long num_physpages, page_cache_size;
-extern int inodes_stat[];
-#define nr_inodes (inodes_stat[0])
-
 kmem_cache_t *dentry_cache; 
 
 /*
@@ -87,8 +82,8 @@
 	}
 }
 
-/*
- * dput()
+/* 
+ * dput
  *
  * This is complicated by the fact that we do not want to put
  * dentries that are no longer on any hash chain on the unused
@@ -103,6 +98,17 @@
  * on the compiler to always get this right (gcc generally doesn't).
  * Real recursion would eat up our stack space.
  */
+
+/*
+ * dput - release a dentry
+ * @dentry: dentry to release 
+ *
+ * Release a dentry. This will drop the usage count and if appropriate
+ * call the dentry unlink method as well as removing it from the queues and
+ * releasing its resources. If the parent dentries were scheduled for release
+ * they too may now get deleted.
+ */
+
 void dput(struct dentry *dentry)
 {
 	int count;
@@ -166,11 +172,16 @@
 	BUG();
 }
 
-/*
+/**
+ * d_invalidate - invalidate a dentry
+ * @dentry: dentry to invalidate
+ *
  * Try to invalidate the dentry if it turns out to be
  * possible. If there are other dentries that can be
- * reached through this one we can't delete it.
+ * reached through this one we can't delete it and we
+ * return -EBUSY. On success we return 0.
  */
+ 
 int d_invalidate(struct dentry * dentry)
 {
 	check_lock();
@@ -225,12 +236,19 @@
 		dput(parent);
 }
 
-/*
+/**
+ * prune_dcache - shrink the dcache
+ * @count: number of entries to try and free
+ *
  * Shrink the dcache. This is done when we need
  * more memory, or simply when we need to unmount
  * something (at which point we need to unuse
  * all dentries).
+ *
+ * This function may fail to free any resources if
+ * all the dentries are in use.
  */
+ 
 void prune_dcache(int count)
 {
 	check_lock();
@@ -264,6 +282,16 @@
  * each dput(), but since the target dentries are all at
  * the end, it's really just a single traversal.
  */
+
+/**
+ * shrink_dcache_sb - shrink dcache for a superblock
+ * @sb: superblock
+ *
+ * Shrink the dcache for the specified super block. This
+ * is used to free the dcache before unmounting a file
+ * system
+ */
+
 void shrink_dcache_sb(struct super_block * sb)
 {
 	struct list_head *tmp, *next;
@@ -307,11 +335,17 @@
 	}
 }
 
-/*
+/**
+ * is_root_busy - check if a root dentry could be freed
+ * @root: Dentry to work down from
+ *
  * Check whether a root dentry would be in use if all of its
  * child dentries were freed. This allows a non-destructive
  * test for unmounting a device.
+ *
+ * Return non zero if the root is still busy.
  */
+ 
 int is_root_busy(struct dentry *root)
 {
 	struct dentry *this_parent = root;
@@ -353,12 +387,21 @@
  * We descend to the next level whenever the d_subdirs
  * list is non-empty and continue searching.
  */
+ 
+/**
+ * have_submounts - check for mounts over a dentry
+ * @parent: dentry to check.
+ *
+ * Return true if the parent or its subdirectories contain
+ * a mount point
+ */
+ 
 int have_submounts(struct dentry *parent)
 {
 	struct dentry *this_parent = parent;
 	struct list_head *next;
 
-	if (parent->d_mounts != parent)
+	if (d_mountpoint(parent))
 		return 1;
 repeat:
 	next = this_parent->d_subdirs.next;
@@ -368,7 +411,7 @@
 		struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
 		next = tmp->next;
 		/* Have we found a mount point ? */
-		if (dentry->d_mounts != dentry)
+		if (d_mountpoint(dentry))
 			return 1;
 		if (!list_empty(&dentry->d_subdirs)) {
 			this_parent = dentry;
@@ -440,9 +483,13 @@
 	return found;
 }
 
-/*
+/**
+ * shrink_dcache_parent - prune dcache
+ * @parent: parent of entries to prune
+ *
  * Prune the dcache to remove unused children of the parent dentry.
  */
+ 
 void shrink_dcache_parent(struct dentry * parent)
 {
 	int found;
@@ -482,6 +529,16 @@
 
 #define NAME_ALLOC_LEN(len)	((len+16) & ~15)
 
+/**
+ * d_alloc	-	allocate a dcache entry
+ * @parent: parent of entry to allocate
+ * @name: qstr of the name
+ *
+ * Allocates a dentry. It returns NULL if there is insufficient memory
+ * available. On a success the dentry is returned. The name passed in is
+ * copied and the copy passed in may be reused after this call.
+ */
+ 
 struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
 {
 	char * str;
@@ -530,7 +587,11 @@
 	return dentry;
 }
 
-/*
+/**
+ * d_instantiate - fill in inode information for a dentry
+ * @entry: dentry to complete
+ * @inode: inode to attacheto this dentry
+ *
  * Fill in inode information in the entry.
  *
  * This turns negative dentries into productive full members
@@ -540,6 +601,7 @@
  * (or otherwise set) by the caller to indicate that it is now
  * in use by the dcache..
  */
+ 
 void d_instantiate(struct dentry *entry, struct inode * inode)
 {
 	if (inode)
@@ -547,6 +609,15 @@
 	entry->d_inode = inode;
 }
 
+/**
+ * d_alloc_root - allocate root dentry
+ * @root_inode: inode to allocate the root for
+ *
+ * Allocate a root ('/') dentry for the inode given. The inode is
+ * instantiated and returned. NULL is returned if there is insufficient
+ * memory or the inode passed is NULL.
+ */
+ 
 struct dentry * d_alloc_root(struct inode * root_inode)
 {
 	struct dentry *res = NULL;
@@ -569,6 +640,17 @@
 	return dentry_hashtable + (hash & D_HASHMASK);
 }
 
+/**
+ * d_lookup - search for a dentry
+ * @parent: parent dentry
+ * @name: qstr of name we wish to find
+ *
+ * Searches the children of the parent dentry for the name in question. If
+ * the dentry is found its reference count is incremented and the dentry
+ * is returned. The caller must use d_put to free the entry when it has
+ * finished using it. NULL is returned on failure.
+ */
+ 
 struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
 {
 	unsigned int len = name->len;
@@ -602,16 +684,23 @@
 	return NULL;
 }
 
-/*
- * An insecure source has sent us a dentry, here we verify it.
+/**
+ * d_validate - verify dentry provided from insecure source
+ * @dentry: The dentry alleged to be valid
+ * @dparent: The parent dentry
+ * @hash: Hash of the dentry
+ * @len: Length of the name
  *
+ * An insecure source has sent us a dentry, here we verify it.
  * This is used by ncpfs in its readdir implementation.
+ * Zero is returned in the dentry is invalid.
  *
- * NOTE! Do _not_ dereference the pointers before we have
+ * NOTE: This function does _not_ dereference the pointers before we have
  * validated them. We can test the pointer values, but we
  * must not actually use them until we have found a valid
  * copy of the pointer in kernel space..
  */
+ 
 int d_validate(struct dentry *dentry, struct dentry *dparent,
 	       unsigned int hash, unsigned int len)
 {
@@ -659,12 +748,19 @@
  * it from the hash queues and waiting for
  * it to be deleted later when it has no users
  */
+ 
+/**
+ * d_delete - delete a dentry
+ * @dentry: The dentry to delete
+ *
+ * Turn the dentry into a negative dentry if possible, otherwise
+ * remove it from the hash queues so it can be deleted later
+ */
+ 
 void d_delete(struct dentry * dentry)
 {
 	check_lock();
 
-	check_lock();
-
 	/*
 	 * Are we the only user?
 	 */
@@ -680,6 +776,13 @@
 	d_drop(dentry);
 }
 
+/**
+ * d_rehash	- add an entry back to the hash
+ * @entry: dentry to add to the hash
+ *
+ * Adds a dentry to the hash according to its name
+ */
+ 
 void d_rehash(struct dentry * entry)
 {
 	struct dentry * parent = entry->d_parent;
@@ -733,6 +836,16 @@
  * the fact that any list-entry can be a head of the list.
  * Think about it.
  */
+ 
+/**
+ * d_move - move a dentry
+ * @dentry: entry to move
+ * @target: new dentry
+ *
+ * Update the dcache to reflect the move of a file name. Negative
+ * dcache entries should not be moved in this way.
+ */
+  
 void d_move(struct dentry * dentry, struct dentry * target)
 {
 	check_lock();
@@ -762,14 +875,24 @@
 	list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
 }
 
-/*
+/**
+ * d_path - return the path of a dentry
+ * @dentry: dentry to report
+ * @buffer: buffer to return value in
+ * @buflen: buffer length
+ *
+ * Convert a dentry into an ascii path name. If the entry has been deleted
+ * the string ' (deleted)' is appended. Note that this is ambiguous. Returns
+ * the buffer.
+ *
  * "buflen" should be PAGE_SIZE or more.
  */
-char * d_path(struct dentry *dentry, char *buffer, int buflen)
+char * __d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+		struct dentry *root, struct vfsmount *rootmnt,
+		char *buffer, int buflen)
 {
 	char * end = buffer+buflen;
 	char * retval;
-	struct dentry * root = current->fs->root;
 
 	*--end = '\0';
 	buflen--;
@@ -839,7 +962,7 @@
 			char * cwd;
 
 			lock_kernel();
-			cwd = d_path(pwd, page, PAGE_SIZE);
+			cwd = d_path(pwd, current->fs->pwdmnt, page, PAGE_SIZE);
 			unlock_kernel();
 
 			error = -ERANGE;
@@ -860,6 +983,16 @@
  *
  * Trivially implemented using the dcache structure
  */
+
+/**
+ * is_subdir - is new dentry a subdirectory of old_dentry
+ * @new_dentry: new dentry
+ * @old_dentry: old dentry
+ *
+ * Returns 1 if new_dentry is a subdirectory of the parent (at any depth).
+ * Returns 0 otherwise.
+ */
+  
 int is_subdir(struct dentry * new_dentry, struct dentry * old_dentry)
 {
 	int result;
@@ -879,14 +1012,20 @@
 	return result;
 }
 
-/*
+/**
+ * find_inode_number - check for dentry with name
+ * @dir: directory to check
+ * @name: Name to find.
+ *
  * Check whether a dentry already exists for the given name,
- * and return the inode number if it has an inode.
+ * and return the inode number if it has an inode. Otherwise
+ * 0 is returned.
  *
  * This routine is used to post-process directory listings for
  * filesystems using synthetic inode numbers, and is necessary
  * to keep getcwd() working.
  */
+ 
 ino_t find_inode_number(struct dentry *dir, struct qstr *name)
 {
 	struct dentry * dentry;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/devfs/base.c linux/fs/devfs/base.c
--- v2.3.99-pre3/linux/fs/devfs/base.c	Fri Mar 10 16:40:47 2000
+++ linux/fs/devfs/base.c	Fri Apr  7 13:38:00 2000
@@ -3091,16 +3091,14 @@
 	return vfs_readlink(dentry, buffer, buflen, name);
 }   /*  End Function devfs_readlink  */
 
-static struct dentry *devfs_follow_link (struct dentry *dentry,
-					 struct dentry *base,
-					 unsigned int follow)
+static int devfs_follow_link (struct dentry *dentry, struct nameidata *nd)
 {
 	struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode);
 	char *name = ERR_PTR(-ENOENT);
 
 	if (di && di->de->registered)
 		name = di->de->u.symlink.linkname;
-	return vfs_follow_link(dentry, base, follow, name);
+	return vfs_follow_link(nd, name);
 }   /*  End Function devfs_follow_link  */
 
 static struct inode_operations devfs_iops =
@@ -3393,12 +3391,11 @@
 void __init mount_devfs_fs (void)
 {
     int err;
-    extern int do_mount (struct block_device *bdev, const char *dev_name,
-			 const char *dir_name, const char * type, int flags,
-			 void * data);
+    extern long do_sys_mount (char *dev_name, char *dir_name,
+				char * type, int flags, void * data);
 
     if ( (boot_options & OPTION_NOMOUNT) ) return;
-    err = do_mount (NULL, "none", "/dev", "devfs", 0, "");
+    err = do_sys_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);
 }   /*  End Function mount_devfs_fs  */
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/dquot.c linux/fs/dquot.c
--- v2.3.99-pre3/linux/fs/dquot.c	Sun Mar 19 18:35:31 2000
+++ linux/fs/dquot.c	Mon Apr  3 14:56:26 2000
@@ -716,15 +716,16 @@
 	}
 	inode->i_flags &= ~S_QUOTA;
 put_it:
-	if (dquot != NODQUOT)
+	if (dquot != NODQUOT) {
 		if (dqput_blocks(dquot)) {
 			if (dquot->dq_count != 1)
 				printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", dquot->dq_count);
 			list_add(&dquot->dq_free, tofree_head);	/* As dquot must have currently users it can't be on the free list... */
 			return 1;
-		}
-		else
+		} else {
 			dqput(dquot);   /* We have guaranteed we won't block */
+		}
+	}
 	return 0;
 }
 
@@ -793,20 +794,12 @@
 
 static void print_warning(struct dquot *dquot, int flag, const char *fmtstr)
 {
-	struct dentry *root;
-	char *path, *buffer;
-
 	if (!need_print_warning(dquot, flag))
 		return;
-	root = dquot->dq_sb->s_root;
-	dget(root);
-	buffer = (char *) __get_free_page(GFP_KERNEL);
-	path = buffer ? d_path(root, buffer, PAGE_SIZE) : "?";
-	sprintf(quotamessage, fmtstr, path, quotatypes[dquot->dq_type]);
-	free_page((unsigned long) buffer);
+	sprintf(quotamessage, fmtstr,
+		bdevname(dquot->dq_sb->s_dev), quotatypes[dquot->dq_type]);
 	tty_write_message(current->tty, quotamessage);
 	dquot->dq_flags |= flag;
-	dput(root);
 }
 
 static inline char ignore_hardlimit(struct dquot *dquot)
@@ -1469,7 +1462,7 @@
 	if (IS_ERR(tmp))
 		goto out_lock;
 
-	f = filp_open(tmp, O_RDWR, 0600, NULL);
+	f = filp_open(tmp, O_RDWR, 0600);
 	putname(tmp);
 
 	error = PTR_ERR(f);
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/exec.c linux/fs/exec.c
--- v2.3.99-pre3/linux/fs/exec.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/exec.c	Fri Apr  7 13:38:00 2000
@@ -112,7 +112,7 @@
 		goto out;
 	file = fget(fd);
 	retval = -ENOEXEC;
-	if (file && file->f_dentry && file->f_op && file->f_op->read) {
+	if (file && file->f_op && file->f_op->read) {
 		spin_lock(&binfmt_lock);
 		for (fmt = formats ; fmt ; fmt = fmt->next) {
 			if (!fmt->load_shlib)
@@ -315,27 +315,30 @@
 	return 0;
 }
 
+/* MOUNT_REWRITE: &mnt should be passed to lookup_dentry */
 struct file *open_exec(const char *name)
 {
 	struct dentry *dentry;
+	struct vfsmount *mnt = NULL;
 	struct file *file;
 
 	lock_kernel();
-	dentry = lookup_dentry(name, NULL, LOOKUP_FOLLOW);
+	dentry = lookup_dentry(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
 	file = (struct file*) dentry;
 	if (!IS_ERR(dentry)) {
 		file = ERR_PTR(-EACCES);
-		if (dentry->d_inode && S_ISREG(dentry->d_inode->i_mode)) {
+		if (S_ISREG(dentry->d_inode->i_mode)) {
 			int err = permission(dentry->d_inode, MAY_EXEC);
 			file = ERR_PTR(err);
 			if (!err) {
-				file = dentry_open(dentry, O_RDONLY);
+				file = dentry_open(dentry, mnt, O_RDONLY);
 out:
 				unlock_kernel();
 				return file;
 			}
 		}
 		dput(dentry);
+		mntput(mnt);
 	}
 	goto out;
 }
@@ -860,7 +863,6 @@
 	struct linux_binfmt * binfmt;
 	char corename[6+sizeof(current->comm)];
 	struct file * file;
-	struct dentry * dentry;
 	struct inode * inode;
 
 	lock_kernel();
@@ -879,17 +881,16 @@
 #else
 	corename[4] = '\0';
 #endif
-	file = filp_open(corename, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600, NULL);
+	file = filp_open(corename, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
 	if (IS_ERR(file))
 		goto fail;
-	dentry = file->f_dentry;
-	inode = dentry->d_inode;
+	inode = file->f_dentry->d_inode;
 	if (inode->i_nlink > 1)
 		goto close_fail;	/* multiple links - don't dump */
 
 	if (!S_ISREG(inode->i_mode))
 		goto close_fail;
-	if (!inode->i_fop)
+	if (!file->f_op)
 		goto close_fail;
 	if (!file->f_op->write)
 		goto close_fail;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.3.99-pre3/linux/fs/ext2/namei.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/ext2/namei.c	Mon Mar 27 10:39:33 2000
@@ -182,61 +182,71 @@
 	return NULL;
 }
 
+static inline void ext2_set_de_type(struct super_block *sb,
+				struct ext2_dir_entry_2 *de,
+				umode_t mode) {
+	if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
+		return;
+	if (S_ISREG(mode))
+		de->file_type = EXT2_FT_REG_FILE;
+	else if (S_ISDIR(mode))
+		de->file_type = EXT2_FT_DIR;
+	else if (S_ISLNK(mode))
+		de->file_type = EXT2_FT_SYMLINK;
+	else if (S_ISSOCK(mode))
+		de->file_type = EXT2_FT_SOCK;
+	else if (S_ISFIFO(mode))
+		de->file_type = EXT2_FT_FIFO;
+	else if (S_ISCHR(mode))
+		de->file_type = EXT2_FT_CHRDEV;
+	else if (S_ISBLK(mode))
+		de->file_type = EXT2_FT_BLKDEV;
+}
+
 /*
  *	ext2_add_entry()
  *
- * adds a file entry to the specified directory, using the same
- * semantics as ext2_find_entry(). It returns NULL if it failed.
- *
- * NOTE!! The inode part of 'de' is left at 0 - which means you
- * may not sleep between calling this and putting something into
- * the entry, as someone else might have used it while you slept.
+ * adds a file entry to the specified directory.
  */
-static struct buffer_head * ext2_add_entry (struct inode * dir,
-					    const char * name, int namelen,
-					    struct ext2_dir_entry_2 ** res_dir,
-					    int *err)
+int ext2_add_entry (struct inode * dir, const char * name, int namelen,
+		    struct inode *inode)
 {
 	unsigned long offset;
 	unsigned short rec_len;
 	struct buffer_head * bh;
 	struct ext2_dir_entry_2 * de, * de1;
 	struct super_block * sb;
+	int	retval;
 
-	*err = -EINVAL;
-	*res_dir = NULL;
 	if (!dir || !dir->i_nlink)
-		return NULL;
+		return -EINVAL;
 	sb = dir->i_sb;
 
 	if (!namelen)
-		return NULL;
+		return -EINVAL;
 	/*
 	 * Is this a busy deleted directory?  Can't create new files if so
 	 */
 	if (dir->i_size == 0)
 	{
-		*err = -ENOENT;
-		return NULL;
+		return -ENOENT;
 	}
-	bh = ext2_bread (dir, 0, 0, err);
+	bh = ext2_bread (dir, 0, 0, &retval);
 	if (!bh)
-		return NULL;
+		return retval;
 	rec_len = EXT2_DIR_REC_LEN(namelen);
 	offset = 0;
 	de = (struct ext2_dir_entry_2 *) bh->b_data;
-	*err = -ENOSPC;
 	while (1) {
 		if ((char *)de >= sb->s_blocksize + bh->b_data) {
 			brelse (bh);
 			bh = NULL;
-			bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, err);
+			bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &retval);
 			if (!bh)
-				return NULL;
+				return retval;
 			if (dir->i_size <= offset) {
 				if (dir->i_size == 0) {
-					*err = -ENOENT;
-					return NULL;
+					return -ENOENT;
 				}
 
 				ext2_debug ("creating next block\n");
@@ -256,14 +266,12 @@
 		}
 		if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
 					   offset)) {
-			*err = -ENOENT;
 			brelse (bh);
-			return NULL;
+			return -ENOENT;
 		}
 		if (ext2_match (namelen, name, de)) {
-				*err = -EEXIST;
 				brelse (bh);
-				return NULL;
+				return -EEXIST;
 		}
 		if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
 		    (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
@@ -276,7 +284,11 @@
 				de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
 				de = de1;
 			}
-			de->inode = 0;
+			if (inode) {
+				de->inode = cpu_to_le32(inode->i_ino);
+				ext2_set_de_type(dir->i_sb, de, inode->i_mode);
+			} else
+				de->inode = 0;
 			de->name_len = namelen;
 			de->file_type = 0;
 			memcpy (de->name, name, namelen);
@@ -296,22 +308,26 @@
 			mark_inode_dirty(dir);
 			dir->i_version = ++event;
 			mark_buffer_dirty(bh, 1);
-			*res_dir = de;
-			*err = 0;
-			return bh;
+			if (IS_SYNC(dir)) {
+				ll_rw_block (WRITE, 1, &bh);
+				wait_on_buffer (bh);
+			}
+			brelse(bh);
+			return 0;
 		}
 		offset += le16_to_cpu(de->rec_len);
 		de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
 	}
 	brelse (bh);
-	return NULL;
+	return -ENOSPC;
 }
 
 /*
  * ext2_delete_entry deletes a directory entry by merging it with the
  * previous entry
  */
-static int ext2_delete_entry (struct ext2_dir_entry_2 * dir,
+static int ext2_delete_entry (struct inode * dir,
+			      struct ext2_dir_entry_2 * de_del,
 			      struct buffer_head * bh)
 {
 	struct ext2_dir_entry_2 * de, * pde;
@@ -324,13 +340,19 @@
 		if (!ext2_check_dir_entry ("ext2_delete_entry", NULL, 
 					   de, bh, i))
 			return -EIO;
-		if (de == dir)  {
+		if (de == de_del)  {
 			if (pde)
 				pde->rec_len =
 					cpu_to_le16(le16_to_cpu(pde->rec_len) +
-						    le16_to_cpu(dir->rec_len));
+						    le16_to_cpu(de->rec_len));
 			else
-				dir->inode = 0;
+				de->inode = 0;
+			dir->i_version = ++event;
+			mark_buffer_dirty(bh, 1);
+			if (IS_SYNC(dir)) {
+				ll_rw_block (WRITE, 1, &bh);
+				wait_on_buffer (bh);
+			}
 			return 0;
 		}
 		i += le16_to_cpu(de->rec_len);
@@ -340,27 +362,6 @@
 	return -ENOENT;
 }
 
-static inline void ext2_set_de_type(struct super_block *sb,
-				struct ext2_dir_entry_2 *de,
-				umode_t mode) {
-	if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
-		return;
-	if (S_ISREG(mode))
-		de->file_type = EXT2_FT_REG_FILE;
-	else if (S_ISDIR(mode))
-		de->file_type = EXT2_FT_DIR;
-	else if (S_ISLNK(mode))
-		de->file_type = EXT2_FT_SYMLINK;
-	else if (S_ISSOCK(mode))
-		de->file_type = EXT2_FT_SOCK;
-	else if (S_ISFIFO(mode))
-		de->file_type = EXT2_FT_FIFO;
-	else if (S_ISCHR(mode))
-		de->file_type = EXT2_FT_CHRDEV;
-	else if (S_ISBLK(mode))
-		de->file_type = EXT2_FT_BLKDEV;
-}
-
 /*
  * By the time this is called, we already have created
  * the directory cache entry for the new file, but it
@@ -372,38 +373,28 @@
 static int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
 {
 	struct inode * inode;
-	struct buffer_head * bh;
-	struct ext2_dir_entry_2 * de;
-	int err = -EIO;
+	int err;
 
 	/*
 	 * N.B. Several error exits in ext2_new_inode don't set err.
 	 */
 	inode = ext2_new_inode (dir, mode, &err);
 	if (!inode)
-		return err;
+		return -EIO;
 
 	inode->i_op = &ext2_file_inode_operations;
 	inode->i_fop = &ext2_file_operations;
 	inode->i_mapping->a_ops = &ext2_aops;
 	inode->i_mode = mode;
 	mark_inode_dirty(inode);
-	bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-	if (!bh) {
+	err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
+			     inode);
+	if (err) {
 		inode->i_nlink--;
 		mark_inode_dirty(inode);
 		iput (inode);
 		return err;
 	}
-	de->inode = cpu_to_le32(inode->i_ino);
-	ext2_set_de_type(dir->i_sb, de, S_IFREG);
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh, 1);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
-	brelse (bh);
 	d_instantiate(dentry, inode);
 	return 0;
 }
@@ -411,56 +402,42 @@
 static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
 {
 	struct inode * inode;
-	struct buffer_head * bh;
-	struct ext2_dir_entry_2 * de;
-	int err = -EIO;
+	int err;
 
 	inode = ext2_new_inode (dir, mode, &err);
 	if (!inode)
-		goto out;
+		return -EIO;
 
 	inode->i_uid = current->fsuid;
 	init_special_inode(inode, mode, rdev);
-	bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-	if (!bh)
+	err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
+			     inode);
+	if (err)
 		goto out_no_entry;
-	de->inode = cpu_to_le32(inode->i_ino);
-	dir->i_version = ++event;
-	ext2_set_de_type(dir->i_sb, de, inode->i_mode);
 	mark_inode_dirty(inode);
-	mark_buffer_dirty(bh, 1);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
 	d_instantiate(dentry, inode);
-	brelse(bh);
-	err = 0;
-out:
-	return err;
+	return 0;
 
 out_no_entry:
 	inode->i_nlink--;
 	mark_inode_dirty(inode);
 	iput(inode);
-	goto out;
+	return err;
 }
 
 static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 {
 	struct inode * inode;
-	struct buffer_head * bh, * dir_block;
+	struct buffer_head * dir_block;
 	struct ext2_dir_entry_2 * de;
 	int err;
 
-	err = -EMLINK;
 	if (dir->i_nlink >= EXT2_LINK_MAX)
-		goto out;
+		return -EMLINK;
 
-	err = -EIO;
 	inode = ext2_new_inode (dir, S_IFDIR, &err);
 	if (!inode)
-		goto out;
+		return -EIO;
 
 	inode->i_op = &ext2_dir_inode_operations;
 	inode->i_fop = &ext2_dir_operations;
@@ -471,7 +448,7 @@
 		inode->i_nlink--; /* is this nlink == 0? */
 		mark_inode_dirty(inode);
 		iput (inode);
-		return err;
+		return -EIO;
 	}
 	de = (struct ext2_dir_entry_2 *) dir_block->b_data;
 	de->inode = cpu_to_le32(inode->i_ino);
@@ -492,31 +469,21 @@
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
 	mark_inode_dirty(inode);
-	bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-	if (!bh)
+	err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
+			     inode);
+	if (err)
 		goto out_no_entry;
-	de->inode = cpu_to_le32(inode->i_ino);
-	ext2_set_de_type(dir->i_sb, de, S_IFDIR);
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh, 1);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
 	dir->i_nlink++;
 	dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
 	mark_inode_dirty(dir);
 	d_instantiate(dentry, inode);
-	brelse (bh);
-	err = 0;
-out:
-	return err;
+	return 0;
 
 out_no_entry:
 	inode->i_nlink = 0;
 	mark_inode_dirty(inode);
 	iput (inode);
-	goto out;
+	return err;
 }
 
 /*
@@ -604,15 +571,9 @@
 	if (!empty_dir (inode))
 		goto end_rmdir;
 
-	retval = ext2_delete_entry (de, bh);
-	dir->i_version = ++event;
+	retval = ext2_delete_entry(dir, de, bh);
 	if (retval)
 		goto end_rmdir;
-	mark_buffer_dirty(bh, 1);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
 	if (inode->i_nlink != 2)
 		ext2_warning (inode->i_sb, "ext2_rmdir",
 			      "empty directory has nlink!=2 (%d)",
@@ -657,15 +618,9 @@
 			      inode->i_ino, inode->i_nlink);
 		inode->i_nlink = 1;
 	}
-	retval = ext2_delete_entry (de, bh);
+	retval = ext2_delete_entry(dir, de, bh);
 	if (retval)
 		goto end_unlink;
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh, 1);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
 	mark_inode_dirty(dir);
@@ -683,18 +638,14 @@
 static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
 {
 	struct inode * inode;
-	struct ext2_dir_entry_2 * de;
-	struct buffer_head * bh = NULL;
 	int l, err;
 
-	err = -ENAMETOOLONG;
 	l = strlen(symname)+1;
 	if (l > dir->i_sb->s_blocksize)
-		goto out;
+		return -ENAMETOOLONG;
 
-	err = -EIO;
 	if (!(inode = ext2_new_inode (dir, S_IFLNK, &err)))
-		goto out;
+		return -EIO;
 
 	inode->i_mode = S_IFLNK | S_IRWXUGO;
 
@@ -711,36 +662,24 @@
 	}
 	mark_inode_dirty(inode);
 
-	bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-	if (!bh)
+	err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
+			     inode);
+	if (err)
 		goto out_no_entry;
-	de->inode = cpu_to_le32(inode->i_ino);
-	ext2_set_de_type(dir->i_sb, de, S_IFLNK);
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh, 1);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
-	brelse (bh);
 	d_instantiate(dentry, inode);
-	err = 0;
-out:
-	return err;
+	return 0;
 
 out_no_entry:
 	inode->i_nlink--;
 	mark_inode_dirty(inode);
 	iput (inode);
-	goto out;
+	return err;
 }
 
 static int ext2_link (struct dentry * old_dentry,
 		struct inode * dir, struct dentry *dentry)
 {
 	struct inode *inode = old_dentry->d_inode;
-	struct ext2_dir_entry_2 * de;
-	struct buffer_head * bh;
 	int err;
 
 	if (S_ISDIR(inode->i_mode))
@@ -748,20 +687,12 @@
 
 	if (inode->i_nlink >= EXT2_LINK_MAX)
 		return -EMLINK;
-
-	bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-	if (!bh)
+	
+	err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
+			     inode);
+	if (err)
 		return err;
 
-	de->inode = cpu_to_le32(inode->i_ino);
-	ext2_set_de_type(dir->i_sb, de, inode->i_mode);
-	dir->i_version = ++event;
-	mark_buffer_dirty(bh, 1);
-	if (IS_SYNC(dir)) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
-	}
-	brelse (bh);
 	inode->i_nlink++;
 	inode->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(inode);
@@ -829,14 +760,26 @@
 			goto end_rename;
 	}
 	if (!new_bh) {
-		new_bh = ext2_add_entry (new_dir, new_dentry->d_name.name,
-					new_dentry->d_name.len, &new_de,
-					&retval);
-		if (!new_bh)
+		retval = ext2_add_entry (new_dir, new_dentry->d_name.name,
+					 new_dentry->d_name.len,
+					 old_inode);
+		if (retval)
 			goto end_rename;
+	} else {
+		new_de->inode = le32_to_cpu(old_inode->i_ino);
+		if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
+					      EXT2_FEATURE_INCOMPAT_FILETYPE))
+			new_de->file_type = old_de->file_type;
+		new_dir->i_version = ++event;
+		mark_buffer_dirty(new_bh, 1);
+		if (IS_SYNC(new_dir)) {
+			ll_rw_block (WRITE, 1, &new_bh);
+			wait_on_buffer (new_bh);
+		}
+		brelse(new_bh);
+		new_bh = NULL;
 	}
-	new_dir->i_version = ++event;
-
+	
 	/*
 	 * Like most other Unix systems, set the ctime for inodes on a
 	 * rename.
@@ -847,14 +790,8 @@
 	/*
 	 * ok, that's it
 	 */
-	new_de->inode = le32_to_cpu(old_inode->i_ino);
-	if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
-				      EXT2_FEATURE_INCOMPAT_FILETYPE))
-		new_de->file_type = old_de->file_type;
-	
-	ext2_delete_entry (old_de, old_bh);
+	ext2_delete_entry(old_dir, old_de, old_bh);
 
-	old_dir->i_version = ++event;
 	if (new_inode) {
 		new_inode->i_nlink--;
 		new_inode->i_ctime = CURRENT_TIME;
@@ -876,16 +813,6 @@
 			new_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
 			mark_inode_dirty(new_dir);
 		}
-	}
-	mark_buffer_dirty(old_bh,  1);
-	if (IS_SYNC(old_dir)) {
-		ll_rw_block (WRITE, 1, &old_bh);
-		wait_on_buffer (old_bh);
-	}
-	mark_buffer_dirty(new_bh, 1);
-	if (IS_SYNC(new_dir)) {
-		ll_rw_block (WRITE, 1, &new_bh);
-		wait_on_buffer (new_bh);
 	}
 
 	retval = 0;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.3.99-pre3/linux/fs/ext2/super.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/ext2/super.c	Mon Mar 27 10:39:33 2000
@@ -197,6 +197,8 @@
 			set_opt (*mount_options, GRPID);
 		else if (!strcmp (this_char, "minixdf"))
 			set_opt (*mount_options, MINIX_DF);
+		else if (!strcmp (this_char, "nocheck"))
+			clear_opt (*mount_options, CHECK);
 		else if (!strcmp (this_char, "nogrpid") ||
 			 !strcmp (this_char, "sysvgroups"))
 			clear_opt (*mount_options, GRPID);
@@ -300,13 +302,6 @@
 		}
 #endif
 	}
-#if 0 /* ibasket's still have unresolved bugs... -DaveM */
-
-	/* [T. Schoebel-Theuer] This limit should be maintained on disk.
-	 * This is just provisionary.
-	 */
-	sb->s_ibasket_max = 100;
-#endif
 }
 
 static int ext2_check_descriptors (struct super_block * sb)
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- v2.3.99-pre3/linux/fs/ext2/symlink.c	Thu Feb 10 17:11:17 2000
+++ linux/fs/ext2/symlink.c	Fri Apr  7 13:38:00 2000
@@ -25,10 +25,10 @@
 	return vfs_readlink(dentry, buffer, buflen, s);
 }
 
-static struct dentry *ext2_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags)
+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(dentry, base, flags, s);
+	return vfs_follow_link(nd, s);
 }
 
 struct inode_operations ext2_fast_symlink_inode_operations = {
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/file_table.c linux/fs/file_table.c
--- v2.3.99-pre3/linux/fs/file_table.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/file_table.c	Sun Apr  2 15:49:08 2000
@@ -122,13 +122,17 @@
 static void __fput(struct file *filp)
 {
 	struct dentry * dentry = filp->f_dentry;
+	struct vfsmount * mnt = filp->f_vfsmnt;
 	struct inode * inode = dentry->d_inode;
 
 	if (filp->f_op && filp->f_op->release)
 		filp->f_op->release(inode, filp);
 	filp->f_dentry = NULL;
+	filp->f_vfsmnt = NULL;
 	if (filp->f_mode & FMODE_WRITE)
 		put_write_access(inode);
+	if (mnt)
+		mntput(mnt);
 	dput(dentry);
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/hfs/dir.c linux/fs/hfs/dir.c
--- v2.3.99-pre3/linux/fs/hfs/dir.c	Fri Mar 10 16:40:47 2000
+++ linux/fs/hfs/dir.c	Sun Apr  2 15:49:08 2000
@@ -314,14 +314,10 @@
 	if (!d_unhashed(dentry))
 		goto hfs_rmdir_put;
 
-	if (/* we only have to worry about 2 and 3 for mount points */
-		(victim->sys_entry[2] &&
-		 (victim->sys_entry[2]->d_mounts !=
-		  victim->sys_entry[2]->d_covers)) ||
-		(victim->sys_entry[3] &&
-		 (victim->sys_entry[3]->d_mounts != 
-		  victim->sys_entry[3]->d_covers))
-		) 
+	/* we only have to worry about 2 and 3 for mount points */
+	if (victim->sys_entry[2] && d_mountpoint(victim->sys_entry[2]))
+		goto hfs_rmdir_put;
+	if (victim->sys_entry[3] && d_mountpoint(victim->sys_entry[3])) 
 		goto hfs_rmdir_put;
 
 	
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/hpfs/dir.c linux/fs/hpfs/dir.c
--- v2.3.99-pre3/linux/fs/hpfs/dir.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/hpfs/dir.c	Sun Apr  2 15:53:28 2000
@@ -23,7 +23,7 @@
 	loff_t pos;
 	struct quad_buffer_head qbh;
 	struct inode *i = filp->f_dentry->d_inode;
-	struct super_block *s = filp->f_dentry->d_sb;
+	struct super_block *s = i->i_sb;
 	/*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);
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/inode.c linux/fs/inode.c
--- v2.3.99-pre3/linux/fs/inode.c	Fri Mar 10 16:40:47 2000
+++ linux/fs/inode.c	Sun Apr  2 15:38:54 2000
@@ -111,6 +111,14 @@
  * In short, make sure you hash any inodes _before_
  * you start marking them dirty..
  */
+ 
+/**
+ *	__mark_inode_dirty -	internal function
+ *	@inode: inode to mark
+ *
+ *	Mark an inode as dirty. Callers should use mark_inode_dirty
+ */
+ 
 void __mark_inode_dirty(struct inode *inode)
 {
 	struct super_block * sb = inode->i_sb;
@@ -202,10 +210,14 @@
 		sync_one(list_entry(tmp, struct inode, i_list));
 }
 
-/*
- * "sync_inodes()" goes through the super block's dirty list, 
- * writes them out, and puts them back on the normal list.
+/**
+ *	sync_inodes
+ *	@dev: device to sync the inodes from.
+ *
+ *	sync_inodes goes through the super block's dirty list, 
+ *	writes them out, and puts them back on the normal list.
  */
+ 
 void sync_inodes(kdev_t dev)
 {
 	struct super_block * sb = sb_entry(super_blocks.next);
@@ -241,9 +253,14 @@
 	}
 }
 
-/*
- * Needed by knfsd
+/**
+ *	write_inode_now	-	write an inode to disk
+ *	@inode: inode to write to disk
+ *
+ *	This function commits an inode to disk immediately if it is
+ *	dirty. This is primarily needed by knfsd.
  */
+ 
 void write_inode_now(struct inode *inode)
 {
 	struct super_block * sb = inode->i_sb;
@@ -258,11 +275,15 @@
 		printk("write_inode_now: no super block\n");
 }
 
-/*
+/**
+ * clear_inode - clear an inode
+ * @inode: inode to clear
+ *
  * This is called by the filesystem to tell us
  * that the inode is no longer useful. We just
  * terminate it with extreme prejudice.
  */
+ 
 void clear_inode(struct inode *inode)
 {
 	if (inode->i_data.nrpages)
@@ -346,6 +367,16 @@
  * is because we don't want to sleep while messing
  * with the global lists..
  */
+ 
+/**
+ *	invalidate_inodes	- discard the inodes on a device
+ *	@sb: superblock
+ *
+ *	Discard all of the inodes for a given superblock. If the discard
+ *	fails because there are busy inodes then a non zero value is returned.
+ *	If the discard is successful all the inodes are dicarded.
+ */
+ 
 int invalidate_inodes(struct super_block * sb)
 {
 	int busy;
@@ -490,12 +521,19 @@
 	inode->i_mapping = &inode->i_data;
 }
 
-/*
+/**
+ * get_empty_inode 	- obtain an inode
+ *
  * This is called by things like the networking layer
  * etc that want to get an inode without any inode
  * number, or filesystems that allocate new inodes with
  * no pre-existing information.
+ *
+ * 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.
  */
+ 
 struct inode * get_empty_inode(void)
 {
 	static unsigned long last_ino = 0;
@@ -585,6 +623,22 @@
 }
 
 /* Yeah, I know about quadratic hash. Maybe, later. */
+
+/**
+ *	iunique - get a unique inode number
+ *	@sb: superblock
+ *	@max_reserved: highest reserved inode number
+ *
+ *	Obtain an inode number that is unique on the system for a given
+ *	superblock. This is used by file systems that have no natural
+ *	permanent inode numbering system. An inode number is returned that
+ *	is higher than the reserved limit but unique.
+ *
+ *	BUGS:
+ *	With a large number of inodes live on the file system this function
+ *	currently becomes quite slow.
+ */
+ 
 ino_t iunique(struct super_block *sb, ino_t max_reserved)
 {
 	static ino_t counter = 0;
@@ -625,6 +679,7 @@
 	return inode;
 }
 
+
 struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
 {
 	struct list_head * head = inode_hashtable + hash(sb,ino);
@@ -647,6 +702,14 @@
 	return get_new_inode(sb, ino, head, find_actor, opaque);
 }
 
+/**
+ *	insert_inode_hash - hash an inode
+ *	@inode: unhashed inode
+ *
+ *	Add an inode to the inode hash for this superblock. If the inode
+ *	has no superblock it is added to a seperate anonymous chain
+ */
+ 
 void insert_inode_hash(struct inode *inode)
 {
 	struct list_head *head = &anon_hash_chain;
@@ -657,6 +720,13 @@
 	spin_unlock(&inode_lock);
 }
 
+/**
+ *	remove_inode_hash - remove an inode from the hash
+ *	@inode: inode to unhash
+ *
+ *	Remove an inode from the superblock or anonymous hash
+ */
+ 
 void remove_inode_hash(struct inode *inode)
 {
 	spin_lock(&inode_lock);
@@ -665,6 +735,14 @@
 	spin_unlock(&inode_lock);
 }
 
+/**
+ *	iput	- put an inode 
+ *	@inode: inode to put
+ *
+ *	Puts an inode, dropping its usage count. If the inode use count hits
+ *	zero the inode is also then freed and may be destroyed.
+ */
+ 
 void iput(struct inode *inode)
 {
 	if (inode) {
@@ -686,11 +764,12 @@
 				inode->i_state|=I_FREEING;
 				spin_unlock(&inode_lock);
 
+				if (inode->i_data.nrpages)
+					truncate_inode_pages(&inode->i_data, 0);
+
 				destroy = 1;
 				if (op && op->delete_inode) {
 					void (*delete)(struct inode *) = op->delete_inode;
-					if (inode->i_data.nrpages)
-						truncate_inode_pages(&inode->i_data, 0);
 					/* s_op->delete_inode internally recalls clear_inode() */
 					delete(inode);
 				} else
@@ -743,6 +822,18 @@
 	}
 }
 
+/**
+ *	bmap	- find a block number in a file
+ *	@inode: inode of file
+ *	@block: block to find
+ *
+ *	Returns the block number on the device holding the inode that
+ *	is the disk block number for the block of the file requested.
+ *	That is asked for block 4 of inode 1 the function will return the
+ *	disk block relative to the disk start that holds that block of the 
+ *	file
+ */
+ 
 int bmap(struct inode * inode, int block)
 {
 	int res = 0;
@@ -774,13 +865,22 @@
 		panic("cannot create inode slab cache");
 }
 
+/**
+ *	update_atime	-	update the access time
+ *	@inode: inode accessed
+ *
+ *	Update the accessed time on an inode and mark it for  writeback.
+ *	This function automatically handles read only file systems and media,
+ *	as well as the noatime flag and inode specific noatime markers
+ */
+ 
 void update_atime (struct inode *inode)
 {
-    if ( IS_NOATIME (inode) ) return;
-    if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
-    if ( IS_RDONLY (inode) ) return;
-    inode->i_atime = CURRENT_TIME;
-    mark_inode_dirty (inode);
+	if ( IS_NOATIME (inode) ) return;
+	if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
+	if ( IS_RDONLY (inode) ) return;
+	inode->i_atime = CURRENT_TIME;
+	mark_inode_dirty (inode);
 }   /*  End Function update_atime  */
 
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/ioctl.c linux/fs/ioctl.c
--- v2.3.99-pre3/linux/fs/ioctl.c	Thu Feb 10 17:11:17 2000
+++ linux/fs/ioctl.c	Sun Apr  2 15:53:28 2000
@@ -98,9 +98,7 @@
 
 		default:
 			error = -ENOTTY;
-			if (!filp->f_dentry || !filp->f_dentry->d_inode)
-				error = -ENOENT;
-			else if (S_ISREG(filp->f_dentry->d_inode->i_mode))
+			if (S_ISREG(filp->f_dentry->d_inode->i_mode))
 				error = file_ioctl(filp, cmd, arg);
 			else if (filp->f_op && filp->f_op->ioctl)
 				error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/clntlock.c linux/fs/lockd/clntlock.c
--- v2.3.99-pre3/linux/fs/lockd/clntlock.c	Thu Aug 26 13:05:40 1999
+++ linux/fs/lockd/clntlock.c	Sun Apr  2 15:31:32 2000
@@ -152,7 +152,7 @@
 		host->h_monitored = 0;
 		host->h_nsmstate = newstate;
 		host->h_state++;
-		host->h_count++;
+		nlm_get_host(host);
 		kernel_thread(reclaimer, host, 0);
 	}
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c
--- v2.3.99-pre3/linux/fs/lockd/clntproc.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/lockd/clntproc.c	Mon Apr  3 13:24:05 2000
@@ -106,10 +106,18 @@
 	struct nlm_rqst		reqst, *call = &reqst;
 	sigset_t		oldset;
 	unsigned long		flags;
-	int			status;
+	int			status, proto, vers;
 
-	/* Always use NLM version 1 over UDP for now... */
-	if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), IPPROTO_UDP, 1)))
+	vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
+	if (NFS_PROTO(inode)->version > 3) {
+		printk(KERN_NOTICE "NFSv4 file locking not implemented!\n");
+		return -ENOLCK;
+	}
+
+	/* Retrieve transport protocol from NFS client */
+	proto = NFS_CLIENT(inode)->cl_xprt->prot;
+
+	if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers)))
 		return -ENOLCK;
 
 	/* Create RPC client handle if not there, and copy soft
@@ -142,6 +150,10 @@
 		spin_unlock_irqrestore(&current->sigmask_lock, flags);
 
 		call = nlmclnt_alloc_call();
+		if (!call) {
+			status = -ENOMEM;
+			goto out_restore;
+		}
 		call->a_flags = RPC_TASK_ASYNC;
 	} else {
 		spin_unlock_irqrestore(&current->sigmask_lock, flags);
@@ -165,8 +177,9 @@
 	}
 
 	if (status < 0 && (call->a_flags & RPC_TASK_ASYNC))
-		rpc_free(call);
+		kfree(call);
 
+ out_restore:
 	spin_lock_irqsave(&current->sigmask_lock, flags);
 	current->blocked = oldset;
 	recalc_sigpending(current);
@@ -200,8 +213,7 @@
 	struct nlm_rqst	*call;
 
 	while (!signalled()) {
-		call = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC,
-					sizeof(struct nlm_rqst));
+		call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL);
 		if (call)
 			return call;
 		printk("nlmclnt_alloc_call: failed, waiting for memory\n");
@@ -246,6 +258,7 @@
 			case -ECONNREFUSED:
 			case -ETIMEDOUT:
 			case -ENOTCONN:
+				nlm_rebind_host(host);
 				status = -EAGAIN;
 				break;
 			case -ERESTARTSYS:
@@ -253,10 +266,7 @@
 			default:
 				break;
 			}
-			if (req->a_args.block)
-				nlm_rebind_host(host);
-			else
-				break;
+			break;
 		} else
 		if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) {
 			dprintk("lockd: server in grace period\n");
@@ -290,7 +300,7 @@
  * Generic NLM call, async version.
  */
 int
-nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
+nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
 {
 	struct nlm_host	*host = req->a_host;
 	struct rpc_clnt	*clnt;
@@ -313,9 +323,20 @@
 	msg.rpc_cred = NULL;	
         status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
 
-	/* If the async call is proceeding, increment host refcount */
-        if (status >= 0 && (req->a_flags & RPC_TASK_ASYNC))
-                host->h_count++;
+	return status;
+}
+
+int
+nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
+{
+	struct nlm_host	*host = req->a_host;
+	int status;
+
+	/* Increment host refcount */
+	nlm_get_host(host);
+	status = nlmsvc_async_call(req, proc, callback);
+	if (status < 0)
+		nlm_release_host(host);
 	return status;
 }
 
@@ -347,6 +368,20 @@
 	return 0;
 }
 
+static
+void nlmclnt_insert_lock_callback(struct file_lock *fl)
+{
+	nlm_get_host(fl->fl_u.nfs_fl.host);
+}
+static
+void nlmclnt_remove_lock_callback(struct file_lock *fl)
+{
+	if (fl->fl_u.nfs_fl.host) {
+		nlm_release_host(fl->fl_u.nfs_fl.host);
+		fl->fl_u.nfs_fl.host = NULL;
+	}
+}
+
 /*
  * LOCK: Try to create a lock
  *
@@ -380,7 +415,7 @@
 		return -ENOLCK;
 	}
 
-	while (1) {
+	do {
 		if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) {
 			if (resp->status != NLM_LCK_BLOCKED)
 				break;
@@ -388,11 +423,14 @@
 		}
 		if (status < 0)
 			return status;
-	}
+	} while (resp->status == NLM_LCK_BLOCKED);
 
 	if (resp->status == NLM_LCK_GRANTED) {
 		fl->fl_u.nfs_fl.state = host->h_state;
 		fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
+		fl->fl_u.nfs_fl.host = host;
+		fl->fl_insert = nlmclnt_insert_lock_callback;
+		fl->fl_remove = nlmclnt_remove_lock_callback;
 	}
 
 	return nlm_stat_to_errno(resp->status);
@@ -444,15 +482,9 @@
 static int
 nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
 {
-	struct nlm_host	*host = req->a_host;
 	struct nlm_res	*resp = &req->a_res;
 	int		status;
 
-	/* No monitor, no lock: see nlmclnt_lock().
-	 * Since this is an UNLOCK, don't try to setup monitoring here. */
-	if (!host->h_monitored)
-		return -ENOLCK;
-
 	/* Clean the GRANTED flag now so the lock doesn't get
 	 * reclaimed while we're stuck in the unlock call. */
 	fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED;
@@ -487,9 +519,7 @@
 
 	if (task->tk_status < 0) {
 		dprintk("lockd: unlock failed (err = %d)\n", -task->tk_status);
-		nlm_rebind_host(req->a_host);
-		rpc_restart_call(task);
-		return;
+		goto retry_unlock;
 	}
 	if (status != NLM_LCK_GRANTED
 	 && status != NLM_LCK_DENIED_GRACE_PERIOD) {
@@ -497,7 +527,12 @@
 	}
 
 die:
-	rpc_release_task(task);
+	nlm_release_host(req->a_host);
+	kfree(req);
+	return;
+ retry_unlock:
+	nlm_rebind_host(req->a_host);
+	rpc_restart_call(task);
 }
 
 /*
@@ -520,10 +555,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irqrestore(&current->sigmask_lock, flags);
 
-	do {
-		req = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC,
-							sizeof(*req));
-	} while (req == NULL);
+	req = nlmclnt_alloc_call();
+	if (!req)
+		return -ENOMEM;
 	req->a_host  = host;
 	req->a_flags = RPC_TASK_ASYNC;
 
@@ -532,7 +566,7 @@
 	status = nlmclnt_async_call(req, NLMPROC_CANCEL,
 					nlmclnt_cancel_callback);
 	if (status < 0)
-		rpc_free(req);
+		kfree(req);
 
 	spin_lock_irqsave(&current->sigmask_lock, flags);
 	current->blocked = oldset;
@@ -573,7 +607,6 @@
 	}
 
 die:
-	rpc_release_task(task);
 	nlm_release_host(req->a_host);
 	kfree(req);
 	return;
@@ -582,7 +615,6 @@
 	nlm_rebind_host(req->a_host);
 	rpc_restart_call(task);
 	rpc_delay(task, 30 * HZ);
-	return;
 }
 
 /*
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/host.c linux/fs/lockd/host.c
--- v2.3.99-pre3/linux/fs/lockd/host.c	Wed Jun 30 10:22:00 1999
+++ linux/fs/lockd/host.c	Sun Apr  2 15:31:32 2000
@@ -15,6 +15,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
+#include <linux/lockd/sm_inter.h>
 
 
 #define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
@@ -105,8 +106,7 @@
 				host->h_next = nlm_hosts[hash];
 				nlm_hosts[hash] = host;
 			}
-			host->h_expires = jiffies + NLM_HOST_EXPIRE;
-			host->h_count++;
+			nlm_get_host(host);
 			up(&nlm_host_sema);
 			return host;
 		}
@@ -172,9 +172,12 @@
 	down(&host->h_sema);
 
 	/* If we've already created an RPC client, check whether
-	 * RPC rebind is required */
+	 * RPC rebind is required
+	 * Note: why keep rebinding if we're on a tcp connection?
+	 */
 	if ((clnt = host->h_rpcclnt) != NULL) {
-		if (time_after_eq(jiffies, host->h_nextrebind)) {
+		xprt = clnt->cl_xprt;
+		if (!xprt->stream && time_after_eq(jiffies, host->h_nextrebind)) {
 			clnt->cl_port = 0;
 			host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 			dprintk("lockd: next rebind in %ld jiffies\n",
@@ -230,13 +233,27 @@
 }
 
 /*
+ * Increment NLM host count
+ */
+struct nlm_host * nlm_get_host(struct nlm_host *host)
+{
+	if (host) {
+		dprintk("lockd: get host %s\n", host->h_name);
+		host->h_count ++;
+		host->h_expires = jiffies + NLM_HOST_EXPIRE;
+	}
+	return host;
+}
+
+/*
  * Release NLM host after use
  */
-void
-nlm_release_host(struct nlm_host *host)
+void nlm_release_host(struct nlm_host *host)
 {
-	dprintk("lockd: release host %s\n", host->h_name);
-	host->h_count -= 1;
+	if (host && host->h_count) {
+		dprintk("lockd: release host %s\n", host->h_name);
+		host->h_count --;
+	}
 }
 
 /*
@@ -308,6 +325,8 @@
 			}
 			dprintk("lockd: delete host %s\n", host->h_name);
 			*q = host->h_next;
+			if (host->h_monitored)
+				nsm_unmonitor(host);
 			if ((clnt = host->h_rpcclnt) != NULL) {
 				if (clnt->cl_users) {
 					printk(KERN_WARNING
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/mon.c linux/fs/lockd/mon.c
--- v2.3.99-pre3/linux/fs/lockd/mon.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/lockd/mon.c	Sun Apr  2 15:31:32 2000
@@ -30,14 +30,12 @@
  * Common procedure for SM_MON/SM_UNMON calls
  */
 static int
-nsm_mon_unmon(struct nlm_host *host, char *what, u32 proc)
+nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
 {
 	struct rpc_clnt	*clnt;
 	int		status;
 	struct nsm_args	args;
-	struct nsm_res	res;
 
-	dprintk("lockd: nsm_%s(%s)\n", what, host->h_name);
 	status = -EACCES;
 	clnt = nsm_create();
 	if (!clnt)
@@ -47,23 +45,15 @@
 	args.prog = NLM_PROGRAM;
 	args.vers = 1;
 	args.proc = NLMPROC_NSM_NOTIFY;
+	memset(res, 0, sizeof(*res));
 
-	status = rpc_call(clnt, proc, &args, &res, 0);
-	if (status < 0) {
+	status = rpc_call(clnt, proc, &args, res, 0);
+	if (status < 0)
 		printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n",
 			status);
-		goto out;
-	}
-
-	status = -EACCES;
-	if (res.status != 0) {
-		printk(KERN_NOTICE "lockd: cannot %s %s\n", what, host->h_name);
-		goto out;
-	}
-
-	nsm_local_state = res.state;
-	status = 0;
-out:
+	else
+		status = 0;
+ out:
 	return status;
 }
 
@@ -73,10 +63,16 @@
 int
 nsm_monitor(struct nlm_host *host)
 {
+	struct nsm_res	res;
 	int		status;
 
-	status = nsm_mon_unmon(host, "monitor", SM_MON);
-	if (status >= 0)
+	dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
+
+	status = nsm_mon_unmon(host, SM_MON, &res);
+
+	if (status < 0 || res.status != 0)
+		printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
+	else
 		host->h_monitored = 1;
 	return status;
 }
@@ -87,9 +83,15 @@
 int
 nsm_unmonitor(struct nlm_host *host)
 {
+	struct nsm_res	res;
 	int		status;
 
-	if ((status = nsm_mon_unmon(host, "unmonitor", SM_UNMON)) >= 0)
+	dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
+
+	status = nsm_mon_unmon(host, SM_UNMON, &res);
+	if (status < 0)
+		printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name);
+	else
 		host->h_monitored = 0;
 	return status;
 }
@@ -187,7 +189,7 @@
 static int
 xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
 {
-	resp->status = ntohl(*p++);
+	resp->state = ntohl(*p++);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/svc4proc.c linux/fs/lockd/svc4proc.c
--- v2.3.99-pre3/linux/fs/lockd/svc4proc.c	Sun Feb 20 21:12:39 2000
+++ linux/fs/lockd/svc4proc.c	Mon Apr  3 13:24:05 2000
@@ -470,7 +470,7 @@
 	host = nlmclnt_lookup_host(&rqstp->rq_addr,
 				rqstp->rq_prot, rqstp->rq_vers);
 	if (!host) {
-		rpc_free(call);
+		kfree(call);
 		return rpc_system_err;
 	}
 
@@ -478,12 +478,14 @@
 	call->a_host  = host;
 	memcpy(&call->a_args, resp, sizeof(*resp));
 
-/* FIXME this should become nlmSVC_async_call when that code gets
-   merged in XXX */
-	if (nlmclnt_async_call(call, proc, nlm4svc_callback_exit) < 0)
-		return rpc_system_err;
+	if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0)
+		goto error;
 
 	return rpc_success;
+ error:
+	kfree(call);
+	nlm_release_host(host);
+	return rpc_system_err;
 }
 
 static void
@@ -496,7 +498,7 @@
 					task->tk_pid, -task->tk_status);
 	}
 	nlm_release_host(call->a_host);
-	rpc_free(call);
+	kfree(call);
 }
 
 /*
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/svclock.c linux/fs/lockd/svclock.c
--- v2.3.99-pre3/linux/fs/lockd/svclock.c	Sun Feb 20 21:12:39 2000
+++ linux/fs/lockd/svclock.c	Mon Apr  3 13:24:05 2000
@@ -94,14 +94,16 @@
 	struct nlm_block	**head, *block;
 	struct file_lock	*fl;
 
-	dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %ld-%ld ty=%d\n",
-				file, lock->fl.fl_pid, lock->fl.fl_start,
-				lock->fl.fl_end, lock->fl.fl_type);
+	dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
+				file, lock->fl.fl_pid,
+				(long long)lock->fl.fl_start,
+				(long long)lock->fl.fl_end, lock->fl.fl_type);
 	for (head = &nlm_blocked; (block = *head); head = &block->b_next) {
 		fl = &block->b_call.a_args.lock.fl;
-		dprintk("lockd: check f=%p pd=%d %ld-%ld ty=%d cookie=%x\n",
-				block->b_file, fl->fl_pid, fl->fl_start,
-				fl->fl_end, fl->fl_type,
+		dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%x\n",
+				block->b_file, fl->fl_pid,
+				(long long)fl->fl_start,
+				(long long)fl->fl_end, fl->fl_type,
 				*(unsigned int*)(block->b_call.a_args.cookie.data));
 		if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
 			if (remove)
@@ -286,12 +288,12 @@
 	struct nlm_block	*block;
 	int			error;
 
-	dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %ld-%ld, bl=%d)\n",
+	dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
 				file->f_file.f_dentry->d_inode->i_dev,
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_type, lock->fl.fl_pid,
-				lock->fl.fl_start,
-				lock->fl.fl_end,
+				(long long)lock->fl.fl_start,
+				(long long)lock->fl.fl_end,
 				wait);
 
 	/* Lock file against concurrent access */
@@ -365,16 +367,17 @@
 {
 	struct file_lock	*fl;
 
-	dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %ld-%ld)\n",
+	dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n",
 				file->f_file.f_dentry->d_inode->i_dev,
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_type,
-				lock->fl.fl_start,
-				lock->fl.fl_end);
+				(long long)lock->fl.fl_start,
+				(long long)lock->fl.fl_end);
 
 	if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
-		dprintk("lockd: conflicting lock(ty=%d, %ld-%ld)\n",
-				fl->fl_type, fl->fl_start, fl->fl_end);
+		dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
+				fl->fl_type, (long long)fl->fl_start,
+				(long long)fl->fl_end);
 		conflock->caller = "somehost";	/* FIXME */
 		conflock->oh.len = 0;		/* don't return OH info */
 		conflock->fl = *fl;
@@ -396,12 +399,12 @@
 {
 	int	error;
 
-	dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %ld-%ld)\n",
+	dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n",
 				file->f_file.f_dentry->d_inode->i_dev,
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_pid,
-				lock->fl.fl_start,
-				lock->fl.fl_end);
+				(long long)lock->fl.fl_start,
+				(long long)lock->fl.fl_end);
 
 	/* First, cancel any lock that might be there */
 	nlmsvc_cancel_blocked(file, lock);
@@ -424,12 +427,12 @@
 {
 	struct nlm_block	*block;
 
-	dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %ld-%ld)\n",
+	dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n",
 				file->f_file.f_dentry->d_inode->i_dev,
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_pid,
-				lock->fl.fl_start,
-				lock->fl.fl_end);
+				(long long)lock->fl.fl_start,
+				(long long)lock->fl.fl_end);
 
 	down(&file->f_sema);
 	if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
@@ -576,7 +579,6 @@
 	block->b_incall = 0;
 
 	nlm_release_host(call->a_host);
-	rpc_release_task(task);
 }
 
 /*
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/svcproc.c linux/fs/lockd/svcproc.c
--- v2.3.99-pre3/linux/fs/lockd/svcproc.c	Sun Feb 20 21:12:39 2000
+++ linux/fs/lockd/svcproc.c	Mon Apr  3 13:24:06 2000
@@ -503,10 +503,14 @@
 	call->a_host  = host;
 	memcpy(&call->a_args, resp, sizeof(*resp));
 
-	if (nlmclnt_async_call(call, proc, nlmsvc_callback_exit) < 0)
-		return rpc_system_err;
+	if (nlmsvc_async_call(call, proc, nlmsvc_callback_exit) < 0)
+		goto error;
 
 	return rpc_success;
+ error:
+	nlm_release_host(host);
+	kfree(call);
+	return rpc_system_err;
 }
 
 static void
@@ -519,7 +523,6 @@
 					task->tk_pid, -task->tk_status);
 	}
 	nlm_release_host(call->a_host);
-	rpc_release_task(task);
 	kfree(call);
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/svcsubs.c linux/fs/lockd/svcsubs.c
--- v2.3.99-pre3/linux/fs/lockd/svcsubs.c	Fri Mar 10 16:40:47 2000
+++ linux/fs/lockd/svcsubs.c	Sun Apr  2 15:31:32 2000
@@ -34,7 +34,7 @@
 {
 	unsigned int tmp=0;
 	int i;
-	for (i=0; i<NFS_FHSIZE;i++)
+	for (i=0; i<NFS2_FHSIZE;i++)
 		tmp += f->data[i];
 	return tmp & (FILE_NRHASH - 1);
 }
@@ -175,7 +175,7 @@
 
 			lock.fl_type  = F_UNLCK;
 			lock.fl_start = 0;
-			lock.fl_end   = NLM_OFFSET_MAX;
+			lock.fl_end   = OFFSET_MAX;
 			if (posix_lock_file(&file->f_file, &lock, 0) < 0) {
 				printk("lockd: unlock failure in %s:%d\n",
 						__FILE__, __LINE__);
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/xdr.c linux/fs/lockd/xdr.c
--- v2.3.99-pre3/linux/fs/lockd/xdr.c	Fri Mar 10 16:40:47 2000
+++ linux/fs/lockd/xdr.c	Sun Apr  2 15:31:32 2000
@@ -22,6 +22,25 @@
 #define NLMDBG_FACILITY		NLMDBG_XDR
 
 
+static inline loff_t
+s32_to_loff_t(__s32 offset)
+{
+	return (loff_t)offset;
+}
+
+static inline __s32
+loff_t_to_s32(loff_t offset)
+{
+	__s32 res;
+	if (offset >= NLM_OFFSET_MAX)
+		res = NLM_OFFSET_MAX;
+	else if (offset <= -NLM_OFFSET_MAX)
+		res = -NLM_OFFSET_MAX;
+	else
+		res = offset;
+	return res;
+}
+
 /*
  * XDR functions for basic NLM types
  */
@@ -65,22 +84,23 @@
 {
 	unsigned int	len;
 
-	if ((len = ntohl(*p++)) != sizeof(*f)) {
+	if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
 		printk(KERN_NOTICE
 			"lockd: bad fhandle size %x (should be %Zu)\n",
-			len, sizeof(*f));
+			len, NFS2_FHSIZE);
 		return NULL;
 	}
-	memcpy(f, p, sizeof(*f));
-	return p + XDR_QUADLEN(sizeof(*f));
+	f->size = NFS2_FHSIZE;
+	memcpy(f->data, p, NFS2_FHSIZE);
+	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
 static inline u32 *
 nlm_encode_fh(u32 *p, struct nfs_fh *f)
 {
-	*p++ = htonl(sizeof(*f));
-	memcpy(p, f, sizeof(*f));
-	return p + XDR_QUADLEN(sizeof(*f));
+	*p++ = htonl(NFS2_FHSIZE);
+	memcpy(p, f->data, NFS2_FHSIZE);
+	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
 /*
@@ -102,7 +122,7 @@
 nlm_decode_lock(u32 *p, struct nlm_lock *lock)
 {
 	struct file_lock	*fl = &lock->fl;
-	int			len;
+	s32			start, len, end;
 
 	if (!(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN))
 	 || !(p = nlm_decode_fh(p, &lock->fh))
@@ -114,10 +134,16 @@
 	fl->fl_pid   = ntohl(*p++);
 	fl->fl_flags = FL_POSIX;
 	fl->fl_type  = F_RDLCK;		/* as good as anything else */
-	fl->fl_start = ntohl(*p++);
+	start = ntohl(*p++);
 	len = ntohl(*p++);
-	if (len == 0 || (fl->fl_end = fl->fl_start + len - 1) < 0)
-		fl->fl_end = NLM_OFFSET_MAX;
+	end = start + len - 1;
+
+	fl->fl_start = s32_to_loff_t(start);
+
+	if (len == 0 || end < 0)
+		fl->fl_end = OFFSET_MAX;
+	else
+		fl->fl_end = s32_to_loff_t(end);
 	return p;
 }
 
@@ -128,18 +154,26 @@
 nlm_encode_lock(u32 *p, struct nlm_lock *lock)
 {
 	struct file_lock	*fl = &lock->fl;
+	__s32			start, len;
 
 	if (!(p = xdr_encode_string(p, lock->caller))
 	 || !(p = nlm_encode_fh(p, &lock->fh))
 	 || !(p = nlm_encode_oh(p, &lock->oh)))
 		return NULL;
 
-	*p++ = htonl(fl->fl_pid);
-	*p++ = htonl(lock->fl.fl_start);
-	if (lock->fl.fl_end == NLM_OFFSET_MAX)
-		*p++ = xdr_zero;
+	if (fl->fl_start > NLM_OFFSET_MAX
+	 || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
+		return NULL;
+
+	start = loff_t_to_s32(fl->fl_start);
+	if (fl->fl_end == OFFSET_MAX)
+		len = 0;
 	else
-		*p++ = htonl(lock->fl.fl_end - lock->fl.fl_start + 1);
+		len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
+
+	*p++ = htonl(fl->fl_pid);
+	*p++ = htonl(start);
+	*p++ = htonl(len);
 
 	return p;
 }
@@ -150,6 +184,8 @@
 static u32 *
 nlm_encode_testres(u32 *p, struct nlm_res *resp)
 {
+	s32		start, len;
+
 	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 		return 0;
 	*p++ = resp->status;
@@ -164,11 +200,14 @@
 		if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
 			return 0;
 
-		*p++ = htonl(fl->fl_start);
-		if (fl->fl_end == NLM_OFFSET_MAX)
-			*p++ = xdr_zero;
+		start = loff_t_to_s32(fl->fl_start);
+		if (fl->fl_end == OFFSET_MAX)
+			len = 0;
 		else
-			*p++ = htonl(fl->fl_end - fl->fl_start + 1);
+			len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
+
+		*p++ = htonl(start);
+		*p++ = htonl(len);
 	}
 
 	return p;
@@ -387,7 +426,8 @@
 	resp->status = ntohl(*p++);
 	if (resp->status == NLM_LCK_DENIED) {
 		struct file_lock	*fl = &resp->lock.fl;
-		u32			excl, len;
+		u32			excl;
+		s32			start, len, end;
 
 		memset(&resp->lock, 0, sizeof(resp->lock));
 		excl = ntohl(*p++);
@@ -397,10 +437,15 @@
 
 		fl->fl_flags = FL_POSIX;
 		fl->fl_type  = excl? F_WRLCK : F_RDLCK;
-		fl->fl_start = ntohl(*p++);
+		start = ntohl(*p++);
 		len = ntohl(*p++);
-		if (len == 0 || (fl->fl_end = fl->fl_start + len - 1) < 0)
-			fl->fl_end = NLM_OFFSET_MAX;
+		end = start + len - 1;
+
+		fl->fl_start = s32_to_loff_t(start);
+		if (len == 0 || end < 0)
+			fl->fl_end = OFFSET_MAX;
+		else
+			fl->fl_end = s32_to_loff_t(end);
 	}
 	return 0;
 }
@@ -487,7 +532,7 @@
 #define NLM_caller_sz		1+QUADLEN(sizeof(system_utsname.nodename))
 #define NLM_netobj_sz		1+QUADLEN(XDR_MAX_NETOBJ)
 /* #define NLM_owner_sz		1+QUADLEN(NLM_MAXOWNER) */
-#define NLM_fhandle_sz		1+QUADLEN(NFS_FHSIZE)
+#define NLM_fhandle_sz		1+QUADLEN(NFS2_FHSIZE)
 #define NLM_lock_sz		3+NLM_caller_sz+NLM_netobj_sz+NLM_fhandle_sz
 #define NLM_holder_sz		4+NLM_netobj_sz
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/xdr4.c linux/fs/lockd/xdr4.c
--- v2.3.99-pre3/linux/fs/lockd/xdr4.c	Fri Mar 10 16:40:47 2000
+++ linux/fs/lockd/xdr4.c	Mon Apr 10 23:02:45 2000
@@ -20,14 +20,25 @@
 #include <linux/lockd/sm_inter.h>
 
 #define NLMDBG_FACILITY		NLMDBG_XDR
-#define OFFSET_MAX		((off_t)LONG_MAX)
+
+static inline loff_t
+s64_to_loff_t(__s64 offset)
+{
+	return (loff_t)offset;
+}
 
 
-static inline off_t
-size_to_off_t(__s64 size)
+static inline s64
+loff_t_to_s64(loff_t offset)
 {
-        size = (size > (__s64)LONG_MAX) ? (off_t)LONG_MAX : (off_t) size;
-        return (size < (__s64)-LONG_MAX) ? (off_t)-LONG_MAX : (off_t) size;
+	s64 res;
+	if (offset > NLM4_OFFSET_MAX)
+		res = NLM4_OFFSET_MAX;
+	else if (offset < -NLM4_OFFSET_MAX)
+		res = -NLM4_OFFSET_MAX;
+	else
+		res = offset;
+	return res;
 }
 
 /*
@@ -73,36 +84,24 @@
 nlm4_decode_fh(u32 *p, struct nfs_fh *f)
 {
 	memset(f->data, 0, sizeof(f->data));
-#ifdef NFS_MAXFHSIZE
 	f->size = ntohl(*p++);
 	if (f->size > NFS_MAXFHSIZE) {
 		printk(KERN_NOTICE
-			"lockd: bad fhandle size %x (should be %d)\n",
+			"lockd: bad fhandle size %d (should be <=%d)\n",
 			f->size, NFS_MAXFHSIZE);
 		return NULL;
 	}
       	memcpy(f->data, p, f->size);
 	return p + XDR_QUADLEN(f->size);
-#else
-	if (ntohl(*p++) != NFS_FHSIZE)
-		return NULL; /* for now, all filehandles are 32 bytes */
-	memcpy(f->data, p, NFS_FHSIZE);
-	return p + XDR_QUADLEN(NFS_FHSIZE);
-#endif
 }
 
 static u32 *
 nlm4_encode_fh(u32 *p, struct nfs_fh *f)
 {
-#ifdef NFS_MAXFHSIZE
 	*p++ = htonl(f->size);
+	if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */
 	memcpy(p, f->data, f->size);
 	return p + XDR_QUADLEN(f->size);
-#else
-	*p++ = htonl(NFS_FHSIZE);
-	memcpy(p, f->data, NFS_FHSIZE);
-	return p + XDR_QUADLEN(NFS_FHSIZE);
-#endif
 }
 
 /*
@@ -141,11 +140,12 @@
 	p = xdr_decode_hyper(p, &len);
 	end = start + len - 1;
 
-	fl->fl_start = size_to_off_t(start);
-	fl->fl_end = size_to_off_t(end);
+	fl->fl_start = s64_to_loff_t(start);
 
-	if (len == 0 || fl->fl_end < 0)
+	if (len == 0 || end < 0)
 		fl->fl_end = OFFSET_MAX;
+	else
+		fl->fl_end = s64_to_loff_t(end);
 	return p;
 }
 
@@ -156,18 +156,26 @@
 nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
 {
 	struct file_lock	*fl = &lock->fl;
+	__s64			start, len;
 
 	if (!(p = xdr_encode_string(p, lock->caller))
 	 || !(p = nlm4_encode_fh(p, &lock->fh))
 	 || !(p = nlm4_encode_oh(p, &lock->oh)))
 		return NULL;
 
-	*p++ = htonl(fl->fl_pid);
-	p = xdr_encode_hyper(p, fl->fl_start);
+	if (fl->fl_start > NLM4_OFFSET_MAX
+	 || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
+		return NULL;
+
+	start = loff_t_to_s64(fl->fl_start);
 	if (fl->fl_end == OFFSET_MAX)
-		p = xdr_encode_hyper(p, 0);
+		len = 0;
 	else
-		p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
+		len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
+
+	*p++ = htonl(fl->fl_pid);
+	p = xdr_encode_hyper(p, start);
+	p = xdr_encode_hyper(p, len);
 
 	return p;
 }
@@ -178,6 +186,8 @@
 static u32 *
 nlm4_encode_testres(u32 *p, struct nlm_res *resp)
 {
+	s64		start, len;
+
 	dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
 		return 0;
@@ -193,12 +203,17 @@
 		if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
 			return 0;
 
-		p = xdr_encode_hyper(p, fl->fl_start);
+		start = loff_t_to_s64(fl->fl_start);
 		if (fl->fl_end == OFFSET_MAX)
-			p = xdr_encode_hyper(p, 0);
+			len = 0;
 		else
-			p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
-		dprintk("xdr: encode_testres (status %d pid %d type %d start %ld end %ld)\n", resp->status, fl->fl_pid, fl->fl_type, fl->fl_start,  fl->fl_end);
+			len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
+		
+		p = xdr_encode_hyper(p, start);
+		p = xdr_encode_hyper(p, len);
+		dprintk("xdr: encode_testres (status %d pid %d type %d start %Ld end %Ld)\n",
+			resp->status, fl->fl_pid, fl->fl_type,
+			(long long)fl->fl_start,  (long long)fl->fl_end);
 	}
 
 	dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
@@ -434,10 +449,11 @@
 		p = xdr_decode_hyper(p, &len);
 		end = start + len - 1;
 
-		fl->fl_start = size_to_off_t(start);
-		fl->fl_end = size_to_off_t(end);
-		if (len == 0 || fl->fl_end < 0)
+		fl->fl_start = s64_to_loff_t(start);
+		if (len == 0 || end < 0)
 			fl->fl_end = OFFSET_MAX;
+		else
+			fl->fl_end = s64_to_loff_t(end);
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/locks.c linux/fs/locks.c
--- v2.3.99-pre3/linux/fs/locks.c	Sun Feb 13 19:29:04 2000
+++ linux/fs/locks.c	Sun Apr  2 15:53:28 2000
@@ -111,8 +111,6 @@
 
 #include <asm/uaccess.h>
 
-#define OFFSET_MAX	((off_t)LONG_MAX)	/* FIXME: move elsewhere? */
-
 static int flock_make_lock(struct file *filp, struct file_lock *fl,
 			       unsigned int cmd);
 static int posix_make_lock(struct file *filp, struct file_lock *fl,
@@ -195,9 +193,9 @@
 
 	if (waiter->fl_prevblock) {
 		printk(KERN_ERR "locks_insert_block: remove duplicated lock "
-			"(pid=%d %ld-%ld type=%d)\n",
-			waiter->fl_pid, waiter->fl_start,
-			waiter->fl_end, waiter->fl_type);
+			"(pid=%d %Ld-%Ld type=%d)\n",
+			waiter->fl_pid, (long long)waiter->fl_start,
+			(long long)waiter->fl_end, waiter->fl_type);
 		locks_delete_block(waiter->fl_prevblock, waiter);
 	}
 
@@ -338,10 +336,6 @@
 	if (!filp)
 		goto out;
 
-	error = -EINVAL;
-	if (!filp->f_dentry || !filp->f_dentry->d_inode)
-		goto out_putf;
-
 	if (!posix_make_lock(filp, &file_lock, &flock))
 		goto out_putf;
 
@@ -385,7 +379,6 @@
 	struct file *filp;
 	struct file_lock file_lock;
 	struct flock flock;
-	struct dentry * dentry;
 	struct inode *inode;
 	int error;
 
@@ -405,10 +398,7 @@
 		goto out;
 
 	error = -EINVAL;
-	if (!(dentry = filp->f_dentry))
-		goto out_putf;
-	if (!(inode = dentry->d_inode))
-		goto out_putf;
+	inode = filp->f_dentry->d_inode;
 
 	/* Don't allow mandatory locks on files that may be memory mapped
 	 * and shared.
@@ -616,7 +606,7 @@
 		/* Block for writes against a "read" lock,
 		 * and both reads and writes against a "write" lock.
 		 */
-		if (posix_locks_conflict(fl, &tfl)) {
+		if (posix_locks_conflict(&tfl, fl)) {
 			error = -EAGAIN;
 			if (filp && (filp->f_flags & O_NONBLOCK))
 				break;
@@ -650,7 +640,7 @@
 static int posix_make_lock(struct file *filp, struct file_lock *fl,
 			   struct flock *l)
 {
-	off_t start;
+	loff_t start;
 
 	memset(fl, 0, sizeof(*fl));
 	
@@ -683,8 +673,11 @@
 
 	if (((start += l->l_start) < 0) || (l->l_len < 0))
 		return (0);
+	fl->fl_end = start + l->l_len - 1;
+	if (l->l_len > 0 && fl->fl_end < 0)
+		return (0);
 	fl->fl_start = start;	/* we record the absolute position */
-	if ((l->l_len == 0) || ((fl->fl_end = start + l->l_len - 1) < 0))
+	if (l->l_len == 0)
 		fl->fl_end = OFFSET_MAX;
 	
 	fl->fl_file = filp;
@@ -703,8 +696,6 @@
 	memset(fl, 0, sizeof(*fl));
 
 	init_waitqueue_head(&fl->fl_wait);
-	if (!filp->f_dentry)	/* just in case */
-		return (0);
 
 	switch (cmd & ~LOCK_NB) {
 	case LOCK_SH:
@@ -1128,6 +1119,8 @@
 		new->fl_start = fl->fl_start;
 		new->fl_end = fl->fl_end;
 		new->fl_notify = fl->fl_notify;
+		new->fl_insert = fl->fl_insert;
+		new->fl_remove = fl->fl_remove;
 		new->fl_u = fl->fl_u;
 	}
 	return new;
@@ -1146,6 +1139,9 @@
 	fl->fl_next = *pos;	/* insert into file's list */
 	*pos = fl;
 
+	if (fl->fl_insert)
+		fl->fl_insert(fl);
+
 	return;
 }
 
@@ -1173,6 +1169,9 @@
 		prevfl->fl_nextlink = nextfl;
 	else
 		file_lock_table = nextfl;
+
+	if (thisfl->fl_remove)
+		thisfl->fl_remove(thisfl);
 	
 	locks_wake_up_blocks(thisfl, wait);
 	locks_free_lock(thisfl);
@@ -1201,10 +1200,10 @@
 		p += sprintf(p, "FLOCK  ADVISORY  ");
 	}
 	p += sprintf(p, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
-	p += sprintf(p, "%d %s:%ld %ld %ld ",
+	p += sprintf(p, "%d %s:%ld %Ld %Ld ",
 		     fl->fl_pid,
-		     kdevname(inode->i_dev), inode->i_ino, fl->fl_start,
-		     fl->fl_end);
+		     kdevname(inode->i_dev), inode->i_ino,
+		     (long long)fl->fl_start, (long long)fl->fl_end);
 	sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n",
 		(long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
 		(long)fl->fl_next, (long)fl->fl_nextblock);
@@ -1212,7 +1211,7 @@
 }
 
 static inline int copy_lock_status(char *p, char **q, off_t pos, int len,
-				   off_t offset, off_t length)
+				   off_t offset, int length)
 {
 	off_t i;
 
@@ -1236,7 +1235,7 @@
 	return (1);
 }
 
-int get_locks_status(char *buffer, char **start, off_t offset, off_t length)
+int get_locks_status(char *buffer, char **start, off_t offset, int length)
 {
 	struct file_lock *fl;
 	struct file_lock *bfl;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/namei.c linux/fs/namei.c
--- v2.3.99-pre3/linux/fs/namei.c	Sun Mar 19 18:35:31 2000
+++ linux/fs/namei.c	Tue Apr 11 10:36:36 2000
@@ -192,31 +192,6 @@
 }
 
 /*
- * "." and ".." are special - ".." especially so because it has to be able
- * to know about the current root directory and parent relationships
- */
-static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * name)
-{
-	struct dentry *result = NULL;
-	if (name->name[0] == '.') {
-		switch (name->len) {
-		default:
-			break;
-		case 2:	
-			if (name->name[1] != '.')
-				break;
-
-			if (parent != current->fs->root)
-				parent = parent->d_covers->d_parent;
-			/* fallthrough */
-		case 1:
-			result = parent;
-		}
-	}
-	return dget(result);
-}
-
-/*
  * Internal lookup() using the new generic dcache.
  */
 static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
@@ -279,39 +254,28 @@
 	return result;
 }
 
-static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow)
+static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	struct inode * inode = dentry->d_inode;
-
-	if ((follow & LOOKUP_FOLLOW)
-	    && inode && inode->i_op && inode->i_op->follow_link) {
-		if (current->link_count < 32) {
-			struct dentry * result;
-
-			current->link_count++;
-			/* This eats the base */
-			result = inode->i_op->follow_link(dentry, base, follow);
-			current->link_count--;
-			dput(dentry);
-			return result;
-		}
-		dput(dentry);
-		dentry = ERR_PTR(-ELOOP);
-	}
-	dput(base);
-	return dentry;
+	int err;
+	if (current->link_count >= 32)
+		goto loop;
+	current->link_count++;
+	UPDATE_ATIME(dentry->d_inode);
+	err = dentry->d_inode->i_op->follow_link(dentry, nd);
+	current->link_count--;
+	return err;
+loop:
+	dput(nd->dentry);
+	mntput(nd->mnt);
+	return -ELOOP;
 }
 
-static inline struct dentry * follow_mount(struct dentry * dentry)
-{
-	struct dentry * mnt = dentry->d_mounts;
-
-	if (mnt != dentry) {
-		dget(mnt);
-		dput(dentry);
-		dentry = mnt;
-	}
-	return dentry;
+static inline int follow_down(struct dentry ** dentry, struct vfsmount **mnt)
+{
+	struct dentry * parent = dget((*dentry)->d_mounts);
+	dput(*dentry);
+	*dentry = parent;
+	return 1;
 }
 
 /*
@@ -319,36 +283,31 @@
  *
  * This is the basic name resolution function, turning a pathname
  * into the final dentry.
+ *
+ * We expect 'base' to be positive and a directory.
  */
-struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned int lookup_flags)
+int walk_name(const char * name, unsigned lookup_flags, struct nameidata *nd)
 {
-	struct dentry * dentry;
+	struct dentry *dentry;
 	struct inode *inode;
+	int err;
 
-	if (*name == '/') {
-		if (base)
-			dput(base);
-		do {
-			name++;
-		} while (*name == '/');
-		__prefix_lookup_dentry(name, lookup_flags);
-		base = dget(current->fs->root);
-	} else if (!base) {
-		base = dget(current->fs->pwd);
-	}
-
+	while (*name=='/')
+		name++;
 	if (!*name)
 		goto return_base;
 
-	inode = base->d_inode;
-	lookup_flags &= LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK;
+	inode = nd->dentry->d_inode;
+	if (current->link_count)
+		lookup_flags = LOOKUP_FOLLOW;
+
+	lookup_flags &= LOOKUP_FOLLOW | LOOKUP_DIRECTORY |
+			LOOKUP_SLASHOK | LOOKUP_POSITIVE | LOOKUP_PARENT;
 
 	/* At this point we know we have a real path component. */
 	for(;;) {
-		int err;
 		unsigned long hash;
 		struct qstr this;
-		unsigned int flags;
 		unsigned int c;
 
 		err = permission(inode, MAY_EXEC);
@@ -369,99 +328,240 @@
 		this.hash = end_name_hash(hash);
 
 		/* remove trailing slashes? */
-		flags = lookup_flags;
-		if (c) {
-			char tmp;
-
-			flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
-			do {
-				tmp = *++name;
-			} while (tmp == '/');
-			if (tmp)
-				flags |= LOOKUP_CONTINUE;
-		}
+		if (!c)
+			goto last_component;
+		while (*++name == '/');
+		if (!*name)
+			goto last_with_slashes;
 
 		/*
+		 * "." and ".." are special - ".." especially so because it has
+		 * to be able to know about the current root directory and
+		 * parent relationships.
+		 */
+		if (this.name[0] == '.') switch (this.len) {
+			default:
+				break;
+			case 2:	
+				if (this.name[1] != '.')
+					break;
+				if (nd->dentry != current->fs->root) {
+					dentry = dget(nd->dentry->d_covers->d_parent);
+					dput(nd->dentry);
+					nd->dentry = dentry;
+					inode = dentry->d_inode;
+				}
+				/* fallthrough */
+			case 1:
+				continue;
+		}
+		/*
 		 * See if the low-level filesystem might want
 		 * to use its own hash..
 		 */
-		if (base->d_op && base->d_op->d_hash) {
-			int error;
-			error = base->d_op->d_hash(base, &this);
-			if (error < 0) {
-				dentry = ERR_PTR(error);
+		if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
+			err = nd->dentry->d_op->d_hash(nd->dentry, &this);
+			if (err < 0)
 				break;
-			}
 		}
-
 		/* This does the actual lookups.. */
-		dentry = reserved_lookup(base, &this);
+		dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
 		if (!dentry) {
-			dentry = cached_lookup(base, &this, flags);
-			if (!dentry) {
-				dentry = real_lookup(base, &this, flags);
-				if (IS_ERR(dentry))
-					break;
-			}
-
-			/* Check mountpoints.. */
-			dentry = follow_mount(dentry);
+			dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
+			err = PTR_ERR(dentry);
+			if (IS_ERR(dentry))
+				break;
 		}
+		/* Check mountpoints.. */
+		while (d_mountpoint(dentry) && follow_down(&dentry, &nd->mnt))
+			;
+
+		err = -ENOENT;
+		inode = dentry->d_inode;
+		if (!inode)
+			break;
+		err = -ENOTDIR; 
+		if (!inode->i_op)
+			break;
 
-		base = do_follow_link(base, dentry, flags);
-		if (IS_ERR(base))
-			goto return_base;
-
-		inode = base->d_inode;
-		if (flags & LOOKUP_DIRECTORY) {
+		if (inode->i_op->follow_link) {
+			err = do_follow_link(dentry, nd);
+			dput(dentry);
+			if (err)
+				goto return_err;
+			err = -ENOENT;
+			inode = nd->dentry->d_inode;
 			if (!inode)
-				goto no_inode;
-			dentry = ERR_PTR(-ENOTDIR); 
+				break;
+			err = -ENOTDIR; 
+			if (!inode->i_op)
+				break;
+		} else {
+			dput(nd->dentry);
+			nd->dentry = dentry;
+		}
+		err = -ENOTDIR; 
+		if (!inode->i_op->lookup)
+			break;
+		continue;
+		/* here ends the main loop */
+
+last_with_slashes:
+		lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+last_component:
+		if (lookup_flags & LOOKUP_PARENT)
+			goto lookup_parent;
+		if (this.name[0] == '.') switch (this.len) {
+			default:
+				break;
+			case 2:	
+				if (this.name[1] != '.')
+					break;
+				if (nd->dentry != current->fs->root) {
+					dentry = dget(nd->dentry->d_covers->d_parent);
+					dput(nd->dentry);
+					nd->dentry = dentry;
+					inode = dentry->d_inode;
+				}
+				/* fallthrough */
+			case 1:
+				goto return_base;
+		}
+		if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
+			err = nd->dentry->d_op->d_hash(nd->dentry, &this);
+			if (err < 0)
+				break;
+		}
+		dentry = cached_lookup(nd->dentry, &this, 0);
+		if (!dentry) {
+			dentry = real_lookup(nd->dentry, &this, 0);
+			err = PTR_ERR(dentry);
+			if (IS_ERR(dentry))
+				break;
+		}
+		while (d_mountpoint(dentry) && follow_down(&dentry, &nd->mnt))
+			;
+		inode = dentry->d_inode;
+		if ((lookup_flags & LOOKUP_FOLLOW)
+		    && inode && inode->i_op && inode->i_op->follow_link) {
+			err = do_follow_link(dentry, nd);
+			dput(dentry);
+			if (err)
+				goto return_err;
+			inode = nd->dentry->d_inode;
+		} else {
+			dput(nd->dentry);
+			nd->dentry = dentry;
+		}
+		err = -ENOENT;
+		if (!inode)
+			goto no_inode;
+		if (lookup_flags & LOOKUP_DIRECTORY) {
+			err = -ENOTDIR; 
 			if (!inode->i_op || !inode->i_op->lookup)
 				break;
-			if (flags & LOOKUP_CONTINUE)
-				continue;
 		}
-return_base:
-		return base;
-/*
- * The case of a nonexisting file is special.
- *
- * In the middle of a pathname lookup (ie when
- * LOOKUP_CONTINUE is set), it's an obvious
- * error and returns ENOENT.
- *
- * At the end of a pathname lookup it's legal,
- * and we return a negative dentry. However, we
- * get here only if there were trailing slashes,
- * which is legal only if we know it's supposed
- * to be a directory (ie "mkdir"). Thus the
- * LOOKUP_SLASHOK flag.
- */
+		goto return_base;
 no_inode:
-		dentry = ERR_PTR(-ENOENT);
-		if (flags & LOOKUP_CONTINUE)
+		err = -ENOENT;
+		if (lookup_flags & LOOKUP_POSITIVE)
 			break;
-		if (flags & LOOKUP_SLASHOK)
-			goto return_base;
-		break;
+		if (lookup_flags & LOOKUP_DIRECTORY)
+			if (!(lookup_flags & LOOKUP_SLASHOK))
+				break;
+		goto return_base;
+lookup_parent:
+		nd->last = this;
+return_base:
+		return 0;
 	}
-	dput(base);
-	return dentry;
+	dput(nd->dentry);
+	mntput(nd->mnt);
+return_err:
+	return err;
+}
+
+/* returns 1 if everything is done */
+static int __emul_lookup_dentry(const char *name, int lookup_flags,
+		struct nameidata *nd)
+{
+	char *emul = __emul_prefix();
+
+	if (!emul)
+		return 0;
+
+	nd->mnt = mntget(current->fs->rootmnt);
+	nd->dentry = dget(current->fs->root);
+	if (walk_name(emul,LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_POSITIVE,nd))
+		return 0;
+	if (walk_name(name, lookup_flags, nd))
+		return 0;
+
+	if (!nd->dentry->d_inode) {
+		struct nameidata nd_root;
+		nd_root.last.len = 0;
+		nd_root.mnt = mntget(current->fs->rootmnt);
+		nd_root.dentry = dget(current->fs->root);
+		if (walk_name(name, lookup_flags, &nd_root))
+			return 1;
+		if (nd_root.dentry->d_inode) {
+			dput(nd->dentry);
+			mntput(nd->mnt);
+			nd->dentry = nd_root.dentry;
+			nd->mnt = nd_root.mnt;
+			nd->last = nd_root.last;
+			return 1;
+		}
+		dput(nd_root.dentry);
+		mntput(nd_root.mnt);
+	}
+	return 1;
+}
+
+static inline int
+walk_init_root(const char *name, unsigned flags, struct nameidata *nd)
+{
+	if (current->personality != PER_LINUX)
+		if (__emul_lookup_dentry(name,flags,nd));
+			return 0;
+	nd->mnt = mntget(current->fs->rootmnt);
+	nd->dentry = dget(current->fs->root);
+	return 1;
+}
+
+int walk_init(const char *name,unsigned int flags,struct nameidata *nd)
+{
+	nd->last.len = 0;
+	if (*name=='/')
+		return walk_init_root(name,flags,nd);
+	nd->mnt = mntget(current->fs->pwdmnt);
+	nd->dentry = dget(current->fs->pwd);
+	return 1;
+}
+
+struct dentry * lookup_dentry(const char * name, unsigned int lookup_flags)
+{
+	struct nameidata nd;
+	int err = 0;
+
+	if (walk_init(name, lookup_flags, &nd))
+		err = walk_name(name, lookup_flags, &nd);
+	if (!err) {
+		mntput(nd.mnt);
+		return nd.dentry;
+	}
+	return ERR_PTR(err);
 }
 
 /*
  * Restricted form of lookup. Doesn't follow links, single-component only,
  * needs parent already locked. Doesn't follow mounts.
  */
-struct dentry * lookup_one(const char * name, struct dentry * base)
+static inline struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
 {
 	struct dentry * dentry;
 	struct inode *inode;
 	int err;
-	unsigned long hash;
-	struct qstr this;
-	unsigned int c;
 
 	inode = base->d_inode;
 	err = permission(inode, MAY_EXEC);
@@ -469,36 +569,20 @@
 	if (err)
 		goto out;
 
-	this.name = name;
-	c = *(const unsigned char *)name;
-	if (!c)
-		goto access;
-
-	hash = init_name_hash();
-	do {
-		name++;
-		if (c == '/')
-			goto access;
-		hash = partial_name_hash(c, hash);
-		c = *(const unsigned char *)name;
-	} while (c);
-	this.len = name - (const char *) this.name;
-	this.hash = end_name_hash(hash);
-
 	/*
 	 * See if the low-level filesystem might want
 	 * to use its own hash..
 	 */
 	if (base->d_op && base->d_op->d_hash) {
-		err = base->d_op->d_hash(base, &this);
+		err = base->d_op->d_hash(base, name);
 		dentry = ERR_PTR(err);
 		if (err < 0)
 			goto out;
 	}
 
-	dentry = cached_lookup(base, &this, 0);
+	dentry = cached_lookup(base, name, 0);
 	if (!dentry) {
-		struct dentry *new = d_alloc(base, &this);
+		struct dentry *new = d_alloc(base, name);
 		dentry = ERR_PTR(-ENOMEM);
 		if (!new)
 			goto out;
@@ -515,9 +599,33 @@
 out:
 	dput(base);
 	return dentry;
+}
+
+struct dentry * lookup_one(const char * name, struct dentry * base)
+{
+	unsigned long hash;
+	struct qstr this;
+	unsigned int c;
+
+	this.name = name;
+	c = *(const unsigned char *)name;
+	if (!c)
+		goto access;
+
+	hash = init_name_hash();
+	do {
+		name++;
+		if (c == '/')
+			goto access;
+		hash = partial_name_hash(c, hash);
+		c = *(const unsigned char *)name;
+	} while (c);
+	this.len = name - (const char *) this.name;
+	this.hash = end_name_hash(hash);
+
+	return lookup_hash(&this, base);
 access:
-	dentry = ERR_PTR(-EACCES);
-	goto out;
+	return ERR_PTR(-EACCES);
 }
 
 /*
@@ -538,14 +646,8 @@
 	name = getname(pathname);
 	dentry = (struct dentry *) name;
 	if (!IS_ERR(name)) {
-		dentry = lookup_dentry(name, NULL, lookup_flags);
+		dentry = lookup_dentry(name,lookup_flags|LOOKUP_POSITIVE);
 		putname(name);
-		if (!IS_ERR(dentry)) {
-			if (!dentry->d_inode) {
-				dput(dentry);
-				dentry = ERR_PTR(-ENOENT);
-			}
-		}
 	}
 	return dentry;
 }
@@ -600,7 +702,7 @@
 			return -ENOTDIR;
 		if (IS_ROOT(victim))
 			return -EBUSY;
-		if (victim->d_mounts != victim->d_covers)
+		if (d_mountpoint(victim))
 			return -EBUSY;
 	} else if (S_ISDIR(victim->d_inode->i_mode))
 		return -EISDIR;
@@ -639,7 +741,7 @@
 	
 	if (f & O_DIRECTORY)
 		retval |= LOOKUP_DIRECTORY;
-	
+
 	return retval;
 }
 
@@ -679,64 +781,92 @@
  * which is a lot more logical, and also allows the "no perm" needed
  * for symlinks (where the permissions are checked later).
  */
-struct dentry * __open_namei(const char * pathname, int flag, int mode, struct dentry * dir)
+int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
 {
-	int acc_mode, error;
+	int acc_mode, error = 0;
 	struct inode *inode;
 	struct dentry *dentry;
 
-	dentry = lookup_dentry(pathname, dir, lookup_flags(flag));
-	if (IS_ERR(dentry))
-		return dentry;
-
 	acc_mode = ACC_MODE(flag);
-	if (flag & O_CREAT) {
+	if (!(flag & O_CREAT)) {
+		if (walk_init(pathname, lookup_flags(flag), nd))
+			error = walk_name(pathname, lookup_flags(flag), nd);
+		if (error)
+			return error;
+
+		dentry = nd->dentry;
+	} else {
 		struct dentry *dir;
 
-		if (dentry->d_inode) {
-			if (!(flag & O_EXCL))
-				goto nocreate;
-			error = -EEXIST;
+		if (walk_init(pathname, LOOKUP_PARENT, nd))
+			error = walk_name(pathname, LOOKUP_PARENT, nd);
+		if (error)
+			return error;
+		/*
+		 * It's not obvious that open(".", O_CREAT, foo) should
+		 * fail, but it's even less obvious that it should succeed.
+		 * Since O_CREAT means an intention to create the thing and
+		 * open(2) had never created directories, count it as caller's
+		 * luserdom and let him sod off - -EISDIR it is.
+		 */
+		error = -EISDIR;
+		if (!nd->last.len || (nd->last.name[0] == '.' &&
+		     (nd->last.len == 1 ||
+		      (nd->last.name[1] == '.' && nd->last.len == 2))))
+			goto exit;
+		/* same for foo/ */
+		if (nd->last.name[nd->last.len])
 			goto exit;
-		}
 
-		dir = lock_parent(dentry);
-		if (!check_parent(dir, dentry)) {
-			/*
-			 * Really nasty race happened. What's the 
-			 * right error code? We had a dentry, but
-			 * before we could use it it was removed
-			 * by somebody else. We could just re-try
-			 * everything, I guess.
-			 *
-			 * ENOENT is definitely wrong.
-			 */
-			error = -ENOENT;
-			unlock_dir(dir);
+		dir = dget(nd->dentry);
+		down(&dir->d_inode->i_sem);
+
+		dentry = lookup_hash(&nd->last, dget(nd->dentry));
+		error = PTR_ERR(dentry);
+		if (IS_ERR(dentry)) {
+			up(&dir->d_inode->i_sem);
+			dput(dir);
 			goto exit;
 		}
 
-		/*
-		 * Somebody might have created the file while we
-		 * waited for the directory lock.. So we have to
-		 * re-do the existence test.
-		 */
 		if (dentry->d_inode) {
-			error = 0;
+			up(&dir->d_inode->i_sem);
+			dput(dir);
+			error = -EEXIST;
 			if (flag & O_EXCL)
-				error = -EEXIST;
+				goto exit;
+			if (dentry->d_inode->i_op &&
+			    dentry->d_inode->i_op->follow_link) {
+				/*
+				 * With O_EXCL it would be -EEXIST.
+				 * If symlink is a dangling one it's -ENOENT.
+				 * Otherwise we open the object it points to.
+				 */
+				error = do_follow_link(dentry, nd);
+				dput(dentry);
+				if (error)
+					return error;
+				dentry = nd->dentry;
+			} else {
+				dput(nd->dentry);
+				nd->dentry = dentry;
+			}
+			error = -EISDIR;
+			if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
+				goto exit;
 		} else {
-			error = vfs_create(dir->d_inode, dentry,mode);
+			error = vfs_create(dir->d_inode, dentry, mode);
 			/* Don't check for write permission, don't truncate */
 			acc_mode = 0;
 			flag &= ~O_TRUNC;
+			dput(nd->dentry);
+			nd->dentry = dentry;
+			unlock_dir(dir);
+			if (error)
+				goto exit;
 		}
-		unlock_dir(dir);
-		if (error)
-			goto exit;
 	}
 
-nocreate:
 	error = -ENOENT;
 	inode = dentry->d_inode;
 	if (!inode)
@@ -804,11 +934,45 @@
 		if (flag & FMODE_WRITE)
 			DQUOT_INIT(inode);
 
-	return dentry;
+	return 0;
 
 exit:
+	dput(nd->dentry);
+	mntput(nd->mnt);
+	return error;
+}
+
+static struct dentry *lookup_create(const char *name, int is_dir)
+{
+	struct nameidata nd;
+	struct dentry *dentry;
+	int err = 0;
+	if (walk_init(name, LOOKUP_PARENT, &nd))
+		err = walk_name(name, LOOKUP_PARENT, &nd);
+	dentry = ERR_PTR(err);
+	if (err)
+		goto out;
+	down(&nd.dentry->d_inode->i_sem);
+	dentry = ERR_PTR(-EEXIST);
+	if (!nd.last.len || (nd.last.name[0] == '.' &&
+	      (nd.last.len == 1 || (nd.last.name[1] == '.' && nd.last.len == 2))))
+		goto fail;
+	dentry = lookup_hash(&nd.last, dget(nd.dentry));
+	if (IS_ERR(dentry))
+		goto fail;
+	if (!is_dir && nd.last.name[nd.last.len] && !dentry->d_inode)
+		goto enoent;
+out_dput:
+	dput(nd.dentry);
+	mntput(nd.mnt);
+out:
+	return dentry;
+enoent:
 	dput(dentry);
-	return ERR_PTR(error);
+	dentry = ERR_PTR(-ENOENT);
+fail:
+	up(&nd.dentry->d_inode->i_sem);
+	goto out_dput;
 }
 
 int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
@@ -842,18 +1006,14 @@
 	struct dentry *dir;
 	struct dentry *dentry, *retval;
 
-	dentry = lookup_dentry(filename, NULL, 0);
+	dentry = lookup_create(filename, 0);
 	if (IS_ERR(dentry))
 		return dentry;
 
-	dir = lock_parent(dentry);
-	error = -ENOENT;
-	if (!check_parent(dir, dentry))
-		goto exit_lock;
+	dir = dget(dentry->d_parent);
 
 	error = vfs_mknod(dir->d_inode, dentry, mode, dev);
 
-exit_lock:
 	retval = ERR_PTR(error);
 	if (!error)
 		retval = dget(dentry);
@@ -875,14 +1035,11 @@
 		return PTR_ERR(tmp);
 
 	lock_kernel();
-	dentry = lookup_dentry(tmp, NULL, 0);
+	dentry = lookup_create(tmp, 0);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto out;
-	dir = lock_parent(dentry);
-	error = -ENOENT;
-	if (!check_parent(dir, dentry))
-		goto out_unlock;
+	dir = dget(dentry->d_parent);
 	switch (mode & S_IFMT) {
 	case 0: case S_IFREG:
 		error = vfs_create(dir->d_inode, dentry, mode);
@@ -896,7 +1053,6 @@
 	default:
 		error = -EINVAL;
 	}
-out_unlock:
 	unlock_dir(dir);
 	dput(dentry);
 out:
@@ -928,50 +1084,28 @@
 	return error;
 }
 
-static inline int do_mkdir(const char * pathname, int mode)
-{
-	int error;
-	struct dentry *dir;
-	struct dentry *dentry;
-
-	dentry = lookup_dentry(pathname, NULL, LOOKUP_SLASHOK);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		goto exit;
-
-	/*
-	 * EEXIST is kind of a strange error code to
-	 * return, but basically if the dentry was moved
-	 * or unlinked while we locked the parent, we
-	 * do know that it _did_ exist before, and as
-	 * such it makes perfect sense.. In contrast,
-	 * ENOENT doesn't make sense for mkdir.
-	 */
-	dir = lock_parent(dentry);
-	error = -EEXIST;
-	if (!check_parent(dir, dentry))
-		goto exit_lock;
-
-	error = vfs_mkdir(dir->d_inode, dentry, mode);
-
-exit_lock:
-	unlock_dir(dir);
-	dput(dentry);
-exit:
-	return error;
-}
-
 asmlinkage long sys_mkdir(const char * pathname, int mode)
 {
 	int error;
 	char * tmp;
 
 	tmp = getname(pathname);
-	if(IS_ERR(tmp))
-		return PTR_ERR(tmp);
-	lock_kernel();
-	error = do_mkdir(tmp,mode);
-	unlock_kernel();
+	error = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		struct dentry *dir;
+		struct dentry *dentry;
+
+		lock_kernel();
+		dentry = lookup_create(tmp, 1);
+		error = PTR_ERR(dentry);
+		if (!IS_ERR(dentry)) {
+			dir = dget(dentry->d_parent);
+			error = vfs_mkdir(dir->d_inode, dentry, mode);
+			unlock_dir(dir);
+			dput(dentry);
+		}
+		unlock_kernel();
+	}
 	putname(tmp);
 
 	return error;
@@ -1033,7 +1167,7 @@
 	struct dentry *dir;
 	struct dentry *dentry;
 
-	dentry = lookup_dentry(name, NULL, 0);
+	dentry = lookup_dentry(name, LOOKUP_POSITIVE);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto exit;
@@ -1082,13 +1216,13 @@
 	return error;
 }
 
-int do_unlink(const char * name, struct dentry * base)
+static int do_unlink(const char * name)
 {
 	int error;
 	struct dentry *dir;
 	struct dentry *dentry;
 
-	dentry = lookup_dentry(name, base, 0);
+	dentry = lookup_dentry(name, LOOKUP_POSITIVE);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto exit;
@@ -1113,7 +1247,7 @@
 	if(IS_ERR(tmp))
 		return PTR_ERR(tmp);
 	lock_kernel();
-	error = do_unlink(tmp, NULL);
+	error = do_unlink(tmp);
 	unlock_kernel();
 	putname(tmp);
 
@@ -1141,32 +1275,6 @@
 	return error;
 }
 
-static inline int do_symlink(const char * oldname, const char * newname)
-{
-	int error;
-	struct dentry *dir;
-	struct dentry *dentry;
-
-	dentry = lookup_dentry(newname, NULL, 0);
-
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		goto exit;
-
-	dir = lock_parent(dentry);
-	error = -ENOENT;
-	if (!check_parent(dir, dentry))
-		goto exit_lock;
-
-	error = vfs_symlink(dir->d_inode, dentry, oldname);
-
-exit_lock:
-	unlock_dir(dir);
-	dput(dentry);
-exit:
-	return error;
-}
-
 asmlinkage long sys_symlink(const char * oldname, const char * newname)
 {
 	int error;
@@ -1179,8 +1287,18 @@
 	to = getname(newname);
 	error = PTR_ERR(to);
 	if (!IS_ERR(to)) {
+		struct dentry *dir;
+		struct dentry *dentry;
+
 		lock_kernel();
-		error = do_symlink(from,to);
+		dentry = lookup_create(to, 0);
+		error = PTR_ERR(dentry);
+		if (!IS_ERR(dentry)) {
+			dir = dget(dentry->d_parent);
+			error = vfs_symlink(dir->d_inode, dentry, from);
+			unlock_dir(dir);
+			dput(dentry);
+		}
 		unlock_kernel();
 		putname(to);
 	}
@@ -1224,51 +1342,20 @@
 	return error;
 }
 
-static inline int do_link(const char * oldname, const char * newname)
-{
-	struct dentry *old_dentry, *new_dentry, *dir;
-	int error;
-
-	/*
-	 * Hardlinks are often used in delicate situations.  We avoid
-	 * security-related surprises by not following symlinks on the
-	 * newname.  --KAB
-	 *
-	 * We don't follow them on the oldname either to be compatible
-	 * with linux 2.0, and to avoid hard-linking to directories
-	 * and other special files.  --ADM
-	 */
-	old_dentry = lookup_dentry(oldname, NULL, 0);
-	error = PTR_ERR(old_dentry);
-	if (IS_ERR(old_dentry))
-		goto exit;
-
-	new_dentry = lookup_dentry(newname, NULL, 0);
-	error = PTR_ERR(new_dentry);
-	if (IS_ERR(new_dentry))
-		goto exit_old;
-
-	dir = lock_parent(new_dentry);
-	error = -ENOENT;
-	if (!check_parent(dir, new_dentry))
-		goto exit_lock;
-
-	error = vfs_link(old_dentry, dir->d_inode, new_dentry);
-
-exit_lock:
-	unlock_dir(dir);
-	dput(new_dentry);
-exit_old:
-	dput(old_dentry);
-exit:
-	return error;
-}
-
+/*
+ * Hardlinks are often used in delicate situations.  We avoid
+ * security-related surprises by not following symlinks on the
+ * newname.  --KAB
+ *
+ * We don't follow them on the oldname either to be compatible
+ * with linux 2.0, and to avoid hard-linking to directories
+ * and other special files.  --ADM
+ */
 asmlinkage long sys_link(const char * oldname, const char * newname)
 {
 	int error;
 	char * from;
-		char * to;
+	char * to;
 
 	from = getname(oldname);
 	if(IS_ERR(from))
@@ -1276,8 +1363,24 @@
 	to = getname(newname);
 	error = PTR_ERR(to);
 	if (!IS_ERR(to)) {
+		struct dentry *old_dentry, *new_dentry, *dir;
+
 		lock_kernel();
-		error = do_link(from,to);
+		old_dentry = lookup_dentry(from, LOOKUP_POSITIVE);
+		error = PTR_ERR(old_dentry);
+		if (IS_ERR(old_dentry))
+			goto exit;
+
+		new_dentry = lookup_create(to, 0);
+		error = PTR_ERR(new_dentry);
+		if (!IS_ERR(new_dentry)) {
+			dir = dget(new_dentry->d_parent);
+			error = vfs_link(old_dentry, dir->d_inode, new_dentry);
+			unlock_dir(dir);
+			dput(new_dentry);
+		}
+		dput(old_dentry);
+exit:
 		unlock_kernel();
 		putname(to);
 	}
@@ -1435,21 +1538,17 @@
 	struct dentry * old_dir, * new_dir;
 	struct dentry * old_dentry, *new_dentry;
 
-	old_dentry = lookup_dentry(oldname, NULL, 0);
+	old_dentry = lookup_dentry(oldname, LOOKUP_POSITIVE);
 
 	error = PTR_ERR(old_dentry);
 	if (IS_ERR(old_dentry))
 		goto exit;
 
-	error = -ENOENT;
-	if (!old_dentry->d_inode)
-		goto exit_old;
-
 	{
 		unsigned int flags = 0;
 		if (S_ISDIR(old_dentry->d_inode->i_mode))
 			flags = LOOKUP_SLASHOK;
-		new_dentry = lookup_dentry(newname, NULL, flags);
+		new_dentry = lookup_dentry(newname, flags);
 	}
 
 	error = PTR_ERR(new_dentry);
@@ -1512,29 +1611,30 @@
 	return len;
 }
 
-static inline struct dentry *
-__vfs_follow_link(struct dentry *dentry, struct dentry *base,
-		unsigned follow, const char *link)
+static inline int
+__vfs_follow_link(struct nameidata *nd, const char *link)
 {
-	struct dentry *result;
-	UPDATE_ATIME(dentry->d_inode);
-
 	if (IS_ERR(link))
 		goto fail;
 
-	result = lookup_dentry(link, base, follow);
-	return result;
+	if (*link == '/') {
+		dput(nd->dentry);
+		mntput(nd->mnt);
+		if (!walk_init_root(link, LOOKUP_FOLLOW, nd))
+			/* weird __emul_prefix() stuff did it */
+			return 0;
+	}
+	return walk_name(link, LOOKUP_FOLLOW, nd);
 
 fail:
-	dput(base);
-	return (struct dentry *)link;
+	dput(nd->dentry);
+	mntput(nd->mnt);
+	return PTR_ERR(link);
 }
 
-struct dentry *
-vfs_follow_link(struct dentry *dentry, struct dentry *base,
-unsigned int follow, const char *link)
+int vfs_follow_link(struct nameidata *nd, const char *link)
 {
-	return __vfs_follow_link(dentry,base,follow,link);
+	return __vfs_follow_link(nd, link);
 }
 
 /* get the link contents into pagecache */
@@ -1572,12 +1672,11 @@
 	return res;
 }
 
-struct dentry *
-page_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
+int page_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct page *page = NULL;
 	char *s = page_getlink(dentry, &page);
-	struct dentry *res = __vfs_follow_link(dentry,base,follow,s);
+	int res = __vfs_follow_link(nd, s);
 	if (page) {
 		kunmap(page);
 		page_cache_release(page);
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/ncpfs/Config.in linux/fs/ncpfs/Config.in
--- v2.3.99-pre3/linux/fs/ncpfs/Config.in	Wed Dec  8 14:11:27 1999
+++ linux/fs/ncpfs/Config.in	Mon Mar 27 09:39:22 2000
@@ -1,13 +1,13 @@
 #
 # NCP Filesystem configuration
 #
-bool '  Packet signatures' CONFIG_NCPFS_PACKET_SIGNING
-bool '  Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING
-bool '  Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG
-bool '  Use NFS namespace if available' CONFIG_NCPFS_NFS_NS
-bool '  Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS
-bool '  Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS
-bool '  Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR
-bool '  NDS authentication support' CONFIG_NCPFS_NDS_DOMAINS
-bool '  Use Native Language Support' CONFIG_NCPFS_NLS
-bool '  Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS
+dep_mbool '  Packet signatures' CONFIG_NCPFS_PACKET_SIGNING $CONFIG_NCP_FS
+dep_mbool '  Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING $CONFIG_NCP_FS
+dep_mbool '  Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG $CONFIG_NCP_FS
+dep_mbool '  Use NFS namespace if available' CONFIG_NCPFS_NFS_NS $CONFIG_NCP_FS
+dep_mbool '  Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS $CONFIG_NCP_FS
+dep_mbool '  Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS $CONFIG_NCP_FS
+dep_mbool '  Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR $CONFIG_NCP_FS
+dep_mbool '  NDS authentication support' CONFIG_NCPFS_NDS_DOMAINS $CONFIG_NCP_FS
+dep_mbool '  Use Native Language Support' CONFIG_NCPFS_NLS $CONFIG_NCP_FS
+dep_mbool '  Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS $CONFIG_NCP_FS
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/Makefile linux/fs/nfs/Makefile
--- v2.3.99-pre3/linux/fs/nfs/Makefile	Mon Mar 27 08:08:29 2000
+++ linux/fs/nfs/Makefile	Sat Apr  1 08:04:27 2000
@@ -14,6 +14,9 @@
 ifdef CONFIG_ROOT_NFS
   O_OBJS += nfsroot.o mount_clnt.o
 endif
+ifdef CONFIG_NFS_V3
+  O_OBJS += nfs3proc.o nfs3xdr.o
+endif
 
 M_OBJS   := $(O_TARGET)
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.3.99-pre3/linux/fs/nfs/dir.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/nfs/dir.c	Sat Apr  1 08:04:27 2000
@@ -17,7 +17,6 @@
  *  6 Jun 1999	Cache readdir lookups in the page cache. -DaveM
  */
 
-#define NFS_NEED_XDR_TYPES
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/stat.h>
@@ -28,7 +27,7 @@
 #include <linux/mm.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
-#include <linux/nfs.h>
+#include <linux/nfs_mount.h>
 #include <linux/pagemap.h>
 
 #include <asm/segment.h>	/* for fs functions */
@@ -71,202 +70,131 @@
 	setattr:	nfs_notify_change,
 };
 
-/* Each readdir response is composed of entries which look
- * like the following, as per the NFSv2 RFC:
- *
- *	__u32	not_end			zero if end of response
- *	__u32	file ID			opaque ino_t
- *	__u32	namelen			size of name string
- *	VAR	name string		the string, padded to modulo 4 bytes
- *	__u32	cookie			opaque ID of next entry
- *
- * When you hit not_end being zero, the next __u32 is non-zero if
- * this is the end of the complete set of readdir entires for this
- * directory.  This can be used, for example, to initiate pre-fetch.
- *
- * In order to know what to ask the server for, we only need to know
- * the final cookie of the previous page, and offset zero has cookie
- * zero, so we cache cookie to page offset translations in chunks.
- */
-#define COOKIES_PER_CHUNK (8 - ((sizeof(void *) / sizeof(__u32))))
-struct nfs_cookie_table {
-	struct nfs_cookie_table *next;
-	__u32	cookies[COOKIES_PER_CHUNK];
-};
-static kmem_cache_t *nfs_cookie_cachep;
+typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
 
-/* This whole scheme relies on the fact that dirent cookies
- * are monotonically increasing.
- *
- * Another invariant is that once we have a valid non-zero
- * EOF marker cached, we also have the complete set of cookie
- * table entries.
+/*
+ * Given a pointer to a buffer that has already been filled by a call
+ * to readdir, find the next entry.
  *
- * We return the page offset assosciated with the page where
- * cookie must be if it exists at all, however if we can not
- * figure that out conclusively, we return < 0.
- */
-static long __nfs_readdir_offset(struct inode *inode, __u32 cookie)
-{
-	struct nfs_cookie_table *p;
-	unsigned long ret = 0;
-
-	for(p = NFS_COOKIES(inode); p != NULL; p = p->next) {
-		int i;
-
-		for (i = 0; i < COOKIES_PER_CHUNK; i++) {
-			__u32 this_cookie = p->cookies[i];
-
-			/* End of known cookies, EOF is our only hope. */
-			if (!this_cookie)
-				goto check_eof;
-
-			/* Next cookie is larger, must be in previous page. */
-			if (this_cookie > cookie)
-				return ret;
-
-			ret += 1;
-
-			/* Exact cookie match, it must be in this page :-) */
-			if (this_cookie == cookie)
-				return ret;
+ * If the end of the buffer has been reached, return -EAGAIN, if not,
+ * return the offset within the buffer of the next entry to be
+ * read.
+ */
+static inline
+long find_dirent(struct page *page, loff_t offset,
+		 struct nfs_entry *entry,
+		 decode_dirent_t decode, int plus, int use_cookie)
+{
+	u8		*p = (u8 *)kmap(page),
+			*start = p;
+	unsigned long	base = page_offset(page),
+			pg_offset = 0;
+	int		loop_count = 0;
+
+	if (!p)
+		return -EIO;
+	for(;;) {
+		p = (u8*)decode((__u32*)p, entry, plus);
+		if (IS_ERR(p))
+			break;
+		pg_offset = p - start;
+		entry->prev = entry->offset;
+		entry->offset = base + pg_offset;
+		if ((use_cookie ? entry->cookie : entry->offset) > offset)
+			break;
+		if (loop_count++ > 200) {
+			loop_count = 0;
+			schedule();
 		}
 	}
-check_eof:
-	if (NFS_DIREOF(inode) != 0)
-		return ret;
-
-	return -1L;
-}
 
-static __inline__ long nfs_readdir_offset(struct inode *inode, __u32 cookie)
-{
-	/* Cookie zero is always at page offset zero.   Optimize the
-	 * other common case since most directories fit entirely
-	 * in one page.
-	 */
-	if (!cookie || (!NFS_COOKIES(inode) && NFS_DIREOF(inode)))
-		return 0;
-	return __nfs_readdir_offset(inode, cookie);
+	kunmap(page);
+	return (IS_ERR(p)) ?  PTR_ERR(p) : (long)pg_offset;
 }
 
-/* Since a cookie of zero is declared special by the NFS
- * protocol, we easily can tell if a cookie in an existing
- * table chunk is valid or not.
+/*
+ * Find the given page, and call find_dirent() in order to try to
+ * return the next entry.
  *
- * NOTE: The cookies are indexed off-by-one because zero
- *       need not an entry.
+ * Returns -EIO if the page is not available, or up to date.
  */
-static __inline__ __u32 *find_cookie(struct inode *inode, unsigned long off)
-{
-	static __u32 cookie_zero = 0;
-	struct nfs_cookie_table *p;
-	__u32 *ret;
-
-	if (!off)
-		return &cookie_zero;
-	off -= 1;
-	p = NFS_COOKIES(inode);
-	while(off >= COOKIES_PER_CHUNK && p) {
-		off -= COOKIES_PER_CHUNK;
-		p = p->next;
-	}
-	ret = NULL;
-	if (p) {
-		ret = &p->cookies[off];
-		if (!*ret)
-			ret = NULL;
-	}
-	return ret;
-}
-
-#define NFS_NAMELEN_ALIGN(__len) ((((__len)+3)>>2)<<2)
-static int create_cookie(__u32 cookie, unsigned long off, struct inode *inode)
-{
-	struct nfs_cookie_table **cpp;
-
-	cpp = (struct nfs_cookie_table **) &NFS_COOKIES(inode);
-	while (off >= COOKIES_PER_CHUNK && *cpp) {
-		off -= COOKIES_PER_CHUNK;
-		cpp = &(*cpp)->next;
-	}
-	if (*cpp) {
-		(*cpp)->cookies[off] = cookie;
-	} else {
-		struct nfs_cookie_table *new;
-		int i;
+static inline
+long find_dirent_page(struct inode *inode, loff_t offset,
+		      struct nfs_entry *entry)
+{
+	decode_dirent_t	decode = NFS_PROTO(inode)->decode_dirent;
+	struct page	*page;
+	unsigned long	index = entry->offset >> PAGE_CACHE_SHIFT;
+	long		status = -EIO;
+	int		plus = NFS_USE_READDIRPLUS(inode),
+			use_cookie = NFS_MONOTONE_COOKIES(inode);
+
+	dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", entry->offset & PAGE_CACHE_MASK);
+
+	if (entry->page)
+		page_cache_release(entry->page);
+
+	page = find_get_page(&inode->i_data, index);
+
+	if (page && Page_Uptodate(page))
+		status = find_dirent(page, offset, entry, decode, plus, use_cookie);
+
+	/* NB: on successful return we will be holding the page */
+	if (status < 0) {
+		entry->page = NULL;
+		if (page)
+			page_cache_release(page);
+	} else
+		entry->page = page;
 
-		new = kmem_cache_alloc(nfs_cookie_cachep, SLAB_ATOMIC);
-		if(!new)
-			return -1;
-		*cpp = new;
-		new->next = NULL;
-		for(i = 0; i < COOKIES_PER_CHUNK; i++) {
-			if (i == off) {
-				new->cookies[i] = cookie;
-			} else {
-				new->cookies[i] = 0;
-			}
-		}
-	}
-	return 0;
+	dfprintk(VFS, "NFS: find_dirent_page() returns %ld\n", status);
+	return status;
 }
 
-static struct page *try_to_get_dirent_page(struct file *, __u32, int);
 
-/* Recover from a revalidation flush.  The case here is that
- * the inode for the directory got invalidated somehow, and
- * all of our cached information is lost.  In order to get
- * a correct cookie for the current readdir request from the
- * user, we must (re-)fetch older readdir page cache entries.
+/*
+ * Recurse through the page cache pages, and return a
+ * filled nfs_entry structure of the next directory entry if possible.
+ *
+ * The target for the search is position 'offset'.
+ * The latter may either be an offset into the page cache, or (better)
+ * a cookie depending on whether we're interested in strictly following
+ * the RFC wrt. not assuming monotonicity of cookies or not.
  *
- * Returns < 0 if some error occurrs, else it is the page offset
- * to fetch.
+ * For most systems, the latter is more reliable since it naturally
+ * copes with holes in the directory.
  */
-static long refetch_to_readdir_cookie(struct file *file, struct inode *inode)
+static inline
+long search_cached_dirent_pages(struct inode *inode, loff_t offset,
+				struct nfs_entry *entry)
 {
-	struct page *page;
-	u32 goal_cookie = file->f_pos;
-	long cur_off, ret = -1L;
+	long		res = 0;
+	int		loop_count = 0;
 
-again:
-	cur_off = 0;
+	dfprintk(VFS, "NFS: search_cached_dirent_pages() searching for cookie %Ld\n", (long long)offset);
 	for (;;) {
-		page = find_get_page(&inode->i_data, cur_off);
-		if (page) {
-			if (!Page_Uptodate(page))
-				goto out_error;
-		} else {
-			__u32 *cp = find_cookie(inode, cur_off);
-
-			if (!cp)
-				goto out_error;
-
-			page = try_to_get_dirent_page(file, *cp, 0);
-			if (!page) {
-				if (!cur_off)
-					goto out_error;
-
-				/* Someone touched the dir on us. */
-				goto again;
-			}
+		res = find_dirent_page(inode, offset, entry);
+		if (res == -EAGAIN) {
+			/* Align to beginning of next page */
+			entry->offset &= PAGE_CACHE_MASK;
+			entry->offset += PAGE_CACHE_SIZE;
+		}
+		if (res != -EAGAIN)
+			break;
+		if (loop_count++ > 200) {
+			loop_count = 0;
+			schedule();
 		}
-		page_cache_release(page);
-
-		if ((ret = nfs_readdir_offset(inode, goal_cookie)) >= 0)
-			goto out;
-
-		cur_off += 1;
 	}
-out:
-	return ret;
-
-out_error:
-	if (page)
-		page_cache_release(page);
-	goto out;
+	if (res < 0 && entry->page) {
+		page_cache_release(entry->page);
+		entry->page = NULL;
+	}
+	dfprintk(VFS, "NFS: search_cached_dirent_pages() returned %ld\n", res);
+	return res;
 }
 
+
 /* Now we cache directories properly, by stuffing the dirent
  * data directly in the page cache.
  *
@@ -279,198 +207,240 @@
  *	 page-in of the RPC reply, nowhere else, this simplies
  *	 things substantially.
  */
+static inline
+long try_to_get_dirent_page(struct file *file, struct inode *inode,
+			    struct nfs_entry *entry)
+{
+	struct dentry	*dir = file->f_dentry;
+	struct page	*page;
+	__u32		*p;
+	unsigned long	index = entry->offset >> PAGE_CACHE_SHIFT;
+	long		res = 0;
+	unsigned int	dtsize = NFS_SERVER(inode)->dtsize;
+	int		plus = NFS_USE_READDIRPLUS(inode);
 
-static int nfs_dir_filler(struct dentry *dentry, struct page *page)
-{
-	struct nfs_readdirargs rd_args;
-	struct nfs_readdirres rd_res;
-	struct inode *inode = dentry->d_inode;
-	long offset = page->index;
-	__u32 *cookiep;
-	int err;
-
-	kmap(page);
-
-	err = -EIO;
-	cookiep = find_cookie(inode, offset);
-	if (!cookiep)
-		goto fail;
-
-	rd_args.fh = NFS_FH(dentry);
-	rd_res.buffer = (char *)page_address(page);
-	rd_res.bufsiz = PAGE_CACHE_SIZE;
-	rd_res.cookie = *cookiep;
-	do {
-		rd_args.buffer = rd_res.buffer;
-		rd_args.bufsiz = rd_res.bufsiz;
-		rd_args.cookie = rd_res.cookie;
-		err = rpc_call(NFS_CLIENT(inode),
-			     NFSPROC_READDIR, &rd_args, &rd_res, 0); 
-		if (err < 0)
-			goto fail;
-	} while(rd_res.bufsiz > 0);
-
-	err = -EIO;
-	if (rd_res.bufsiz < 0)
-		NFS_DIREOF(inode) = rd_res.cookie;
-	else if (create_cookie(rd_res.cookie, offset, inode))
-		goto fail;
+	dfprintk(VFS, "NFS: try_to_get_dirent_page() reading directory page @ index %ld\n", index);
 
-	SetPageUptodate(page);
-	kunmap(page);
-	UnlockPage(page);
-	return 0;
-fail:
-	SetPageError(page);
-	kunmap(page);
-	UnlockPage(page);
-	return err;
-}
+	page = grab_cache_page(&inode->i_data, index);
 
-static struct page *try_to_get_dirent_page(struct file *file, __u32 cookie, int refetch_ok)
-{
-	struct dentry *dentry = file->f_dentry;
-	struct inode *inode = dentry->d_inode;
-	struct page *page;
-	long offset;
+	if (!page) {
+		res = -ENOMEM;
+		goto out;
+	}
 
-	if ((offset = nfs_readdir_offset(inode, cookie)) < 0) {
-		if (!refetch_ok ||
-		    (offset = refetch_to_readdir_cookie(file, inode)) < 0) {
-			goto fail;
-		}
+	if (Page_Uptodate(page)) {
+		dfprintk(VFS, "NFS: try_to_get_dirent_page(): page already up to date.\n");
+		goto unlock_out;
 	}
 
-	page = read_cache_page(&inode->i_data, offset,
-				(filler_t *)nfs_dir_filler, dentry);
-	if (IS_ERR(page))
-		goto fail;
-	if (!Page_Uptodate(page))
-		goto fail2;
-	return page;
+	p = (__u32 *)kmap(page);
 
-fail2:
+	if (dtsize > PAGE_CACHE_SIZE)
+		dtsize = PAGE_CACHE_SIZE;
+	res = NFS_PROTO(inode)->readdir(dir, entry->cookie, p, dtsize, plus);
+
+	kunmap(page);
+
+	if (res < 0)
+		goto error;
+	if (PageError(page))
+		ClearPageError(page);
+	SetPageUptodate(page);
+
+ unlock_out:
+	UnlockPage(page);
 	page_cache_release(page);
-fail:
-	return NULL;
+ out:
+	dfprintk(VFS, "NFS: try_to_get_dirent_page() returns %ld\n", res);
+	return res;
+ error:
+	SetPageError(page);
+	goto unlock_out;
 }
 
-/* Seek up to dirent assosciated with the passed in cookie,
- * then fill in dirents found.  Return the last cookie
- * actually given to the user, to update the file position.
+/* Recover from a revalidation flush.  The case here is that
+ * the inode for the directory got invalidated somehow, and
+ * all of our cached information is lost.  In order to get
+ * a correct cookie for the current readdir request from the
+ * user, we must (re-)fetch all the older readdir page cache
+ * entries.
+ *
+ * Returns < 0 if some error occurs.
  */
-static __inline__ u32 nfs_do_filldir(__u32 *p, u32 cookie,
-				     void *dirent, filldir_t filldir)
-{
-	u32 end;
+static inline
+long refetch_to_readdir(struct file *file, struct inode *inode,
+			loff_t off, struct nfs_entry *entry)
+{
+	struct nfs_entry	my_dirent,
+				*dirent = &my_dirent;
+	long			res;
+	int			plus = NFS_USE_READDIRPLUS(inode),
+				use_cookie = NFS_MONOTONE_COOKIES(inode),
+				loop_count = 0;
+
+	dfprintk(VFS, "NFS: refetch_to_readdir() searching for cookie %Ld\n", (long long)off);
+	*dirent = *entry;
+	entry->page = NULL;
+
+	for (res = 0;res >= 0;) {
+		if (loop_count++ > 200) {
+			loop_count = 0;
+			schedule();
+		}
 
-	while((end = *p++) != 0) {
-		__u32 fileid, len, skip, this_cookie;
-		char *name;
-
-		fileid = *p++;
-		len = *p++;
-		name = (char *) p;
-		skip = NFS_NAMELEN_ALIGN(len);
-		p += (skip >> 2);
-		this_cookie = *p++;
+		/* Search for last cookie in page cache */
+		res = search_cached_dirent_pages(inode, off, dirent);
 
-		if (this_cookie < cookie)
+		if (res >= 0) {
+			/* Cookie was found */
+			if ((use_cookie?dirent->cookie:dirent->offset) > off) {
+				*entry = *dirent;
+				dirent->page = NULL;
+				break;
+			}
 			continue;
+		}
+
+		if (dirent->page)
+			page_cache_release(dirent->page);
+		dirent->page = NULL;
 
-		cookie = this_cookie;
-		if (filldir(dirent, name, len, cookie, fileid) < 0)
+		if (res != -EIO) {
+			*entry = *dirent;
 			break;
+		}
+
+		/* Read in a new page */
+		res = try_to_get_dirent_page(file, inode, dirent);
+		if (res == -EBADCOOKIE) {
+			memset(dirent, 0, sizeof(*dirent));
+			nfs_zap_caches(inode);
+			res = 0;
+		}
+		/* We requested READDIRPLUS, but the server doesn't grok it */
+		if (plus && res == -ENOTSUPP) {
+			NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
+			memset(dirent, 0, sizeof(*dirent));
+			nfs_zap_caches(inode);
+			plus = 0;
+			res = 0;
+		}
 	}
+	if (dirent->page)
+		page_cache_release(dirent->page);
 
-	return cookie;
+	dfprintk(VFS, "NFS: refetch_to_readdir() returns %ld\n", res);
+	return res;
 }
 
-/* The file offset position is represented in pure bytes, to
- * make the page cache interface straight forward.
- *
- * However, some way is needed to make the connection between the
- * opaque NFS directory entry cookies and our offsets, so a per-inode
- * cookie cache table is used.
+/*
+ * Once we've found the start of the dirent within a page: fill 'er up...
  */
-static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
-{
-	struct dentry *dentry = filp->f_dentry;
-	struct inode *inode = dentry->d_inode;
-	struct page *page;
-	long offset;
-	int res;
-
-	res = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
-	if (res < 0)
-		return res;
-
-	if (NFS_DIREOF(inode) && filp->f_pos >= NFS_DIREOF(inode))
-		return 0;
-
-	if ((offset = nfs_readdir_offset(inode, filp->f_pos)) < 0)
-		goto no_dirent_page;
-
-	page = find_get_page(&inode->i_data, offset);
-	if (!page)
-		goto no_dirent_page;
-	if (!Page_Uptodate(page))
-		goto dirent_read_error;
-success:
-	kmap(page);
-	filp->f_pos = nfs_do_filldir((__u32 *) page_address(page),
-				     filp->f_pos, dirent, filldir);
+static
+int nfs_do_filldir(struct file *file, struct inode *inode,
+		   struct nfs_entry *entry, void *dirent, filldir_t filldir)
+{
+	decode_dirent_t	decode = NFS_PROTO(inode)->decode_dirent;
+	struct page	*page = entry->page;
+	__u8		*p,
+			*start;
+	unsigned long	base = page_offset(page),
+			offset = entry->offset,
+			pg_offset,
+			fileid;
+	int		plus = NFS_USE_READDIRPLUS(inode),
+			use_cookie = NFS_MONOTONE_COOKIES(inode),
+			loop_count = 0,
+			res = 0;
+
+	dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ offset %ld\n", entry->offset);
+	pg_offset = offset & ~PAGE_CACHE_MASK;
+	start = (u8*)kmap(page);
+	p = start + pg_offset;
+
+	for(;;) {
+		/* Note: entry->prev contains the offset of the start of the
+		 *       current dirent */
+		fileid = nfs_fileid_to_ino_t(entry->ino);
+		if (use_cookie)
+			res = filldir(dirent, entry->name, entry->len, entry->prev_cookie, fileid);
+		else
+			res = filldir(dirent, entry->name, entry->len, entry->prev, fileid);
+		if (res < 0)
+			break;
+		file->f_pos = (use_cookie) ? entry->cookie : entry->offset;
+		p = (u8*)decode((__u32*)p, entry, plus);
+		if (!p || IS_ERR(p))
+			break;
+		pg_offset = p - start;
+		entry->prev = entry->offset;
+		entry->offset = base + pg_offset;
+		if (loop_count++ > 200) {
+			loop_count = 0;
+			schedule();
+		}
+	}
 	kunmap(page);
-	page_cache_release(page);
-	return 0;
 
-no_dirent_page:
-	page = try_to_get_dirent_page(filp, filp->f_pos, 1);
-	if (!page)
-		goto no_page;
-
-	if (Page_Uptodate(page))
-		goto success;
-dirent_read_error:
-	page_cache_release(page);
-no_page:
-	return -EIO;
+	dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ offset %ld; returning = %d\n", entry->offset, res);
+	return res;
 }
 
-/* Flush directory cookie and EOF caches for an inode.
- * So we don't thrash allocating/freeing cookie tables,
- * we keep the cookies around until the inode is
- * deleted/reused.
+/* The file offset position is now represented as a true offset into the
+ * page cache as is the case in most of the other filesystems.
  */
-__inline__ void nfs_flush_dircache(struct inode *inode)
+static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
-	struct nfs_cookie_table *p = NFS_COOKIES(inode);
+	struct dentry	*dentry = filp->f_dentry;
+	struct inode	*inode = dentry->d_inode;
+	struct page	*page;
+	struct nfs_entry my_entry,
+			*entry = &my_entry;
+	loff_t		offset;
+	long		res;
 
-	while (p != NULL) {
-		int i;
+	res = nfs_revalidate(dentry);
+	if (res < 0)
+		return res;
 
-		for(i = 0; i < COOKIES_PER_CHUNK; i++)
-			p->cookies[i] = 0;
+	/*
+	 * filp->f_pos points to the file offset in the page cache.
+	 * but if the cache has meanwhile been zapped, we need to
+	 * read from the last dirent to revalidate f_pos
+	 * itself.
+	 */
+	memset(entry, 0, sizeof(*entry));
 
-		p = p->next;
-	}
-	NFS_DIREOF(inode) = 0;
-}
+	offset = filp->f_pos;
 
-/* Free up directory cache state, this happens when
- * nfs_delete_inode is called on an NFS directory.
- */
-void nfs_free_dircache(struct inode *inode)
-{
-	struct nfs_cookie_table *p = NFS_COOKIES(inode);
+	while(!entry->eof) {
+		res = search_cached_dirent_pages(inode, offset, entry);
+
+		if (res < 0) {
+			if (entry->eof)
+				break;
+			res = refetch_to_readdir(filp, inode, offset, entry);
+			if (res < 0)
+				break;
+		}
 
-	while (p != NULL) {
-		struct nfs_cookie_table *next = p->next;
-		kmem_cache_free(nfs_cookie_cachep, p);
-		p = next;
+		page = entry->page;
+		if (!page)
+			printk(KERN_ERR "NFS: Missing page...\n");
+		res = nfs_do_filldir(filp, inode, entry, dirent, filldir);
+		page_cache_release(page);
+		entry->page = NULL;
+		if (res < 0) {
+			res = 0;
+			break;
+		}
+		offset = filp->f_pos;
 	}
-	NFS_COOKIES(inode) = NULL;
-	NFS_DIREOF(inode) = 0;
+	if (entry->page)
+		page_cache_release(entry->page);
+	if (res < 0 && res != -EBADCOOKIE)
+		return res;
+	return 0;
 }
 
 /*
@@ -540,7 +510,8 @@
  */
 static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
 {
-	struct dentry * parent = dentry->d_parent;
+	struct dentry *dir = dentry->d_parent;
+	struct inode *dir_i = dir->d_inode;
 	struct inode * inode = dentry->d_inode;
 	int error;
 	struct nfs_fh fhandle;
@@ -559,7 +530,7 @@
 
 	if (is_bad_inode(inode)) {
 		dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
-			parent->d_name.name, dentry->d_name.name);
+			dir->d_name.name, dentry->d_name.name);
 		goto out_bad;
 	}
 
@@ -574,13 +545,14 @@
 	/*
 	 * Do a new lookup and check the dentry attributes.
 	 */
-	error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent),
-				dentry->d_name.name, &fhandle, &fattr);
+	error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle,
+					 &fattr);
 	if (error)
 		goto out_bad;
 
 	/* Inode number matches? */
-	if (NFS_FSID(inode) != fattr.fsid ||
+	if (!(fattr.valid & NFS_ATTR_FATTR) ||
+	    NFS_FSID(inode) != fattr.fsid ||
 	    NFS_FILEID(inode) != fattr.fileid)
 		goto out_bad;
 
@@ -603,10 +575,9 @@
 		goto out_valid;
 	d_drop(dentry);
 	/* Purge readdir caches. */
-	if (dentry->d_parent->d_inode) {
-		nfs_zap_caches(dentry->d_parent->d_inode);
-		NFS_CACHEINV(dentry->d_parent->d_inode);
-	}
+	nfs_zap_caches(dir_i);
+	if (inode && S_ISDIR(inode->i_mode))
+		nfs_zap_caches(inode);
 	return 0;
 }
 
@@ -687,18 +658,19 @@
 #endif /* NFS_PARANOIA */
 #endif /* 0 */
 
-static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
+static struct dentry *nfs_lookup(struct inode *dir_i, struct dentry * dentry)
 {
+	struct dentry *dir = dentry->d_parent;
 	struct inode *inode;
 	int error;
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
 
 	dfprintk(VFS, "NFS: lookup(%s/%s)\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name);
+		dir->d_name.name, dentry->d_name.name);
 
 	error = -ENAMETOOLONG;
-	if (dentry->d_name.len > NFS_MAXNAMLEN)
+	if (dentry->d_name.len > NFS_SERVER(dir_i)->namelen)
 		goto out;
 
 	error = -ENOMEM;
@@ -709,8 +681,8 @@
 	}
 	dentry->d_op = &nfs_dentry_operations;
 
-	error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dentry->d_parent), 
-				dentry->d_name.name, &fhandle, &fattr);
+	error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle,
+					 &fattr);
 	inode = NULL;
 	if (error == -ENOENT)
 		goto no_entry;
@@ -743,6 +715,7 @@
 		nfs_renew_times(dentry);
 		error = 0;
 	}
+	NFS_CACHEINV(dentry->d_parent->d_inode);
 	return error;
 }
 
@@ -752,29 +725,32 @@
  * that the operation succeeded on the server, but an error in the
  * reply path made it appear to have failed.
  */
-static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
+static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode)
 {
-	int error;
+	struct dentry *dir = dentry->d_parent;
 	struct iattr attr;
 	struct nfs_fattr fattr;
 	struct nfs_fh fhandle;
+	int error;
 
 	dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
 
 	attr.ia_mode = mode;
 	attr.ia_valid = ATTR_MODE;
 
 	/*
-	 * Invalidate the dir cache before the operation to avoid a race.
+	 * The 0 argument passed into the create function should one day
+	 * contain the O_EXCL flag if requested. This allows NFSv3 to
+	 * select the appropriate create strategy. Currently open_namei
+	 * does not pass the create flags.
 	 */
-	invalidate_inode_pages(dir);
-	nfs_flush_dircache(dir);
-	error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-			dentry->d_name.name, &attr, &fhandle, &fattr);
-	if (!error)
+	nfs_zap_caches(dir_i);
+	error = NFS_PROTO(dir_i)->create(dir, &dentry->d_name,
+					 &attr, 0, &fhandle, &fattr);
+	if (!error && fhandle.size != 0)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
-	if (error)
+	if (error || fhandle.size == 0)
 		d_drop(dentry);
 	return error;
 }
@@ -782,31 +758,26 @@
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
+static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int rdev)
 {
-	int error;
+	struct dentry *dir = dentry->d_parent;
 	struct iattr attr;
 	struct nfs_fattr fattr;
 	struct nfs_fh fhandle;
+	int error;
 
 	dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
 
 	attr.ia_mode = mode;
 	attr.ia_valid = ATTR_MODE;
-	/* FIXME: move this to a special nfs_proc_mknod() */
-	if (S_ISCHR(mode) || S_ISBLK(mode)) {
-		attr.ia_size = rdev; /* get out your barf bag */
-		attr.ia_valid |= ATTR_SIZE;
-	}
 
-	invalidate_inode_pages(dir);
-	nfs_flush_dircache(dir);
-	error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-				dentry->d_name.name, &attr, &fhandle, &fattr);
-	if (!error)
+	nfs_zap_caches(dir_i);
+	error = NFS_PROTO(dir_i)->mknod(dir, &dentry->d_name, &attr, rdev,
+					&fhandle, &fattr);
+	if (!error && fhandle.size != 0)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
-	if (error)
+	if (error || fhandle.size == 0)
 		d_drop(dentry);
 	return error;
 }
@@ -814,19 +785,21 @@
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
 {
-	int error;
+	struct dentry *dir = dentry->d_parent;
 	struct iattr attr;
 	struct nfs_fattr fattr;
 	struct nfs_fh fhandle;
+	int error;
 
 	dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
 
 	attr.ia_valid = ATTR_MODE;
 	attr.ia_mode = mode | S_IFDIR;
 
+#if 0
 	/*
 	 * Always drop the dentry, we can't always depend on
 	 * the fattr returned by the server (AIX seems to be
@@ -834,44 +807,48 @@
 	 * depending on potentially bogus information.
 	 */
 	d_drop(dentry);
-	invalidate_inode_pages(dir);
-	nfs_flush_dircache(dir);
-	error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
-				dentry->d_name.name, &attr, &fhandle, &fattr);
-	if (!error)
-		dir->i_nlink++;
+#endif
+	nfs_zap_caches(dir_i);
+	dir_i->i_nlink++;
+	error = NFS_PROTO(dir_i)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
+					&fattr);
+	if (!error && fhandle.size != 0)
+		error = nfs_instantiate(dentry, &fhandle, &fattr);
+	if (error || fhandle.size == 0)
+		d_drop(dentry);
 	return error;
 }
 
-static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
+static int nfs_rmdir(struct inode *dir_i, struct dentry *dentry)
 {
+	struct dentry *dir = dentry->d_parent;
 	int error;
 
 	dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
 
-	invalidate_inode_pages(dir);
-	nfs_flush_dircache(dir);
-	error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-				dentry->d_name.name);
+	nfs_zap_caches(dir_i);
+	error = NFS_PROTO(dir_i)->rmdir(dir, &dentry->d_name);
 
 	/* Update i_nlink and invalidate dentry. */
 	if (!error) {
 		d_drop(dentry);
-		if (dir->i_nlink)
-			dir->i_nlink--;
+		if (dir_i->i_nlink)
+			dir_i->i_nlink--;
 	}
 
 	return error;
 }
 
-static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
+static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry)
 {
+	struct dentry *dir = dentry->d_parent;
 	static unsigned int sillycounter = 0;
-	const int      i_inosize  = sizeof(dir->i_ino)*2;
+	const int      i_inosize  = sizeof(dir_i->i_ino)*2;
 	const int      countersize = sizeof(sillycounter)*2;
 	const int      slen       = strlen(".nfs") + i_inosize + countersize;
 	char           silly[slen+1];
+	struct qstr    qsilly;
 	struct dentry *sdentry;
 	int            error = -EIO;
 
@@ -923,11 +900,10 @@
 			goto out;
 	} while(sdentry->d_inode != NULL); /* need negative lookup */
 
-	invalidate_inode_pages(dir);
-	nfs_flush_dircache(dir);
-	error = nfs_proc_rename(NFS_SERVER(dir),
-				NFS_FH(dentry->d_parent), dentry->d_name.name,
-				NFS_FH(dentry->d_parent), silly);
+	nfs_zap_caches(dir_i);
+	qsilly.name = silly;
+	qsilly.len  = strlen(silly);
+	error = NFS_PROTO(dir_i)->rename(dir, &dentry->d_name, dir, &qsilly);
 	if (!error) {
 		nfs_renew_times(dentry);
 		d_move(dentry, sdentry);
@@ -948,7 +924,8 @@
  */
 static int nfs_safe_remove(struct dentry *dentry)
 {
-	struct inode *dir = dentry->d_parent->d_inode;
+	struct dentry *dir = dentry->d_parent;
+	struct inode *dir_i = dir->d_inode;
 	struct inode *inode = dentry->d_inode;
 	int error, rehash = 0;
 		
@@ -979,22 +956,22 @@
 		d_drop(dentry);
 		rehash = 1;
 	}
+	nfs_zap_caches(dir_i);
+	error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name);
+	if (error < 0)
+		goto out;
 	/*
-	 * Update i_nlink and free the inode before unlinking.
+	 * Update i_nlink and free the inode
 	 */
 	if (inode) {
 		if (inode->i_nlink)
 			inode->i_nlink --;
 		d_delete(dentry);
 	}
-	invalidate_inode_pages(dir);
-	nfs_flush_dircache(dir);
-	error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-				dentry->d_name.name);
 	/*
 	 * Rehash the negative dentry if the operation succeeded.
 	 */
-	if (!error && rehash)
+	if (rehash)
 		d_add(dentry, NULL);
 out:
 	return error;
@@ -1023,16 +1000,22 @@
 }
 
 static int
-nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname)
 {
+	struct dentry *dir = dentry->d_parent;
 	struct iattr attr;
+	struct nfs_fattr sym_attr;
+	struct nfs_fh sym_fh;
+	struct qstr qsymname;
+	unsigned int maxlen;
 	int error;
 
 	dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
+		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name, symname);
 
 	error = -ENAMETOOLONG;
-	if (strlen(symname) > NFS_MAXPATHLEN)
+	maxlen = (NFS_PROTO(dir_i)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
+	if (strlen(symname) > maxlen)
 		goto out;
 
 #ifdef NFS_PARANOIA
@@ -1047,21 +1030,19 @@
 	attr.ia_valid = ATTR_MODE;
 	attr.ia_mode = S_IFLNK | S_IRWXUGO;
 
-	/*
-	 * Drop the dentry in advance to force a new lookup.
-	 * Since nfs_proc_symlink doesn't return a fattr, we
-	 * can't instantiate the new inode.
-	 */
-	d_drop(dentry);
-	invalidate_inode_pages(dir);
-	nfs_flush_dircache(dir);
-	error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-				dentry->d_name.name, symname, &attr);
-	if (!error) {
-		nfs_renew_times(dentry->d_parent);
-	} else if (error == -EEXIST) {
-		printk("nfs_proc_symlink: %s/%s already exists??\n",
-			dentry->d_parent->d_name.name, dentry->d_name.name);
+	qsymname.name = symname;
+	qsymname.len  = strlen(symname);
+
+	nfs_zap_caches(dir_i);
+	error = NFS_PROTO(dir_i)->symlink(dir, &dentry->d_name, &qsymname,
+					  &attr, &sym_fh, &sym_attr);
+	if (!error && sym_fh.size != 0 && (sym_attr.valid & NFS_ATTR_FATTR)) {
+		error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
+	} else {
+		if (error == -EEXIST)
+			printk("nfs_proc_symlink: %s/%s already exists??\n",
+			       dir->d_name.name, dentry->d_name.name);
+		d_drop(dentry);
 	}
 
 out:
@@ -1069,8 +1050,9 @@
 }
 
 static int 
-nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
+nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
 {
+	struct dentry *dir = dentry->d_parent;
 	struct inode *inode = old_dentry->d_inode;
 	int error;
 
@@ -1084,10 +1066,8 @@
 	 * we can't use the existing dentry.
 	 */
 	d_drop(dentry);
-	invalidate_inode_pages(dir);
-	nfs_flush_dircache(dir);
-	error = nfs_proc_link(NFS_DSERVER(old_dentry), NFS_FH(old_dentry),
-				NFS_FH(dentry->d_parent), dentry->d_name.name);
+	nfs_zap_caches(dir_i);
+	error = NFS_PROTO(dir_i)->link(old_dentry, dir, &dentry->d_name);
 	if (!error) {
  		/*
 		 * Update the link count immediately, as some apps
@@ -1197,14 +1177,12 @@
 	if (new_inode)
 		d_delete(new_dentry);
 
-	invalidate_inode_pages(new_dir);
-	nfs_flush_dircache(new_dir);
-	invalidate_inode_pages(old_dir);
-	nfs_flush_dircache(old_dir);
-	error = nfs_proc_rename(NFS_DSERVER(old_dentry),
-			NFS_FH(old_dentry->d_parent), old_dentry->d_name.name,
-			NFS_FH(new_dentry->d_parent), new_dentry->d_name.name);
-
+	nfs_zap_caches(new_dir);
+	nfs_zap_caches(old_dir);
+	error = NFS_PROTO(old_dir)->rename(old_dentry->d_parent,
+					   &old_dentry->d_name,
+					   new_dentry->d_parent,
+					   &new_dentry->d_name);
 	NFS_CACHEINV(old_dir);
 	NFS_CACHEINV(new_dir);
 	/* Update the dcache if needed */
@@ -1229,14 +1207,13 @@
 	if (nfs_fh_cachep == NULL)
 		return -ENOMEM;
 
-	nfs_cookie_cachep = kmem_cache_create("nfs_dcookie",
-					      sizeof(struct nfs_cookie_table),
-					      0, SLAB_HWCACHE_ALIGN,
-					      NULL, NULL);
-	if (nfs_cookie_cachep == NULL)
-		return -ENOMEM;
-
 	return 0;
+}
+
+void nfs_destroy_fhcache(void)
+{
+	if (kmem_cache_destroy(nfs_fh_cachep))
+		printk(KERN_INFO "nfs_fh: not all structures were freed\n");
 }
 
 /*
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.3.99-pre3/linux/fs/nfs/file.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/nfs/file.c	Sun Apr  2 15:31:32 2000
@@ -22,6 +22,7 @@
 #include <linux/fcntl.h>
 #include <linux/stat.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/pagemap.h>
@@ -215,10 +216,10 @@
 	struct inode * inode = filp->f_dentry->d_inode;
 	int	status = 0;
 
-	dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%ld:%ld)\n",
+	dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
 			inode->i_dev, inode->i_ino,
 			fl->fl_type, fl->fl_flags,
-			fl->fl_start, fl->fl_end);
+			(long long)fl->fl_start, (long long)fl->fl_end);
 
 	if (!inode)
 		return -EINVAL;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/flushd.c linux/fs/nfs/flushd.c
--- v2.3.99-pre3/linux/fs/nfs/flushd.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/nfs/flushd.c	Mon Apr  3 13:24:06 2000
@@ -299,6 +299,5 @@
 		cache->task = NULL;
 	spin_unlock(&nfs_flushd_lock);
 	wake_up(&cache->request_wait);
-	rpc_release_task(task);
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.3.99-pre3/linux/fs/nfs/inode.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/nfs/inode.c	Sun Apr  2 15:31:32 2000
@@ -27,6 +27,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
 #include <linux/nfs_flushd.h>
 #include <linux/lockd/bind.h>
 #include <linux/smp_lock.h>
@@ -58,7 +59,32 @@
 	umount_begin:	nfs_umount_begin,
 };
 
+/*
+ * RPC cruft for NFS
+ */
 struct rpc_stat			nfs_rpcstat = { &nfs_program };
+static struct rpc_version *	nfs_version[] = {
+	NULL,
+	NULL,
+	&nfs_version2,
+#ifdef CONFIG_NFS_V3
+	&nfs_version3,
+#endif
+};
+
+struct rpc_program		nfs_program = {
+	"nfs",
+	NFS_PROGRAM,
+	sizeof(nfs_version) / sizeof(nfs_version[0]),
+	nfs_version,
+	&nfs_rpcstat,
+};
+
+static inline unsigned long
+nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
+{
+	return nfs_fileid_to_ino_t(fattr->fileid);
+}
 
 /*
  * The "read_inode" function doesn't actually do anything:
@@ -83,6 +109,7 @@
 	inode->u.nfs_i.npages = 0;
 	NFS_CACHEINV(inode);
 	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+	NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 }
 
 static void
@@ -101,18 +128,12 @@
 {
 	dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
 
-	lock_kernel();
-	if (S_ISDIR(inode->i_mode)) {
-		nfs_free_dircache(inode);
-	} else {
-		/*
-		 * The following can never actually happen...
-		 */
-		if (nfs_have_writebacks(inode)) {
-			printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
-		}
+	/*
+	 * The following can never actually happen...
+	 */
+	if (nfs_have_writebacks(inode)) {
+		printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
 	}
-	unlock_kernel();
 
 	clear_inode(inode);
 }
@@ -153,33 +174,68 @@
 		rpc_killall_tasks(rpc);
 }
 
-/*
- * Compute and set NFS server blocksize
- */
-static unsigned int
-nfs_block_size(unsigned int bsize, unsigned char *nrbitsp)
-{
-	if (bsize < 1024)
-		bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
-	else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
-		bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
 
+static inline unsigned long
+nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
+{
 	/* make sure blocksize is a power of two */
 	if ((bsize & (bsize - 1)) || nrbitsp) {
-		unsigned int	nrbits;
+		unsigned char	nrbits;
 
 		for (nrbits = 31; nrbits && !(bsize & (1 << nrbits)); nrbits--)
 			;
 		bsize = 1 << nrbits;
 		if (nrbitsp)
 			*nrbitsp = nrbits;
-		if (bsize < NFS_DEF_FILE_IO_BUFFER_SIZE)
-			bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
 	}
 
 	return bsize;
 }
 
+/*
+ * Calculate the number of 512byte blocks used.
+ */
+static inline unsigned long
+nfs_calc_block_size(u64 tsize)
+{
+	loff_t used = (tsize + 511) / 512;
+	return (used > ULONG_MAX) ? ULONG_MAX : used;
+}
+
+/*
+ * Compute and set NFS server blocksize
+ */
+static inline unsigned long
+nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
+{
+	if (bsize < 1024)
+		bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
+	else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
+		bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
+
+	return nfs_block_bits(bsize, nrbitsp);
+}
+
+/*
+ * Obtain the root inode of the file system.
+ */
+static struct inode *
+nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh)
+{
+	struct nfs_server	*server = &sb->u.nfs_sb.s_server;
+	struct nfs_fattr	fattr;
+	struct inode		*inode;
+	int			error;
+
+	if ((error = server->rpc_ops->getroot(server, rootfh, &fattr)) < 0) {
+		printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
+		return NULL;
+	}
+
+	inode = __nfs_fhget(sb, &fattr);
+	return inode;
+}
+
 extern struct nfs_fh *nfs_fh_alloc(void);
 extern void nfs_fh_free(struct nfs_fh *p);
 
@@ -194,19 +250,20 @@
 {
 	struct nfs_mount_data	*data = (struct nfs_mount_data *) raw_data;
 	struct nfs_server	*server;
-	struct rpc_xprt		*xprt;
-	struct rpc_clnt		*clnt;
-	struct nfs_fh		*root_fh;
-	struct inode		*root_inode;
+	struct rpc_xprt		*xprt = NULL;
+	struct rpc_clnt		*clnt = NULL;
+	struct nfs_fh		*root = &data->root, *root_fh, fh;
+	struct inode		*root_inode = NULL;
 	unsigned int		authflavor;
-	int			tcp;
 	struct sockaddr_in	srvaddr;
 	struct rpc_timeout	timeparms;
-	struct nfs_fattr	fattr;
+	struct nfs_fsinfo	fsinfo;
+	int			tcp, version, maxlen;
 
 	if (!data)
 		goto out_miss_args;
 
+	memset(&fh, 0, sizeof(fh));
 	if (data->version != NFS_MOUNT_VERSION) {
 		printk("nfs warning: mount version %s than kernel\n",
 			data->version < NFS_MOUNT_VERSION ? "older" : "newer");
@@ -214,6 +271,12 @@
 			data->namlen = 0;
 		if (data->version < 3)
 			data->bsize  = 0;
+		if (data->version < 4) {
+			data->flags &= ~NFS_MOUNT_VER3;
+			root = &fh;
+			root->size = NFS2_FHSIZE;
+			memcpy(root->data, data->old_root.data, NFS2_FHSIZE);
+		}
 	}
 
 	/* We now require that the mount process passes the remote address */
@@ -225,12 +288,12 @@
 
 	sb->s_magic      = NFS_SUPER_MAGIC;
 	sb->s_op         = &nfs_sops;
+	sb->s_blocksize_bits = 0;
 	sb->s_blocksize  = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
-	sb->u.nfs_sb.s_root = data->root;
 	server           = &sb->u.nfs_sb.s_server;
 	server->rsize    = nfs_block_size(data->rsize, NULL);
 	server->wsize    = nfs_block_size(data->wsize, NULL);
-	server->flags    = data->flags;
+	server->flags    = data->flags & NFS_MOUNT_FLAGMASK;
 
 	if (data->flags & NFS_MOUNT_NOAC) {
 		data->acregmin = data->acregmax = 0;
@@ -241,11 +304,32 @@
 	server->acdirmin = data->acdirmin*HZ;
 	server->acdirmax = data->acdirmax*HZ;
 
+	server->namelen  = data->namlen;
 	server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
 	if (!server->hostname)
 		goto out_unlock;
 	strcpy(server->hostname, data->hostname);
 
+ nfsv3_try_again:
+	/* Check NFS protocol revision and initialize RPC op vector
+	 * and file handle pool. */
+	if (data->flags & NFS_MOUNT_VER3) {
+#ifdef CONFIG_NFS_V3
+		server->rpc_ops = &nfs_v3_clientops;
+		version = 3;
+		if (data->version < 4) {
+			printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
+			goto out_unlock;
+		}
+#else
+		printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
+		goto out_unlock;
+#endif
+	} else {
+		server->rpc_ops = &nfs_v2_clientops;
+		version = 2;
+        }
+
 	/* Which protocol do we use? */
 	tcp   = (data->flags & NFS_MOUNT_TCP);
 
@@ -255,6 +339,11 @@
 	timeparms.to_maxval  = tcp? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT;
 	timeparms.to_exponential = 1;
 
+	if (!timeparms.to_initval)
+		timeparms.to_initval = (tcp ? 600 : 11) * HZ / 10;
+	if (!timeparms.to_retries)
+		timeparms.to_retries = 5;
+
 	/* Now create transport and client */
 	xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
 						&srvaddr, &timeparms);
@@ -269,7 +358,7 @@
 		authflavor = RPC_AUTH_KRB;
 
 	clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
-						NFS_VERSION, authflavor);
+				 version, authflavor);
 	if (clnt == NULL)
 		goto out_no_client;
 
@@ -289,20 +378,68 @@
 	root_fh = nfs_fh_alloc();
 	if (!root_fh)
 		goto out_no_fh;
-	*root_fh = data->root;
+	memcpy((u8*)root_fh, (u8*)root, sizeof(*root));
 
-	if (nfs_proc_getattr(server, root_fh, &fattr) != 0)
-		goto out_no_fattr;
+	/* Did getting the root inode fail? */
+	if (!(root_inode = nfs_get_root(sb, root))
+	    && (data->flags & NFS_MOUNT_VER3)) {
+		data->flags &= ~NFS_MOUNT_VER3;
+		nfs_fh_free(root_fh);
+		rpciod_down();
+		rpc_shutdown_client(server->client);
+		goto nfsv3_try_again;
+	}
 
-	root_inode = __nfs_fhget(sb, &fattr);
 	if (!root_inode)
 		goto out_no_root;
 	sb->s_root = d_alloc_root(root_inode);
 	if (!sb->s_root)
 		goto out_no_root;
+
 	sb->s_root->d_op = &nfs_dentry_operations;
 	sb->s_root->d_fsdata = root_fh;
 
+	/* Get some general file system info */
+        if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) {
+		if (server->namelen == 0)
+			server->namelen = fsinfo.namelen;
+	} else {
+		printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
+		goto out_no_root;
+        }
+
+	/* Work out a lot of parameters */
+	if (data->rsize == 0)
+		server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+	if (data->wsize == 0)
+		server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+	server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+	/* NFSv3: we don't have bsize, but rather rtmult and wtmult... */
+	if (!fsinfo.bsize)
+		fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult;
+	/* Also make sure we don't go below rsize/wsize since
+	 * RPC calls are expensive */
+	if (fsinfo.bsize < server->rsize)
+		fsinfo.bsize = server->rsize;
+	if (fsinfo.bsize < server->wsize)
+		fsinfo.bsize = server->wsize;
+
+	if (data->bsize == 0)
+		sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
+	if (server->rsize > fsinfo.rtmax)
+		server->rsize = fsinfo.rtmax;
+	if (server->rsize > PAGE_CACHE_SIZE)
+		server->rsize = PAGE_CACHE_SIZE;
+	if (server->wsize > fsinfo.wtmax)
+		server->wsize = fsinfo.wtmax;
+        if (server->wsize > NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT)
+                server->wsize = NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT;
+
+        maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
+
+        if (server->namelen == 0 || server->namelen > maxlen)
+                server->namelen = maxlen;
+
 	/* Fire up the writeback cache */
 	if (nfs_reqlist_alloc(server) < 0) {
 		printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
@@ -322,11 +459,6 @@
 out_no_root:
 	printk("nfs_read_super: get root inode failed\n");
 	iput(root_inode);
-	goto out_free_fh;
-
-out_no_fattr:
-	printk("nfs_read_super: get root fattr failed\n");
-out_free_fh:
 	nfs_fh_free(root_fh);
 out_no_fh:
 	rpciod_down();
@@ -366,21 +498,33 @@
 static int
 nfs_statfs(struct super_block *sb, struct statfs *buf)
 {
-	int error;
+	struct nfs_server *server = &sb->u.nfs_sb.s_server;
+	unsigned char blockbits;
+	unsigned long blockres;
 	struct nfs_fsinfo res;
+	int error;
 
-	error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
-		&res);
-	if (error) {
-		printk("nfs_statfs: statfs error = %d\n", -error);
-		res.bsize = res.blocks = res.bfree = res.bavail = -1;
-	}
+	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res);
 	buf->f_type = NFS_SUPER_MAGIC;
-	buf->f_bsize = res.bsize;
-	buf->f_blocks = res.blocks;
-	buf->f_bfree = res.bfree;
-	buf->f_bavail = res.bavail;
-	buf->f_namelen = NAME_MAX;
+	if (error < 0)
+		goto out_err;
+
+	if (res.bsize == 0)
+		res.bsize = sb->s_blocksize;
+	buf->f_bsize = nfs_block_bits(res.bsize, &blockbits);
+	blockres = (1 << blockbits) - 1;
+	buf->f_blocks = (res.tbytes + blockres) >> blockbits;
+	buf->f_bfree = (res.fbytes + blockres) >> blockbits;
+	buf->f_bavail = (res.abytes + blockres) >> blockbits;
+	buf->f_files = res.tfiles;
+	buf->f_ffree = res.afiles;
+	if (res.namelen == 0 || res.namelen > server->namelen)
+		res.namelen = server->namelen;
+	buf->f_namelen = res.namelen;
+	return 0;
+ out_err:
+	printk("nfs_statfs: statfs error = %d\n", -error);
+	buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
 	return 0;
 }
 
@@ -429,11 +573,12 @@
 nfs_zap_caches(struct inode *inode)
 {
 	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
-	NFS_CACHEINV(inode);
+	NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 
 	invalidate_inode_pages(inode);
-	if (S_ISDIR(inode->i_mode))
-		nfs_flush_dircache(inode);
+
+	memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+	NFS_CACHEINV(inode);
 }
 
 /*
@@ -481,9 +626,16 @@
 		 * Preset the size and mtime, as there's no need
 		 * to invalidate the caches.
 		 */ 
-		inode->i_size  = fattr->size;
-		inode->i_mtime = fattr->mtime.seconds;
-		NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+		inode->i_size  = nfs_size_to_loff_t(fattr->size);
+		inode->i_mtime = nfs_time_to_secs(fattr->mtime);
+		inode->i_atime = nfs_time_to_secs(fattr->atime);
+		inode->i_ctime = nfs_time_to_secs(fattr->ctime);
+		NFS_CACHE_CTIME(inode) = fattr->ctime;
+		NFS_CACHE_MTIME(inode) = fattr->mtime;
+		NFS_CACHE_ATIME(inode) = fattr->atime;
+		NFS_CACHE_ISIZE(inode) = fattr->size;
+		NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 	}
 	nfs_refresh_inode(inode, fattr);
 }
@@ -551,9 +703,9 @@
 {
 	struct super_block *sb = dentry->d_sb;
 
-	dprintk("NFS: nfs_fhget(%s/%s fileid=%d)\n",
+	dprintk("NFS: nfs_fhget(%s/%s fileid=%Ld)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
-		fattr->fileid);
+		(long long)fattr->fileid);
 
 	/* Install the file handle in the dentry */
 	*((struct nfs_fh *) dentry->d_fsdata) = *fhandle;
@@ -572,7 +724,7 @@
 		inode->i_sb = sb;
 		inode->i_dev = sb->s_dev;
 		inode->i_flags = 0;
-		inode->i_ino = fattr->fileid;
+		inode->i_ino = nfs_fattr_to_ino_t(fattr);
 		nfs_read_inode(inode);
 		nfs_fill_inode(inode, fattr);
 		inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
@@ -598,12 +750,15 @@
 	struct inode *inode = NULL;
 	unsigned long ino;
 
+	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+		goto out_no_inode;
+
 	if (!fattr->nlink) {
 		printk("NFS: Buggy server - nlink == 0!\n");
 		goto out_no_inode;
 	}
 
-	ino = fattr->fileid;
+	ino = nfs_fattr_to_ino_t(fattr);
 
 	while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
 
@@ -666,8 +821,7 @@
 	if (error)
 		goto out;
 
-	error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry),
-				&fattr, attr);
+	error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
 	if (error)
 		goto out;
 	/*
@@ -676,13 +830,21 @@
 	 */
 	if (attr->ia_valid & ATTR_SIZE) {
 		if (attr->ia_size != fattr.size)
-			printk("nfs_notify_change: attr=%Ld, fattr=%d??\n",
-			       (long long) attr->ia_size, fattr.size);
-		inode->i_mtime = fattr.mtime.seconds;
+			printk("nfs_notify_change: attr=%Ld, fattr=%Ld??\n",
+			       (long long) attr->ia_size, (long long)fattr.size);
 		vmtruncate(inode, attr->ia_size);
 	}
-	if (attr->ia_valid & ATTR_MTIME)
-		inode->i_mtime = fattr.mtime.seconds;
+
+	/*
+	 * If we changed the size or mtime, update the inode
+	 * now to avoid invalidating the page cache.
+	 */
+	if (!(fattr.valid & NFS_ATTR_WCC)) {
+		fattr.pre_size = NFS_CACHE_ISIZE(inode);
+		fattr.pre_mtime = NFS_CACHE_MTIME(inode);
+		fattr.pre_ctime = NFS_CACHE_CTIME(inode);
+		fattr.valid |= NFS_ATTR_WCC;
+	}
 	error = nfs_refresh_inode(inode, &fattr);
 out:
 	return error;
@@ -695,24 +857,13 @@
 int
 nfs_wait_on_inode(struct inode *inode, int flag)
 {
-	struct task_struct	*tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-	int			intr, error = 0;
-
-	intr = NFS_SERVER(inode)->flags & NFS_MOUNT_INTR;
-	add_wait_queue(&inode->i_wait, &wait);
-	for (;;) {
-		set_task_state(tsk, (intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE));
-		error = 0;
-		if (!(NFS_FLAGS(inode) & flag))
-			break;
-		error = -ERESTARTSYS;
-		if (intr && signalled())
-			break;
-		schedule();
-	}
-	set_task_state(tsk, TASK_RUNNING);
-	remove_wait_queue(&inode->i_wait, &wait);
+	struct rpc_clnt	*clnt = NFS_CLIENT(inode);
+	int error;
+	if (!(NFS_FLAGS(inode) & flag))
+		return 0;
+	inode->i_count++;
+	error = nfs_wait_event(clnt, inode->i_wait, !(NFS_FLAGS(inode) & flag));
+	iput(inode);
 	return error;
 }
 
@@ -768,30 +919,32 @@
 	}
 	NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
 
-	status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr);
+	status = NFS_PROTO(inode)->getattr(dentry, &fattr);
 	if (status) {
+		struct dentry *dir = dentry->d_parent;
+		struct inode *dir_i = dir->d_inode;
 		int error;
 		u32 *fh;
 		struct nfs_fh fhandle;
 		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
-			dentry->d_parent->d_name.name,
-			dentry->d_name.name, inode->i_ino, status);
+			 dir->d_name.name, dentry->d_name.name,
+			 inode->i_ino, status);
 		if (status != -ESTALE)
 			goto out;
 		/*
 		 * A "stale filehandle" error ... show the current fh
 		 * and find out what the filehandle should be.
 		 */
-		fh = (u32 *) NFS_FH(dentry);
+		fh = (u32 *) NFS_FH(dentry)->data;
 		dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
 			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
-		error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent), 
-					dentry->d_name.name, &fhandle, &fattr);
+		error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name,
+						 &fhandle, &fattr);
 		if (error) {
 			dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
 			goto out;
 		}
-		fh = (u32 *) &fhandle;
+		fh = (u32 *) fhandle.data;
 		dfprintk(PAGECACHE, "            %08x%08x%08x%08x%08x%08x%08x%08x\n",
 			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
 		goto out;
@@ -827,19 +980,37 @@
 int
 nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
-	int invalid = 0;
-	int error = -EIO;
-
-	dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
-		 inode->i_dev, inode->i_ino, inode->i_count);
+	__u64		new_size, new_mtime;
+	loff_t		new_isize;
+	int		invalid = 0;
+	int		error = -EIO;
 
 	if (!inode || !fattr) {
-		printk("nfs_refresh_inode: inode or fattr is NULL\n");
+		printk(KERN_ERR "nfs_refresh_inode: inode or fattr is NULL\n");
+		goto out;
+	}
+	if (inode->i_mode == 0) {
+		printk(KERN_ERR "nfs_refresh_inode: empty inode\n");
 		goto out;
 	}
-	if (inode->i_ino != fattr->fileid) {
-		printk("nfs_refresh_inode: mismatch, ino=%ld, fattr=%d\n",
-			inode->i_ino, fattr->fileid);
+
+	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+		goto out;
+
+	if (is_bad_inode(inode))
+		goto out;
+
+	dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d info=0x%x)\n",
+			inode->i_dev, inode->i_ino, inode->i_count,
+			fattr->valid);
+
+
+	if (NFS_FSID(inode) != fattr->fsid ||
+	    NFS_FILEID(inode) != fattr->fileid) {
+		printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n"
+		       "expected (0x%Lx/0x%Lx), got (0x%Lx/0x%Lx)\n",
+		       (long long)NFS_FSID(inode), (long long)NFS_FILEID(inode),
+		       (long long)fattr->fsid, (long long)fattr->fileid);
 		goto out;
 	}
 
@@ -849,54 +1020,101 @@
 	if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
 		goto out_changed;
 
-	inode->i_mode = fattr->mode;
-	inode->i_nlink = fattr->nlink;
-	inode->i_uid = fattr->uid;
-	inode->i_gid = fattr->gid;
+ 	new_mtime = fattr->mtime;
+	new_size = fattr->size;
+ 	new_isize = nfs_size_to_loff_t(fattr->size);
 
-	inode->i_blocks = fattr->blocks;
-	inode->i_atime = fattr->atime.seconds;
-	inode->i_ctime = fattr->ctime.seconds;
+	error = 0;
 
 	/*
 	 * Update the read time so we don't revalidate too often.
 	 */
 	NFS_READTIME(inode) = jiffies;
-	error = 0;
 
 	/*
-	 * If we have pending write-back entries, we don't want
-	 * to look at the size or the mtime the server sends us
-	 * too closely, as we're in the middle of modifying them.
+	 * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache.
+	 *       NOT inode->i_size!!!
 	 */
-	if (nfs_have_writebacks(inode))
-		goto out;
-
-	if (inode->i_size != fattr->size) {
+	if (NFS_CACHE_ISIZE(inode) != new_size) {
 #ifdef NFS_DEBUG_VERBOSE
-printk("NFS: size change on %x/%ld\n", inode->i_dev, inode->i_ino);
+		printk(KERN_DEBUG "NFS: isize change on %x/%ld\n", inode->i_dev, inode->i_ino);
 #endif
-		inode->i_size = fattr->size;
 		invalid = 1;
 	}
 
-	if (inode->i_mtime != fattr->mtime.seconds) {
+	/*
+	 * Note: we don't check inode->i_mtime since pipes etc.
+	 *       can change this value in VFS without requiring a
+	 *	 cache revalidation.
+	 */
+	if (NFS_CACHE_MTIME(inode) != new_mtime) {
 #ifdef NFS_DEBUG_VERBOSE
-printk("NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
+		printk(KERN_DEBUG "NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
 #endif
-		inode->i_mtime = fattr->mtime.seconds;
 		invalid = 1;
 	}
 
-	if (invalid)
-		goto out_invalid;
+	/* Check Weak Cache Consistency data.
+	 * If size and mtime match the pre-operation values, we can
+	 * assume that any attribute changes were caused by our NFS
+         * operation, so there's no need to invalidate the caches.
+         */
+        if ((fattr->valid & NFS_ATTR_WCC)
+	    && NFS_CACHE_ISIZE(inode) == fattr->pre_size
+	    && NFS_CACHE_MTIME(inode) == fattr->pre_mtime) {
+		invalid = 0;
+	}
+
+	/*
+	 * If we have pending writebacks, things can get
+	 * messy.
+	 */
+	if (nfs_have_writebacks(inode) && new_isize < inode->i_size)
+		new_isize = inode->i_size;
+
+	NFS_CACHE_CTIME(inode) = fattr->ctime;
+	inode->i_ctime = nfs_time_to_secs(fattr->ctime);
+	/* If we've been messing around with atime, don't
+	 * update it. Save the server value in NFS_CACHE_ATIME.
+	 */
+	NFS_CACHE_ATIME(inode) = fattr->atime;
+	if (time_before(inode->i_atime, nfs_time_to_secs(fattr->atime)))
+		inode->i_atime = nfs_time_to_secs(fattr->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;
+ 	}
+ 	inode->i_rdev = 0;
+ 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ 		inode->i_rdev = to_kdev_t(fattr->rdev);
+ 
 	/* Update attrtimeo value */
-	if (fattr->mtime.seconds == NFS_OLDMTIME(inode)) {
+	if (!invalid && time_after(jiffies, NFS_ATTRTIMEO_UPDATE(inode)+NFS_ATTRTIMEO(inode))) {
 		if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
 			NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
+		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 	}
-	NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+
+	if (invalid)
+		nfs_zap_caches(inode);
 
 out:
 	return error;
@@ -906,22 +1124,16 @@
 	 * Big trouble! The inode has become a different object.
 	 */
 #ifdef NFS_PARANOIA
-printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
-inode->i_ino, inode->i_mode, fattr->mode);
+	printk(KERN_DEBUG "nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
+	       inode->i_ino, inode->i_mode, fattr->mode);
 #endif
 	/*
 	 * No need to worry about unhashing the dentry, as the
 	 * lookup validation will know that the inode is bad.
+	 * (But we fall through to invalidate the caches.)
 	 */
 	nfs_invalidate_inode(inode);
 	goto out;
-
-out_invalid:
-#ifdef NFS_DEBUG_VERBOSE
-printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
-#endif
-	nfs_zap_caches(inode);
-	goto out;
 }
 
 /*
@@ -930,7 +1142,9 @@
 static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, 0);
 
 extern int nfs_init_fhcache(void);
+extern void nfs_destroy_fhcache(void);
 extern int nfs_init_nfspagecache(void);
+extern void nfs_destroy_nfspagecache(void);
 
 /*
  * Initialize NFS
@@ -972,6 +1186,8 @@
 void
 cleanup_module(void)
 {
+	nfs_destroy_nfspagecache();
+	nfs_destroy_fhcache();
 #ifdef CONFIG_PROC_FS
 	rpc_proc_unregister("nfs");
 #endif
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/mount_clnt.c linux/fs/nfs/mount_clnt.c
--- v2.3.99-pre3/linux/fs/nfs/mount_clnt.c	Sun Nov  7 16:37:34 1999
+++ linux/fs/nfs/mount_clnt.c	Sat Apr  1 08:04:27 2000
@@ -30,7 +30,9 @@
 #define MOUNT_UMNT		3
  */
 
-static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *);
+static int			nfs_gen_mount(struct sockaddr_in *,
+					      char *, struct nfs_fh *, int);
+static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *, int);
 extern struct rpc_program	mnt_program;
 
 struct mnt_fhstatus {
@@ -44,24 +46,38 @@
 int
 nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
 {
+	return nfs_gen_mount(addr, path, fh, NFS_MNT_VERSION);
+}
+
+int
+nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
+{
+	return nfs_gen_mount(addr, path, fh, NFS_MNT3_VERSION);
+}
+
+static int
+nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, int version)
+{
 	struct rpc_clnt		*mnt_clnt;
 	struct mnt_fhstatus	result = { 0, fh };
 	char			hostname[32];
 	int			status;
+	int			call;
 
 	dprintk("NFS:      nfs_mount(%08x:%s)\n",
 			(unsigned)ntohl(addr->sin_addr.s_addr), path);
 
 	strcpy(hostname, in_ntoa(addr->sin_addr.s_addr));
-	if (!(mnt_clnt = mnt_create(hostname, addr)))
+	if (!(mnt_clnt = mnt_create(hostname, addr, version)))
 		return -EACCES;
 
-	status = rpc_call(mnt_clnt, NFS_MNTPROC_MNT, path, &result, 0);
+	call = (version == 3) ? MOUNTPROC3_MNT : MNTPROC_MNT;
+	status = rpc_call(mnt_clnt, call, path, &result, 0);
 	return status < 0? status : (result.status? -EACCES : 0);
 }
 
 static struct rpc_clnt *
-mnt_create(char *hostname, struct sockaddr_in *srvaddr)
+mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version)
 {
 	struct rpc_xprt	*xprt;
 	struct rpc_clnt	*clnt;
@@ -70,7 +86,7 @@
 		return NULL;
 
 	clnt = rpc_create_client(xprt, hostname,
-				&mnt_program, NFS_MNT_VERSION,
+				&mnt_program, version,
 				RPC_AUTH_NULL);
 	if (!clnt) {
 		xprt_destroy(xprt);
@@ -104,8 +120,26 @@
 static int
 xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
 {
-	if ((res->status = ntohl(*p++)) == 0)
-		memcpy(res->fh, p, sizeof(*res->fh));
+	memset((u8 *)res, 0, sizeof(*res));
+	if ((res->status = ntohl(*p++)) == 0) {
+		res->fh->size = NFS2_FHSIZE;
+		memcpy(res->fh->data, p, NFS2_FHSIZE);
+	}
+	return 0;
+}
+
+static int
+xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
+{
+	memset((u8 *)res, 0, sizeof(*res));
+	if ((res->status = ntohl(*p++)) == 0) {
+		int size = ntohl(*p++);
+		if (size <= NFS3_FHSIZE) {
+			res->fh->size = size;
+			memcpy(res->fh->data, p, res->fh->size);
+		} else
+			res->status = -EBADHANDLE;
+	}
 	return 0;
 }
 
@@ -122,13 +156,30 @@
 		MNT_dirpath_sz << 2, 0 },
 };
 
+static struct rpc_procinfo mnt3_procedures[2] = {
+	{ "mnt3_null",
+		(kxdrproc_t) xdr_error,
+		(kxdrproc_t) xdr_error, 0, 0 },
+	{ "mnt3_mount",
+		(kxdrproc_t) xdr_encode_dirpath,
+		(kxdrproc_t) xdr_decode_fhstatus3,
+		MNT_dirpath_sz << 2, 0 },
+};
+
+
 static struct rpc_version	mnt_version1 = {
 	1, 2, mnt_procedures
 };
 
+static struct rpc_version       mnt_version3 = {
+	3, 2, mnt3_procedures
+};
+
 static struct rpc_version *	mnt_version[] = {
 	NULL,
 	&mnt_version1,
+	NULL,
+	&mnt_version3,
 };
 
 static struct rpc_stat		mnt_stats;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/nfs2xdr.c linux/fs/nfs/nfs2xdr.c
--- v2.3.99-pre3/linux/fs/nfs/nfs2xdr.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/nfs/nfs2xdr.c	Sat Apr  1 08:04:27 2000
@@ -1,14 +1,14 @@
 /*
- * linux/fs/nfs/xdr.c
+ * linux/fs/nfs/nfs2xdr.c
  *
  * XDR functions to encode/decode NFS RPC arguments and results.
  *
  * Copyright (C) 1992, 1993, 1994  Rick Sladkey
  * Copyright (C) 1996 Olaf Kirch
+ * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
+ * 		FIFO's need special handling in NFSv2
  */
 
-#define NFS_NEED_XDR_TYPES
-
 #include <linux/param.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -20,6 +20,8 @@
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
 
 /* Uncomment this to support servers requiring longword lengths */
@@ -28,8 +30,7 @@
 #define NFSDBG_FACILITY		NFSDBG_XDR
 /* #define NFS_PARANOIA 1 */
 
-#define QUADLEN(len)		(((len) + 3) >> 2)
-static int			nfs_stat_to_errno(int stat);
+extern int			nfs_stat_to_errno(int stat);
 
 /* Mapping from NFS error code to "errno" error code. */
 #define errno_NFSERR_IO		EIO
@@ -40,8 +41,8 @@
  */
 #define NFS_fhandle_sz		8
 #define NFS_sattr_sz		8
-#define NFS_filename_sz		1+(NFS_MAXNAMLEN>>2)
-#define NFS_path_sz		1+(NFS_MAXPATHLEN>>2)
+#define NFS_filename_sz		1+(NFS2_MAXNAMLEN>>2)
+#define NFS_path_sz		1+(NFS2_MAXPATHLEN>>2)
 #define NFS_fattr_sz		17
 #define NFS_info_sz		5
 #define NFS_entry_sz		NFS_filename_sz+3
@@ -49,6 +50,7 @@
 #define NFS_enc_void_sz		0
 #define NFS_diropargs_sz	NFS_fhandle_sz+NFS_filename_sz
 #define NFS_sattrargs_sz	NFS_fhandle_sz+NFS_sattr_sz
+#define NFS_readlinkargs_sz	NFS_fhandle_sz
 #define NFS_readargs_sz		NFS_fhandle_sz+3
 #define NFS_writeargs_sz	NFS_fhandle_sz+4
 #define NFS_createargs_sz	NFS_diropargs_sz+NFS_sattr_sz
@@ -56,14 +58,13 @@
 #define NFS_linkargs_sz		NFS_fhandle_sz+NFS_diropargs_sz
 #define NFS_symlinkargs_sz	NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
 #define NFS_readdirargs_sz	NFS_fhandle_sz+2
-#define NFS_readlinkargs_sz	NFS_fhandle_sz
 
 #define NFS_dec_void_sz		0
 #define NFS_attrstat_sz		1+NFS_fattr_sz
 #define NFS_diropres_sz		1+NFS_fhandle_sz+NFS_fattr_sz
 #define NFS_readlinkres_sz	1
 #define NFS_readres_sz		1+NFS_fattr_sz+1
-#define NFS_writeres_sz		NFS_attrstat_sz
+#define NFS_writeres_sz         NFS_attrstat_sz
 #define NFS_stat_sz		1
 #define NFS_readdirres_sz	1
 #define NFS_statfsres_sz	1+NFS_info_sz
@@ -74,15 +75,19 @@
 static inline u32 *
 xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
 {
-	*((struct nfs_fh *) p) = *fhandle;
-	return p + QUADLEN(sizeof(*fhandle));
+	memcpy(p, fhandle->data, NFS2_FHSIZE);
+	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
 static inline u32 *
 xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
 {
-	*fhandle = *((struct nfs_fh *) p);
-	return p + QUADLEN(sizeof(*fhandle));
+	/* Zero handle first to allow comparisons */
+	memset(fhandle, 0, sizeof(*fhandle));
+	/* NFSv2 handles have a fixed length */
+	fhandle->size = NFS2_FHSIZE;
+	memcpy(fhandle->data, p, NFS2_FHSIZE);
+	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
 static inline u32 *
@@ -93,7 +98,14 @@
 	if (*len > maxlen)
 		return NULL;
 	*string = (char *) p;
-	return p + QUADLEN(*len);
+	return p + XDR_QUADLEN(*len);
+}
+
+static inline u32*
+xdr_decode_time(u32 *p, u64 *timep)
+{
+	*timep = ((u64)ntohl(*p++) << 32) + (u64)ntohl(*p++);
+	return p;
 }
 
 static inline u32 *
@@ -105,21 +117,23 @@
 	fattr->uid = ntohl(*p++);
 	fattr->gid = ntohl(*p++);
 	fattr->size = ntohl(*p++);
-	fattr->blocksize = ntohl(*p++);
+	fattr->du.nfs2.blocksize = ntohl(*p++);
 	fattr->rdev = ntohl(*p++);
-	fattr->blocks = ntohl(*p++);
+	fattr->du.nfs2.blocks = ntohl(*p++);
 	fattr->fsid = ntohl(*p++);
 	fattr->fileid = ntohl(*p++);
-	fattr->atime.seconds = ntohl(*p++);
-	fattr->atime.useconds = ntohl(*p++);
-	fattr->mtime.seconds = ntohl(*p++);
-	fattr->mtime.useconds = ntohl(*p++);
-	fattr->ctime.seconds = ntohl(*p++);
-	fattr->ctime.useconds = ntohl(*p++);
+	p = xdr_decode_time(p, &fattr->atime);
+	p = xdr_decode_time(p, &fattr->mtime);
+	p = xdr_decode_time(p, &fattr->ctime);
+	fattr->valid |= NFS_ATTR_FATTR;
+	if (fattr->type == NFCHR && fattr->rdev == NFS2_FIFO_DEV) {
+		fattr->type = NFFIFO;
+		fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
+		fattr->rdev = 0;
+	}
 	return p;
 }
 
-
 #define SATTR(p, attr, flag, field) \
         *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
 static inline u32 *
@@ -194,7 +208,7 @@
 nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
-	p = xdr_encode_string(p, args->name);
+	p = xdr_encode_array(p, args->name, args->len);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
@@ -208,7 +222,8 @@
 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		replen, buflen;
+	int		buflen, replen;
+	unsigned int	nr;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	*p++ = htonl(args->offset);
@@ -216,16 +231,25 @@
 	*p++ = htonl(args->count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
+	/* Get the number of buffers in the receive iovec */
+        nr = args->nriov;
+
+        if (nr+2 > MAX_IOVEC) {
+                printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
+                return -EINVAL;
+        }
+
 	/* set up reply iovec */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
 	buflen = req->rq_rvec[0].iov_len;
 	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->count;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
+        /* Copy the iovec */
+        memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
+
+	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[nr+1].iov_len  = buflen - replen;
 	req->rq_rlen = args->count + buflen;
-	req->rq_rnr = 3;
+	req->rq_rnr += nr+1;
 
 	return 0;
 }
@@ -239,7 +263,6 @@
 	struct iovec *iov = req->rq_rvec;
 	int	status, count, recvd, hdrlen;
 
-	dprintk("RPC:      readres OK status %lx\n", (long)ntohl(*p));
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 	p = xdr_decode_fattr(p, res->fattr);
@@ -247,22 +270,26 @@
 	count = ntohl(*p++);
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	recvd = req->rq_rlen - hdrlen;
-	if (p != iov[2].iov_base) {
+	if (p != iov[req->rq_rnr-1].iov_base) {
 		/* Unexpected reply header size. Punt.
 		 * XXX: Move iovec contents to align data on page
 		 * boundary and adjust RPC header size guess */
-		printk("NFS: Odd RPC header size in read reply: %d\n", hdrlen);
+		printk(KERN_WARNING "NFS: Odd RPC header size in read reply: %d\n", hdrlen);
 		return -errno_NFSERR_IO;
 	}
 	if (count > recvd) {
-		printk("NFS: server cheating in read reply: "
+		printk(KERN_WARNING "NFS: server cheating in read reply: "
 			"count %d > recvd %d\n", count, recvd);
 		count = recvd;
 	}
 
 	dprintk("RPC:      readres OK count %d\n", count);
-	if (count < res->count)
-		memset((u8 *)(iov[1].iov_base+count), 0, res->count-count);
+	if (count < res->count) {
+		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
+		res->count = count;
+		res->eof = 1;  /* Silly NFSv3ism which can't be helped */
+	} else
+		res->eof = 0;
 
 	return count;
 }
@@ -288,13 +315,13 @@
 	nr = args->nriov;
 
 	if (nr+2 > MAX_IOVEC) {
-		printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs "
-			"(nr %d max %d)\n", nr, MAX_IOVEC);
-		return -EINVAL;
-	}
+                printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs "
+                        "(nr %d max %d)\n", nr, MAX_IOVEC);
+                return -EINVAL;
+        }
 
 	/* Copy the iovec */
-	memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
+        memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
 
 #ifdef NFS_PAD_WRITES
 	/*
@@ -325,7 +352,7 @@
 nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
-	p = xdr_encode_string(p, args->name);
+	p = xdr_encode_array(p, args->name, args->len);
 	p = xdr_encode_sattr(p, args->sattr);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
@@ -338,9 +365,9 @@
 nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
-	p = xdr_encode_string(p, args->fromname);
+	p = xdr_encode_array(p, args->fromname, args->fromlen);
 	p = xdr_encode_fhandle(p, args->tofh);
-	p = xdr_encode_string(p, args->toname);
+	p = xdr_encode_array(p, args->toname, args->tolen);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
@@ -353,7 +380,7 @@
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
 	p = xdr_encode_fhandle(p, args->tofh);
-	p = xdr_encode_string(p, args->toname);
+	p = xdr_encode_array(p, args->toname, args->tolen);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
@@ -365,8 +392,8 @@
 nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
-	p = xdr_encode_string(p, args->fromname);
-	p = xdr_encode_string(p, args->topath);
+	p = xdr_encode_array(p, args->fromname, args->fromlen);
+	p = xdr_encode_array(p, args->topath, args->tolen);
 	p = xdr_encode_sattr(p, args->sattr);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
@@ -380,108 +407,113 @@
 {
 	struct rpc_task	*task = req->rq_task;
 	struct rpc_auth	*auth = task->tk_auth;
-	int		bufsiz = args->bufsiz;
-	int		replen;
+	u32		bufsiz = args->bufsiz;
+	int		buflen, replen;
 
-	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->cookie);
-
-	/* Some servers (e.g. HP OS 9.5) seem to expect the buffer size
+	/*
+	 * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
 	 * to be in longwords ... check whether to convert the size.
 	 */
 	if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE)
-		*p++ = htonl(bufsiz >> 2);
-	else
-		*p++ = htonl(bufsiz);
+		bufsiz = bufsiz >> 2;
 
+	p = xdr_encode_fhandle(p, args->fh);
+	*p++ = htonl(args->cookie);
+	*p++ = htonl(bufsiz); /* see above */
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
 	/* set up reply iovec */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
+	buflen = req->rq_rvec[0].iov_len;
 	req->rq_rvec[0].iov_len  = replen;
 	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = bufsiz;
-	req->rq_rlen = replen + bufsiz;
-	req->rq_rnr = 2;
+	req->rq_rvec[1].iov_len  = args->bufsiz;
+	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[2].iov_len  = buflen - replen;
+	req->rq_rlen = buflen + args->bufsiz;
+	req->rq_rnr += 2;
 
 	return 0;
 }
 
 /*
  * Decode the result of a readdir call.
+ * We're not really decoding anymore, we just leave the buffer untouched
+ * and only check that it is syntactically correct.
+ * The real decoding happens in nfs_decode_entry below, called directly
+ * from nfs_readdir for each entry.
  */
-#define NFS_DIRENT_MAXLEN	(5 * sizeof(u32) + (NFS_MAXNAMLEN + 1))
 static int
 nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
 {
 	struct iovec		*iov = req->rq_rvec;
 	int			 status, nr;
-	u32			*end;
-	u32			last_cookie = res->cookie;
+	u32			*end, *entry, len;
 
-	status = ntohl(*p++);
-	if (status) {
-		nr = -nfs_stat_to_errno(status);
-		goto error;
-	}
+	if ((status = ntohl(*p++)))
+		return -nfs_stat_to_errno(status);
 	if ((void *) p != ((u8 *) iov->iov_base+iov->iov_len)) {
 		/* Unexpected reply header size. Punt. */
-		printk("NFS: Odd RPC header size in readdirres reply\n");
-		nr = -errno_NFSERR_IO;
-		goto error;
+		printk(KERN_WARNING "NFS: Odd RPC header size in readdirres reply\n");
+		return -errno_NFSERR_IO;
 	}
 
-	/* Get start and end address of XDR readdir response. */
+	/* Get start and end address of XDR data */
 	p   = (u32 *) iov[1].iov_base;
 	end = (u32 *) ((u8 *) p + iov[1].iov_len);
-	for (nr = 0; *p++; nr++) {
-		__u32 len;
 
-		/* Convert fileid. */
-		*p = ntohl(*p);
-		p++;
-
-		/* Convert and capture len */
-		len = *p = ntohl(*p);
-		p++;
-
-		if ((p + QUADLEN(len) + 3) > end) {
-			struct rpc_clnt *clnt = req->rq_task->tk_client;
-
-			clnt->cl_flags |= NFS_CLNTF_BUFSIZE;
-			p -= 2;
-			p[-1] = 0;
-			p[0] = 0;
-			break;
+	/* Get start and end of dirent buffer */
+	if (res->buffer != p) {
+		printk(KERN_ERR "NFS: Bad result buffer in readdir\n");
+		return -errno_NFSERR_IO;
+	}
+
+	for (nr = 0; *p++; nr++) {
+		entry = p - 1;
+		p++; /* fileid */
+		len = ntohl(*p++);
+		p += XDR_QUADLEN(len) + 1;	/* name plus cookie */
+		if (len > NFS2_MAXNAMLEN) {
+			printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
+						len);
+			return -errno_NFSERR_IO;
 		}
-		if (len > NFS_MAXNAMLEN) {
-			nr = -errno_NFSERR_IO;
-			goto error;
+		if (p + 2 > end) {
+			printk(KERN_NOTICE
+				"NFS: short packet in readdir reply!\n");
+			entry[0] = entry[1] = 0;
+			break;
 		}
-		p += QUADLEN(len);
+	}
+	p++; /* EOF flag */
 
-		/* Convert and capture cookie. */
-		last_cookie = *p = ntohl(*p);
-		p++;
-	}
-	p -= 1;
-	status = ((end - p) << 2);
-	if (!p[1] && (status >= NFS_DIRENT_MAXLEN)) {
-		status = ((__u8 *)p - (__u8 *)iov[1].iov_base);
-		res->buffer += status;
-		res->bufsiz -= status;
-	} else if (p[1]) {
-		status = (int)((long)p & ~PAGE_CACHE_MASK);
-		res->bufsiz = -status;
-	} else {
-		res->bufsiz = 0;
+	if (p > end) {
+		printk(KERN_NOTICE
+			"NFS: short packet in readdir reply!\n");
+		return -errno_NFSERR_IO;
 	}
-	res->cookie = last_cookie;
 	return nr;
+}
 
-error:
-	res->bufsiz = 0;
-	return nr;
+u32 *
+nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+{
+	if (!*p++) {
+		if (!*p)
+			return ERR_PTR(-EAGAIN);
+		entry->eof = 1;
+		return ERR_PTR(-EBADCOOKIE);
+	}
+
+	entry->ino	  = ntohl(*p++);
+	entry->len	  = ntohl(*p++);
+	entry->name	  = (const char *) p;
+	p		 += XDR_QUADLEN(entry->len);
+	entry->prev_cookie	  = entry->cookie;
+	entry->cookie	  = ntohl(*p++);
+	entry->eof	  = !p[0] && p[1];
+
+	return p;
 }
 
 /*
@@ -518,12 +550,9 @@
 {
 	int	status;
 
-	dprintk("RPC:      attrstat status %lx\n", (long)ntohl(*p));
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 	xdr_decode_fattr(p, fattr);
-	dprintk("RPC:      attrstat OK type %d mode %o dev %x ino %x\n",
-		fattr->type, fattr->mode, fattr->fsid, fattr->fileid);
 	return 0;
 }
 
@@ -536,36 +565,34 @@
 {
 	int	status;
 
-	dprintk("RPC:      diropres status %lx\n", (long)ntohl(*p));
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 	p = xdr_decode_fhandle(p, res->fh);
 	xdr_decode_fattr(p, res->fattr);
-	dprintk("RPC:      diropres OK type %x mode %o dev %x ino %x\n",
-		res->fattr->type, res->fattr->mode,
-		res->fattr->fsid, res->fattr->fileid);
 	return 0;
 }
 
 /*
- * Encode arguments to readlink call
+ * Encode READLINK args
  */
-static int nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
+static int
+nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
 {
 	struct rpc_task *task = req->rq_task;
 	struct rpc_auth *auth = task->tk_auth;
-	int bufsiz = NFS_MAXPATHLEN;
-	int replen;
+	int		buflen, replen;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
-	req->rq_rvec[0].iov_len = replen;
-	req->rq_rvec[1].iov_base = (void *) args->buffer;
-	req->rq_rvec[1].iov_len = bufsiz;
-	req->rq_rlen = replen + bufsiz;
-	req->rq_rnr = 2;
-
+	buflen = req->rq_rvec[0].iov_len;
+	req->rq_rvec[0].iov_len  = replen;
+	req->rq_rvec[1].iov_base = args->buffer;
+	req->rq_rvec[1].iov_len  = args->bufsiz;
+	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[2].iov_len  = buflen - replen;
+	req->rq_rlen = buflen + args->bufsiz;
+	req->rq_rnr += 2;
 	return 0;
 }
 
@@ -573,31 +600,24 @@
  * Decode READLINK reply
  */
 static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
 {
-	struct iovec	*iov = req->rq_rvec;
-	int		status,	len;
-	char		*name;
+	u32	*strlen;
+	char	*string;
+	int	status;
+	unsigned int len;
 
-	/* Verify OK status. */
-	if ((status = ntohl(*p++)) != 0)
+	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
-
-	/* Verify OK response length. */
-	if ((__u8 *)p != ((u8 *) iov->iov_base + iov->iov_len))
-		return -errno_NFSERR_IO;
-
-	/* Convert and verify that string length is in range. */
-	p = iov[1].iov_base;
-	len = *p = ntohl(*p);
-	p++;
-	if (len > iov[1].iov_len)
-		return -errno_NFSERR_IO;
-
-	/* NULL terminate the string we got. */
-	name = (char *) p;
-	name[len] = 0;
-
+	strlen = (u32*)res->buffer;
+	/* Convert length of symlink */
+	len = ntohl(*strlen);
+	if (len > res->bufsiz - 5)
+		len = res->bufsiz - 5;
+	*strlen = len;
+	/* NULL terminate the string we got */
+	string = (char *)(strlen + 1);
+	string[len] = 0;
 	return 0;
 }
 
@@ -618,14 +638,34 @@
 nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
 {
 	int	status;
+	u32	xfer_size;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
-	res->tsize = ntohl(*p++);
-	res->bsize = ntohl(*p++);
-	res->blocks = ntohl(*p++);
-	res->bfree = ntohl(*p++);
-	res->bavail = ntohl(*p++);
+
+	/* For NFSv2, we more or less have to guess the preferred
+	 * read/write/readdir sizes from the single 'transfer size'
+	 * value.
+	 */
+	xfer_size = ntohl(*p++);	/* tsize */
+	res->rtmax  = 8 * 1024;
+	res->rtpref = xfer_size;
+	res->rtmult = xfer_size;
+	res->wtmax  = 8 * 1024;
+	res->wtpref = xfer_size;
+	res->wtmult = xfer_size;
+	res->dtpref = PAGE_CACHE_SIZE;
+	res->maxfilesize = 0x7FFFFFFF;	/* just a guess */
+	res->bsize  = ntohl(*p++);
+
+	res->tbytes = ntohl(*p++) * res->bsize;
+	res->fbytes = ntohl(*p++) * res->bsize;
+	res->abytes = ntohl(*p++) * res->bsize;
+	res->tfiles = 0;
+	res->ffiles = 0;
+	res->afiles = 0;
+	res->namelen = 0;
+
 	return 0;
 }
 
@@ -642,7 +682,7 @@
 	{ NFSERR_NOENT,		ENOENT		},
 	{ NFSERR_IO,		errno_NFSERR_IO	},
 	{ NFSERR_NXIO,		ENXIO		},
-	{ NFSERR_EAGAIN,	EAGAIN		},
+/*	{ NFSERR_EAGAIN,	EAGAIN		}, */
 	{ NFSERR_ACCES,		EACCES		},
 	{ NFSERR_EXIST,		EEXIST		},
 	{ NFSERR_XDEV,		EXDEV		},
@@ -653,18 +693,31 @@
 	{ NFSERR_FBIG,		EFBIG		},
 	{ NFSERR_NOSPC,		ENOSPC		},
 	{ NFSERR_ROFS,		EROFS		},
-	{ NFSERR_OPNOTSUPP,	EOPNOTSUPP	},
+	{ NFSERR_MLINK,		EMLINK		},
 	{ NFSERR_NAMETOOLONG,	ENAMETOOLONG	},
 	{ NFSERR_NOTEMPTY,	ENOTEMPTY	},
 	{ NFSERR_DQUOT,		EDQUOT		},
 	{ NFSERR_STALE,		ESTALE		},
+	{ NFSERR_REMOTE,	EREMOTE		},
 #ifdef EWFLUSH
 	{ NFSERR_WFLUSH,	EWFLUSH		},
 #endif
+	{ NFSERR_BADHANDLE,	EBADHANDLE	},
+	{ NFSERR_NOT_SYNC,	ENOTSYNC	},
+	{ NFSERR_BAD_COOKIE,	EBADCOOKIE	},
+	{ NFSERR_NOTSUPP,	ENOTSUPP	},
+	{ NFSERR_TOOSMALL,	ETOOSMALL	},
+	{ NFSERR_SERVERFAULT,	ESERVERFAULT	},
+	{ NFSERR_BADTYPE,	EBADTYPE	},
+	{ NFSERR_JUKEBOX,	EJUKEBOX	},
 	{ -1,			EIO		}
 };
 
-static int
+/*
+ * Convert an NFS error code to a local one.
+ * This one is used jointly by NFSv2 and NFSv3.
+ */
+int
 nfs_stat_to_errno(int stat)
 {
 	int i;
@@ -673,7 +726,7 @@
 		if (nfs_errtbl[i].stat == stat)
 			return nfs_errtbl[i].errno;
 	}
-	printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
+	printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
 	return nfs_errtbl[i].errno;
 }
 
@@ -685,7 +738,8 @@
     { "nfs_" #proc,					\
       (kxdrproc_t) nfs_xdr_##argtype,			\
       (kxdrproc_t) nfs_xdr_##restype,			\
-      MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2	\
+      MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,	\
+      0							\
     }
 
 static struct rpc_procinfo	nfs_procedures[18] = {
@@ -709,22 +763,8 @@
     PROC(statfs,	fhandle,	statfsres),
 };
 
-static struct rpc_version	nfs_version2 = {
+struct rpc_version		nfs_version2 = {
 	2,
 	sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
 	nfs_procedures
-};
-
-static struct rpc_version *	nfs_version[] = {
-	NULL,
-	NULL,
-	&nfs_version2
-};
-
-struct rpc_program	nfs_program = {
-	"nfs",
-	NFS_PROGRAM,
-	sizeof(nfs_version) / sizeof(nfs_version[0]),
-	nfs_version,
-	&nfs_rpcstat,
 };
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/nfs3proc.c linux/fs/nfs/nfs3proc.c
--- v2.3.99-pre3/linux/fs/nfs/nfs3proc.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nfs/nfs3proc.c	Sat Apr  1 08:04:27 2000
@@ -0,0 +1,477 @@
+/*
+ *  linux/fs/nfs/nfs3proc.c
+ *
+ *  Client-side NFSv3 procedures stubs.
+ *
+ *  Copyright (C) 1997, Olaf Kirch
+ */
+
+#include <linux/mm.h>
+#include <linux/utsname.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
+
+#include <asm/segment.h>
+
+#define NFSDBG_FACILITY		NFSDBG_PROC
+
+/*
+ * Bare-bones access to getattr: this is for nfs_read_super.
+ */
+static int
+nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+		   struct nfs_fattr *fattr)
+{
+	int	status;
+
+	dprintk("NFS call  getroot\n");
+	fattr->valid = 0;
+	status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0);
+	dprintk("NFS reply getroot\n");
+	return status;
+}
+
+/*
+ * One function for each procedure in the NFS protocol.
+ */
+static int
+nfs3_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr)
+{
+	int	status;
+
+	dprintk("NFS call  getattr\n");
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_GETATTR,
+			  NFS_FH(dentry), fattr, 0);
+	dprintk("NFS reply getattr\n");
+	return status;
+}
+
+static int
+nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+			struct iattr *sattr)
+{
+	struct nfs3_sattrargs	arg = { NFS_FH(dentry), sattr, 0, 0 };
+	int	status;
+
+	dprintk("NFS call  setattr\n");
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_SETATTR, &arg, fattr, 0);
+	dprintk("NFS reply setattr\n");
+	return status;
+}
+
+static int
+nfs3_proc_lookup(struct dentry *dir, struct qstr *name,
+		 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	struct nfs_fattr	dir_attr;
+	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
+	int			status;
+
+	dprintk("NFS call  lookup %s\n", name->name);
+	dir_attr.valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_LOOKUP, &arg, &res, 0);
+	if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR))
+		status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_GETATTR,
+			 fhandle, fattr, 0);
+	dprintk("NFS reply lookup: %d\n", status);
+	nfs_refresh_inode(dir->d_inode, &dir_attr);
+	return status;
+}
+
+static int
+nfs3_proc_access(struct dentry *dentry, int mode, int ruid)
+{
+	struct nfs_fattr	fattr;
+	struct nfs3_accessargs	arg = { NFS_FH(dentry), 0 };
+	struct nfs3_accessres	res = { &fattr, 0 };
+	int	status, flags;
+
+	dprintk("NFS call  access\n");
+	fattr.valid = 0;
+
+	if (mode & MAY_READ)
+		arg.access |= NFS3_ACCESS_READ;
+	if (S_ISDIR(dentry->d_inode->i_mode)) {
+		if (mode & MAY_WRITE)
+			arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE;
+		if (mode & MAY_EXEC)
+			arg.access |= NFS3_ACCESS_LOOKUP;
+	} else {
+		if (mode & MAY_WRITE)
+			arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND;
+		if (mode & MAY_EXEC)
+			arg.access |= NFS3_ACCESS_EXECUTE;
+	}
+	flags = (ruid) ? RPC_CALL_REALUID : 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_ACCESS, &arg, &res, flags);
+	nfs_refresh_inode(dentry->d_inode, &fattr);
+	dprintk("NFS reply access\n");
+
+	if (status == 0 && (arg.access & res.access) != arg.access)
+		status = -EACCES;
+	return status;
+}
+
+static int
+nfs3_proc_readlink(struct dentry *dentry, void *buffer, unsigned int buflen)
+{
+	struct nfs_fattr	fattr;
+	struct nfs3_readlinkargs args = { NFS_FH(dentry), buffer, buflen };
+	struct nfs3_readlinkres	res = { &fattr, buffer, buflen };
+	int			status;
+
+	dprintk("NFS call  readlink\n");
+	fattr.valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_READLINK,
+			  &args, &res, 0);
+	nfs_refresh_inode(dentry->d_inode, &fattr);
+	dprintk("NFS reply readlink: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+	       loff_t offset, unsigned int count, void *buffer, int *eofp)
+{
+	struct nfs_readargs	arg = { NFS_FH(dentry), offset, count, 1,
+					{{buffer, count}, {0,0}, {0,0}, {0,0},
+					 {0,0}, {0,0}, {0,0}, {0,0}} };
+	struct nfs_readres	res = { fattr, count, 0 };
+	struct rpc_message	msg = { NFS3PROC_READ, &arg, &res, NULL };
+	int			status;
+
+	dprintk("NFS call  read %d @ %Ld\n", count, (long long)offset);
+	fattr->valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+	dprintk("NFS reply read: %d\n", status);
+	*eofp = res.eof;
+	return status;
+}
+
+static int
+nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+		loff_t offset, unsigned int count,
+		void *buffer, struct nfs_writeverf *verf)
+{
+	struct nfs_writeargs	arg = { NFS_FH(dentry), offset, count,
+					NFS_FILE_SYNC, 1,
+					{{buffer, count}, {0,0}, {0,0}, {0,0},
+					 {0,0}, {0,0}, {0,0}, {0,0}} };
+	struct nfs_writeres	res = { fattr, verf, 0 };
+	struct rpc_message	msg = { NFS3PROC_WRITE, &arg, &res, NULL };
+	int			status, rpcflags = 0;
+
+	dprintk("NFS call  write %d @ %Ld\n", count, (long long)offset);
+	fattr->valid = 0;
+	if (flags & NFS_RW_SWAP)
+		rpcflags |= NFS_RPC_SWAPFLAGS;
+	arg.stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE;
+
+	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, rpcflags);
+
+	dprintk("NFS reply read: %d\n", status);
+	return status < 0? status : res.count;
+}
+
+/*
+ * Create a regular file.
+ * For now, we don't implement O_EXCL.
+ */
+static int
+nfs3_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+		 int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	struct nfs_fattr	dir_attr;
+	struct nfs3_createargs	arg = { NFS_FH(dir), name->name, name->len,
+					sattr, 0, { 0, 0 } };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
+	int			status;
+
+	dprintk("NFS call  create %s\n", name->name);
+	arg.createmode = NFS3_CREATE_UNCHECKED;
+	if (flags & O_EXCL) {
+		arg.createmode  = NFS3_CREATE_EXCLUSIVE;
+		arg.verifier[0] = jiffies;
+		arg.verifier[1] = current->pid;
+	}
+
+again:
+	dir_attr.valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_CREATE, &arg, &res, 0);
+	nfs_refresh_inode(dir->d_inode, &dir_attr);
+
+	/* If the server doesn't support the exclusive creation semantics,
+	 * try again with simple 'guarded' mode. */
+	if (status == NFSERR_NOTSUPP) {
+		switch (arg.createmode) {
+			case NFS3_CREATE_EXCLUSIVE:
+				arg.createmode = NFS3_CREATE_GUARDED;
+				break;
+
+			case NFS3_CREATE_GUARDED:
+				arg.createmode = NFS3_CREATE_UNCHECKED;
+				break;
+
+			case NFS3_CREATE_UNCHECKED:
+				goto exit;
+		}
+		goto again;
+	}
+
+exit:
+	dprintk("NFS reply create: %d\n", status);
+
+	/* When we created the file with exclusive semantics, make
+	 * sure we set the attributes afterwards. */
+	if (status == 0 && arg.createmode == NFS3_CREATE_EXCLUSIVE) {
+		struct nfs3_sattrargs	arg = { fhandle, sattr, 0, 0 };
+		dprintk("NFS call  setattr (post-create)\n");
+
+		/* Note: we could use a guarded setattr here, but I'm
+		 * not sure this buys us anything (and I'd have
+		 * to revamp the NFSv3 XDR code) */
+		fattr->valid = 0;
+		status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SETATTR,
+						&arg, fattr, 0);
+		dprintk("NFS reply setattr (post-create): %d\n", status);
+	}
+
+	return status;
+}
+
+static int
+nfs3_proc_remove(struct dentry *dir, struct qstr *name)
+{
+	struct nfs_fattr	dir_attr;
+	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
+	struct rpc_message	msg = { NFS3PROC_REMOVE, &arg, &dir_attr, NULL };
+	int			status;
+
+	dprintk("NFS call  remove %s\n", name->name);
+	dir_attr.valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	nfs_refresh_inode(dir->d_inode, &dir_attr);
+	dprintk("NFS reply remove: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_rename(struct dentry *old_dir, struct qstr *old_name,
+		 struct dentry *new_dir, struct qstr *new_name)
+{
+	struct nfs_fattr	old_dir_attr, new_dir_attr;
+	struct nfs3_renameargs	arg = { NFS_FH(old_dir),
+					old_name->name, old_name->len,
+					NFS_FH(new_dir),
+					new_name->name, new_name->len };
+	struct nfs3_renameres	res = { &old_dir_attr, &new_dir_attr };
+	int			status;
+
+	dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
+	old_dir_attr.valid = 0;
+	new_dir_attr.valid = 0;
+	status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFS3PROC_RENAME, &arg, &res, 0);
+	nfs_refresh_inode(old_dir->d_inode, &old_dir_attr);
+	nfs_refresh_inode(new_dir->d_inode, &new_dir_attr);
+	dprintk("NFS reply rename: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_link(struct dentry *dentry, struct dentry *dir, struct qstr *name)
+{
+	struct nfs_fattr	dir_attr, fattr;
+	struct nfs3_linkargs	arg = { NFS_FH(dentry), NFS_FH(dir),
+					name->name, name->len };
+	struct nfs3_linkres	res = { &dir_attr, &fattr };
+	int			status;
+
+	dprintk("NFS call  link %s\n", name->name);
+	dir_attr.valid = 0;
+	fattr.valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_LINK, &arg, &res, 0);
+	nfs_refresh_inode(dir->d_inode, &dir_attr);
+	nfs_refresh_inode(dentry->d_inode, &fattr);
+	dprintk("NFS reply link: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path,
+		  struct iattr *sattr, struct nfs_fh *fhandle,
+		  struct nfs_fattr *fattr)
+{
+	struct nfs_fattr	dir_attr;
+	struct nfs3_symlinkargs	arg = { NFS_FH(dir), name->name, name->len,
+					path->name, path->len, sattr };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
+	int			status;
+
+	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
+	dir_attr.valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SYMLINK, &arg, &res, 0);
+	nfs_refresh_inode(dir->d_inode, &dir_attr);
+	dprintk("NFS reply symlink: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+		struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	struct nfs_fattr	dir_attr;
+	struct nfs3_createargs	arg = { NFS_FH(dir), name->name, name->len,
+					sattr, 0, { 0, 0 } };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
+	int			status;
+
+	dprintk("NFS call  mkdir %s\n", name->name);
+	dir_attr.valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKDIR, &arg, &res, 0);
+	nfs_refresh_inode(dir->d_inode, &dir_attr);
+	dprintk("NFS reply mkdir: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_rmdir(struct dentry *dir, struct qstr *name)
+{
+	struct nfs_fattr	dir_attr;
+	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
+	int			status;
+
+	dprintk("NFS call  rmdir %s\n", name->name);
+	dir_attr.valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_RMDIR, &arg, &dir_attr, 0);
+	nfs_refresh_inode(dir->d_inode, &dir_attr);
+	dprintk("NFS reply rmdir: %d\n", status);
+	return status;
+}
+
+/*
+ * The READDIR implementation is somewhat hackish - we pass the user buffer
+ * to the encode function, which installs it in the receive iovec.
+ * The decode function itself doesn't perform any decoding, it just makes
+ * sure the reply is syntactically correct.
+ *
+ * Also note that this implementation handles both plain readdir and
+ * readdirplus.
+ */
+static int
+nfs3_proc_readdir(struct dentry *dir, u64 cookie, void *entry,
+		  unsigned int size, int plus)
+{
+	struct nfs_fattr	dir_attr;
+	struct nfs3_readdirargs	arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 };
+	struct nfs3_readdirres	res = { &dir_attr, 0, 0, 0, 0 };
+	struct rpc_message	msg = { NFS3PROC_READDIR, &arg, &res, NULL };
+	u32			*verf = NFS_COOKIEVERF(dir->d_inode);
+	int			status;
+
+	arg.buffer  = entry;
+	arg.bufsiz  = size;
+	arg.verf[0] = verf[0];
+	arg.verf[1] = verf[1];
+	arg.plus    = plus;
+	res.buffer  = entry;
+	res.bufsiz  = size;
+	res.verf    = verf;
+	res.plus    = plus;
+
+	if (plus)
+		msg.rpc_proc = NFS3PROC_READDIRPLUS;
+
+	dprintk("NFS call  readdir%s %d\n",
+			plus? "plus" : "", (unsigned int) cookie);
+
+	dir_attr.valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	nfs_refresh_inode(dir->d_inode, &dir_attr);
+	dprintk("NFS reply readdir: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+		dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
+{
+	struct nfs_fattr	dir_attr;
+	struct nfs3_mknodargs	arg = { NFS_FH(dir), name->name, name->len, 0,
+					sattr, rdev };
+	struct nfs3_diropres	res = { &dir_attr, fh, fattr };
+	int			status;
+
+	switch (sattr->ia_mode & S_IFMT) {
+	case S_IFBLK:	arg.type = NF3BLK;  break;
+	case S_IFCHR:	arg.type = NF3CHR;  break;
+	case S_IFIFO:	arg.type = NF3FIFO; break;
+	case S_IFSOCK:	arg.type = NF3SOCK; break;
+	default:	return -EINVAL;
+	}
+
+	dprintk("NFS call  mknod %s %x\n", name->name, rdev);
+	dir_attr.valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKNOD, &arg, &res, 0);
+	nfs_refresh_inode(dir->d_inode, &dir_attr);
+	dprintk("NFS reply mknod: %d\n", status);
+	return status;
+}
+
+/*
+ * This is a combo call of fsstat and fsinfo
+ */
+static int
+nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
+		 struct nfs_fsinfo *info)
+{
+	int	status;
+
+	dprintk("NFS call  fsstat\n");
+	memset((char *)info, 0, sizeof(*info));
+	status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, info, 0);
+	if (status < 0)
+		goto error;
+	status = rpc_call(server->client, NFS3PROC_FSINFO, fhandle, info, 0);
+
+error:
+	dprintk("NFS reply statfs: %d\n", status);
+	return status;
+}
+
+extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
+
+struct nfs_rpc_ops	nfs_v3_clientops = {
+	3,			/* protocol version */
+	nfs3_proc_get_root,
+	nfs3_proc_getattr,
+	nfs3_proc_setattr,
+	nfs3_proc_lookup,
+	nfs3_proc_access,
+	nfs3_proc_readlink,
+	nfs3_proc_read,
+	nfs3_proc_write,
+	NULL,			/* commit */
+	nfs3_proc_create,
+	nfs3_proc_remove,
+	nfs3_proc_rename,
+	nfs3_proc_link,
+	nfs3_proc_symlink,
+	nfs3_proc_mkdir,
+	nfs3_proc_rmdir,
+	nfs3_proc_readdir,
+	nfs3_proc_mknod,
+	nfs3_proc_statfs,
+	nfs3_decode_dirent,
+};
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/nfs3xdr.c linux/fs/nfs/nfs3xdr.c
--- v2.3.99-pre3/linux/fs/nfs/nfs3xdr.c	Mon Nov  1 13:56:27 1999
+++ linux/fs/nfs/nfs3xdr.c	Sat Apr  1 08:04:27 2000
@@ -1,94 +1,158 @@
 /*
- * linux/fs/nfs/nfs2xdr.c
+ * linux/fs/nfs/nfs3xdr.c
  *
  * XDR functions to encode/decode NFSv3 RPC arguments and results.
- * Note: this is incomplete!
  *
- * Copyright (C) 1996 Olaf Kirch
+ * Copyright (C) 1996, 1997 Olaf Kirch
  */
 
-#define NFS_NEED_XDR_TYPES
-
 #include <linux/param.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
-#include <linux/nfs_fs.h>
 #include <linux/utsname.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/in.h>
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
+#include <linux/kdev_t.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
 
-#ifdef RPC_DEBUG
-# define RPC_FACILITY		RPCDBG_NFS
-#endif
+/* Uncomment this to support servers requiring longword lengths */
+#define NFS_PAD_WRITES		1
 
-#define QUADLEN(len)		(((len) + 3) >> 2)
-static int			nfs_stat_to_errno(int stat);
+#define NFSDBG_FACILITY		NFSDBG_XDR
 
 /* Mapping from NFS error code to "errno" error code. */
 #define errno_NFSERR_IO		EIO
 
+extern int			nfs_stat_to_errno(int);
+
 /*
  * Declare the space requirements for NFS arguments and replies as
  * number of 32bit-words
  */
-#define NFS_fhandle_sz		(1+16)
-#define NFS_sattr_sz		8
-#define NFS_filename_sz		1+(NFS_MAXNAMLEN>>2)
-#define NFS_path_sz		1+(NFS_MAXPATHLEN>>2)
-#define NFS_fattr_sz		17
-#define NFS_info_sz		5
-#define NFS_entry_sz		NFS_filename_sz+3
-
-#define NFS_enc_void_sz		0
-#define NFS_diropargs_sz	NFS_fhandle_sz+NFS_filename_sz
-#define NFS_sattrargs_sz	NFS_fhandle_sz+NFS_sattr_sz
-#define NFS_readargs_sz		NFS_fhandle_sz+3
-#define NFS_writeargs_sz	NFS_fhandle_sz+4
-#define NFS_createargs_sz	NFS_diropargs_sz+NFS_sattr_sz
-#define NFS_renameargs_sz	NFS_diropargs_sz+NFS_diropargs_sz
-#define NFS_linkargs_sz		NFS_fhandle_sz+NFS_diropargs_sz
-#define NFS_symlinkargs_sz	NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
-#define NFS_readdirargs_sz	NFS_fhandle_sz+2
-
-#define NFS_dec_void_sz		0
-#define NFS_attrstat_sz		1+NFS_fattr_sz
-#define NFS_diropres_sz		1+NFS_fhandle_sz+NFS_fattr_sz
-#define NFS_readlinkres_sz	1+NFS_path_sz
-#define NFS_readres_sz		1+NFS_fattr_sz+1
-#define NFS_stat_sz		1
-#define NFS_readdirres_sz	1
-#define NFS_statfsres_sz	1+NFS_info_sz
+#define NFS3_fhandle_sz		1+16
+#define NFS3_fh_sz		NFS3_fhandle_sz	/* shorthand */
+#define NFS3_sattr_sz		15
+#define NFS3_filename_sz	1+(NFS3_MAXNAMLEN>>2)
+#define NFS3_path_sz		1+(NFS3_MAXPATHLEN>>2)
+#define NFS3_fattr_sz		21
+#define NFS3_wcc_attr_sz		6
+#define NFS3_pre_op_attr_sz	1+NFS3_wcc_attr_sz
+#define NFS3_post_op_attr_sz	1+NFS3_fattr_sz
+#define NFS3_wcc_data_sz		NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
+#define NFS3_fsstat_sz		
+#define NFS3_fsinfo_sz		
+#define NFS3_pathconf_sz		
+#define NFS3_entry_sz		NFS3_filename_sz+3
+
+#define NFS3_enc_void_sz	0
+#define NFS3_sattrargs_sz	NFS3_fh_sz+NFS3_sattr_sz+3
+#define NFS3_diropargs_sz	NFS3_fh_sz+NFS3_filename_sz
+#define NFS3_accessargs_sz	NFS3_fh_sz+1
+#define NFS3_readlinkargs_sz	NFS3_fh_sz
+#define NFS3_readargs_sz	NFS3_fh_sz+3
+#define NFS3_writeargs_sz	NFS3_fh_sz+5
+#define NFS3_createargs_sz	NFS3_diropargs_sz+NFS3_sattr_sz
+#define NFS3_mkdirargs_sz	NFS3_diropargs_sz+NFS3_sattr_sz
+#define NFS3_symlinkargs_sz	NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
+#define NFS3_mknodargs_sz	NFS3_diropargs_sz+2+NFS3_sattr_sz
+#define NFS3_renameargs_sz	NFS3_diropargs_sz+NFS3_diropargs_sz
+#define NFS3_linkargs_sz		NFS3_fh_sz+NFS3_diropargs_sz
+#define NFS3_readdirargs_sz	NFS3_fh_sz+2
+#define NFS3_commitargs_sz	NFS3_fh_sz+3
+
+#define NFS3_dec_void_sz	0
+#define NFS3_attrstat_sz	1+NFS3_fattr_sz
+#define NFS3_wccstat_sz		1+NFS3_wcc_data_sz
+#define NFS3_lookupres_sz	1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
+#define NFS3_accessres_sz	1+NFS3_post_op_attr_sz+1
+#define NFS3_readlinkres_sz	1+NFS3_post_op_attr_sz
+#define NFS3_readres_sz		1+NFS3_post_op_attr_sz+3
+#define NFS3_writeres_sz	1+NFS3_wcc_data_sz+4
+#define NFS3_createres_sz	1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
+#define NFS3_renameres_sz	1+(2 * NFS3_wcc_data_sz)
+#define NFS3_linkres_sz		1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
+#define NFS3_readdirres_sz	1+NFS3_post_op_attr_sz+2
+#define NFS3_fsstatres_sz	1+NFS3_post_op_attr_sz+13
+#define NFS3_fsinfores_sz	1+NFS3_post_op_attr_sz+12
+#define NFS3_pathconfres_sz	1+NFS3_post_op_attr_sz+6
+#define NFS3_commitres_sz	1+NFS3_wcc_data_sz+2
+
+/*
+ * Map file type to S_IFMT bits
+ */
+static struct {
+	unsigned int	mode;
+	unsigned int	nfs2type;
+} nfs_type2fmt[] = {
+      { 0,		NFNON	},
+      { S_IFREG,	NFREG	},
+      { S_IFDIR,	NFDIR	},
+      { S_IFBLK,	NFBLK	},
+      { S_IFCHR,	NFCHR	},
+      { S_IFLNK,	NFLNK	},
+      { S_IFSOCK,	NFSOCK	},
+      { S_IFIFO,	NFFIFO	},
+      { 0,		NFBAD	}
+};
 
 /*
  * Common NFS XDR functions as inlines
  */
 static inline u32 *
-xdr_encode_fhandle(u32 *p, struct nfs3_fh *fh)
+xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
 {
 	*p++ = htonl(fh->size);
 	memcpy(p, fh->data, fh->size);
-	return p + QUADLEN(fh->size);
+	return p + XDR_QUADLEN(fh->size);
 }
 
 static inline u32 *
-xdr_decode_fhandle(u32 *p, struct nfs3_fh *fh)
+xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
 {
+	/*
+	 * Zero all nonused bytes
+	 */
+	memset((u8 *)fh, 0, sizeof(*fh));
 	if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
 		memcpy(fh->data, p, fh->size);
-		return p + QUADLEN(fh->size);
+		return p + XDR_QUADLEN(fh->size);
 	}
 	return NULL;
 }
 
-static inline enum nfs_ftype
-xdr_decode_ftype(u32 type)
+/*
+ * Encode/decode time.
+ * Since the VFS doesn't care for fractional times, we ignore the
+ * nanosecond field.
+ */
+static inline u32 *
+xdr_encode_time(u32 *p, time_t time)
+{
+	*p++ = htonl(time);
+	*p++ = 0;
+	return p;
+}
+
+static inline u32 *
+xdr_decode_time3(u32 *p, u64 *timep)
+{
+	*timep = ((u64)ntohl(*p++) << 32) + (u64)ntohl(*p++);
+	return p;
+}
+
+static inline u32 *
+xdr_encode_time3(u32 *p, u64 time)
 {
-	return (type == NF3FIFO)? NFFIFO : (enum nfs_ftype) type;
+	*p++ = htonl(time >> 32);
+	*p++ = htonl(time & 0xFFFFFFFF);
+	return p;
 }
 
 static inline u32 *
@@ -99,47 +163,119 @@
 	if (*len > maxlen)
 		return NULL;
 	*string = (char *) p;
-	return p + QUADLEN(*len);
+	return p + XDR_QUADLEN(*len);
 }
 
 static inline u32 *
-xdr_decode_fattr(u32 *p, struct nfs3_fattr *fattr)
+xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 {
-	fattr->type = xdr_decode_ftype(ntohl(*p++));
-	fattr->mode = ntohl(*p++);
+	unsigned int	type;
+	int		fmode;
+
+	type = ntohl(*p++);
+	if (type >= NF3BAD)
+		type = NF3BAD;
+	fmode = nfs_type2fmt[type].mode;
+	fattr->type = nfs_type2fmt[type].nfs2type;
+	fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
 	fattr->nlink = ntohl(*p++);
 	fattr->uid = ntohl(*p++);
 	fattr->gid = ntohl(*p++);
-	fattr->size = ((u64) ntohl(*p++) << 32) | ntohl(*p++);
-	fattr->used = ((u64) ntohl(*p++) << 32) | ntohl(*p++);
-	fattr->rdev_maj = ntohl(*p++);
-	fattr->rdev_min = ntohl(*p++);
-	fattr->fsid = ntohl(*p++);
-	fattr->fileid = ntohl(*p++);
-	fattr->atime.seconds = ntohl(*p++);
-	fattr->atime.useconds = ntohl(*p++);
-	fattr->mtime.seconds = ntohl(*p++);
-	fattr->mtime.useconds = ntohl(*p++);
-	fattr->ctime.seconds = ntohl(*p++);
-	fattr->ctime.useconds = ntohl(*p++);
+	p = xdr_decode_hyper(p, &fattr->size);
+	p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
+	/* Turn remote device info into Linux-specific dev_t */
+	fattr->rdev = (ntohl(*p++) << MINORBITS) | (ntohl(*p++) & MINORMASK);
+	p = xdr_decode_hyper(p, &fattr->fsid);
+	p = xdr_decode_hyper(p, &fattr->fileid);
+	p = xdr_decode_time3(p, &fattr->atime);
+	p = xdr_decode_time3(p, &fattr->mtime);
+	p = xdr_decode_time3(p, &fattr->ctime);
+
+	/* Update the mode bits */
+	fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
 	return p;
 }
 
 static inline u32 *
-xdr_encode_sattr(u32 *p, struct nfs_sattr *sattr)
+xdr_encode_sattr(u32 *p, struct iattr *attr)
 {
-	*p++ = htonl(sattr->mode);
-	*p++ = htonl(sattr->uid);
-	*p++ = htonl(sattr->gid);
-	*p++ = htonl(sattr->size >> 32);
-	*p++ = htonl(sattr->size & 0xFFFFFFFF);
-	*p++ = htonl(sattr->atime.seconds);
-	*p++ = htonl(sattr->atime.useconds);
-	*p++ = htonl(sattr->mtime.seconds);
-	*p++ = htonl(sattr->mtime.useconds);
+	if (attr->ia_valid & ATTR_MODE) {
+		*p++ = xdr_one;
+		*p++ = htonl(attr->ia_mode);
+	} else {
+		*p++ = xdr_zero;
+	}
+	if (attr->ia_valid & ATTR_UID) {
+		*p++ = xdr_one;
+		*p++ = htonl(attr->ia_uid);
+	} else {
+		*p++ = xdr_zero;
+	}
+	if (attr->ia_valid & ATTR_GID) {
+		*p++ = xdr_one;
+		*p++ = htonl(attr->ia_gid);
+	} else {
+		*p++ = xdr_zero;
+	}
+	if (attr->ia_valid & ATTR_SIZE) {
+		*p++ = xdr_one;
+		p = xdr_encode_hyper(p, (__u64) attr->ia_size);
+	} else {
+		*p++ = xdr_zero;
+	}
+	if (attr->ia_valid & ATTR_ATIME_SET) {
+		*p++ = xdr_two;
+		p = xdr_encode_time(p, attr->ia_atime);
+	} else if (attr->ia_valid & ATTR_ATIME) {
+		*p++ = xdr_one;
+	} else {
+		*p++ = xdr_zero;
+	}
+	if (attr->ia_valid & ATTR_MTIME_SET) {
+		*p++ = xdr_two;
+		p = xdr_encode_time(p, attr->ia_mtime);
+	} else if (attr->ia_valid & ATTR_MTIME) {
+		*p++ = xdr_one;
+	} else {
+		*p++ = xdr_zero;
+	}
+	return p;
+}
+
+static inline u32 *
+xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
+{
+	p = xdr_decode_hyper(p, &fattr->pre_size);
+	p = xdr_decode_time3(p, &fattr->pre_mtime);
+	p = xdr_decode_time3(p, &fattr->pre_ctime);
+	fattr->valid |= NFS_ATTR_WCC;
 	return p;
 }
 
+static inline u32 *
+xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
+{
+	if (*p++)
+		p = xdr_decode_fattr(p, fattr);
+	return p;
+}
+
+static inline u32 *
+xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
+{
+	if (*p++)
+		return xdr_decode_wcc_attr(p, fattr);
+	return p;
+}
+
+
+static inline u32 *
+xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
+{
+	p = xdr_decode_pre_op_attr(p, fattr);
+	return xdr_decode_post_op_attr(p, fattr);
+}
+
 /*
  * NFS encode functions
  */
@@ -147,7 +283,7 @@
  * Encode void argument
  */
 static int
-nfs_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs3_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
 {
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
@@ -155,10 +291,9 @@
 
 /*
  * Encode file handle argument
- * GETATTR, READLINK, STATFS
  */
 static int
-nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs3_fh *fh)
+nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
 {
 	p = xdr_encode_fhandle(p, fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
@@ -169,23 +304,37 @@
  * Encode SETATTR arguments
  */
 static int
-nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
+nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_sattr(p, args->sattr);
+	*p++ = htonl(args->guard);
+	if (args->guard)
+		p = xdr_encode_time3(p, args->guardtime);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
  * Encode directory ops argument
- * LOOKUP, REMOVE, RMDIR
  */
 static int
-nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
+nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xdr_encode_array(p, args->name, args->len);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+/*
+ * Encode access() argument
+ */
+static int
+nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
-	p = xdr_encode_string(p, args->name);
+	*p++ = htonl(args->access);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
@@ -193,149 +342,181 @@
 /*
  * Arguments to a READ call. Since we read data directly into the page
  * cache, we also set up the reply iovec here so that iov[1] points
- * exactly to the page wewant to fetch.
+ * exactly to the page we want to fetch.
  */
 static int
-nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
+nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		replen, buflen;
+	int		buflen, replen;
+	unsigned int	nr;
 
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->count);
+	p = xdr_encode_hyper(p, args->offset);
 	*p++ = htonl(args->count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-#if 1
+	/* Get the number of buffers in the receive iovec */
+	nr = args->nriov;
+
+	if (nr+2 > MAX_IOVEC) {
+		printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
+		return -EINVAL;
+	}
+
 	/* set up reply iovec */
-	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
 	buflen = req->rq_rvec[0].iov_len;
 	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->count;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
+
+	/* Copy the iovec */
+	memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
+
+	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[nr+1].iov_len  = buflen - replen;
 	req->rq_rlen = args->count + buflen;
-	req->rq_rnr = 3;
-#else
-	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
-	req->rq_rvec[0].iov_len  = replen;
-#endif
+	req->rq_rnr += nr+1;
 
 	return 0;
 }
 
 /*
- * Decode READ reply
+ * Write arguments. Splice the buffer to be written into the iovec.
  */
 static int
-nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
+nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
 {
-	struct iovec *iov = req->rq_rvec;
-	int	status, count, recvd, hdrlen;
+	unsigned int	nr;
+	u32 count = args->count;
 
-	dprintk("RPC:      readres OK status %lx\n", ntohl(*p));
-	if ((status = ntohl(*p++)))
-		return -nfs_stat_to_errno(status);
-	p = xdr_decode_fattr(p, res->fattr);
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xdr_encode_hyper(p, args->offset);
+	*p++ = htonl(count);
+	*p++ = htonl(args->stable);
+	*p++ = htonl(count);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	count = ntohl(*p++);
-	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
-	recvd = req->rq_rlen - hdrlen;
-	if (p != iov[2].iov_base) {
-		/* Unexpected reply header size. Punt.
-		 * XXX: Move iovec contents to align data on page
-		 * boundary and adjust RPC header size guess */
-		printk("NFS: Odd RPC header size in read reply: %d\n", hdrlen);
-		return -errno_NFSERR_IO;
-	}
-	if (count > recvd) {
-		printk("NFS: server cheating in read reply: "
-			"count %d > recvd %d\n", count, recvd);
-		count = recvd;
+	/* Get the number of buffers in the send iovec */
+	nr = args->nriov;
+
+	if (nr+2 > MAX_IOVEC) {
+		printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs\n");
+		return -EINVAL;
 	}
 
-	dprintk("RPC:      readres OK count %d\n", count);
-	if (count < res->count)
-		memset((u8 *)(iov[1].iov_base+count), 0, res->count-count);
+	/* Copy the iovec */
+	memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
 
-	return count;
-}
+#ifdef NFS_PAD_WRITES
+	/*
+	 * Some old servers require that the message length
+	 * be a multiple of 4, so we pad it here if needed.
+	 */
+	if (count & 3) {
+		struct iovec	*iov = req->rq_svec + nr + 1;
+		int		pad = 4 - (count & 3);
+
+		iov->iov_base = (void *) "\0\0\0";
+		iov->iov_len  = pad;
+		count += pad;
+		nr++;
+	}
+#endif
+	req->rq_slen += count;
+	req->rq_snr  += nr;
 
+	return 0;
+}
 
 /*
- * Write arguments. Splice the buffer to be written into the iovec.
+ * Encode CREATE arguments
  */
 static int
-nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->count);
-	*p++ = htonl(args->count);
-	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	p = xdr_encode_array(p, args->name, args->len);
 
-	req->rq_svec[1].iov_base = (void *) args->buffer;
-	req->rq_svec[1].iov_len = args->count;
-	req->rq_slen += args->count;
-	req->rq_snr = 2;
+	*p++ = htonl(args->createmode);
+	if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
+		*p++ = args->verifier[0];
+		*p++ = args->verifier[1];
+	} else
+		p = xdr_encode_sattr(p, args->sattr);
 
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
- * Encode create arguments
- * CREATE, MKDIR
+ * Encode MKDIR arguments
  */
 static int
-nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
+nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
-	p = xdr_encode_string(p, args->name);
+	p = xdr_encode_array(p, args->name, args->len);
 	p = xdr_encode_sattr(p, args->sattr);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
- * Encode RENAME arguments
+ * Encode SYMLINK arguments
  */
 static int
-nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
+nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
-	p = xdr_encode_string(p, args->fromname);
-	p = xdr_encode_fhandle(p, args->tofh);
-	p = xdr_encode_string(p, args->toname);
+	p = xdr_encode_array(p, args->fromname, args->fromlen);
+	p = xdr_encode_sattr(p, args->sattr);
+	p = xdr_encode_array(p, args->topath, args->tolen);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
- * Encode LINK arguments
+ * Encode MKNOD arguments
+ */
+static int
+nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xdr_encode_array(p, args->name, args->len);
+	*p++ = htonl(args->type);
+	p = xdr_encode_sattr(p, args->sattr);
+	if (args->type == NF3CHR || args->type == NF3BLK) {
+		*p++ = htonl(args->rdev >> MINORBITS);
+		*p++ = htonl(args->rdev & MINORMASK);
+	}
+
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+/*
+ * Encode RENAME arguments
  */
 static int
-nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
+nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
+	p = xdr_encode_array(p, args->fromname, args->fromlen);
 	p = xdr_encode_fhandle(p, args->tofh);
-	p = xdr_encode_string(p, args->toname);
+	p = xdr_encode_array(p, args->toname, args->tolen);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
- * Encode SYMLINK arguments
+ * Encode LINK arguments
  */
 static int
-nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
+nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
-	p = xdr_encode_string(p, args->fromname);
-	p = xdr_encode_string(p, args->topath);
-	p = xdr_encode_sattr(p, args->sattr);
+	p = xdr_encode_fhandle(p, args->tofh);
+	p = xdr_encode_array(p, args->toname, args->tolen);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
@@ -344,131 +525,164 @@
  * Encode arguments to readdir call
  */
 static int
-nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
+nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		replen;
+	int		buflen, replen;
 
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->cookie);
+	p = xdr_encode_hyper(p, args->cookie);
+	*p++ = args->verf[0];
+	*p++ = args->verf[1];
+	if (args->plus) {
+		/* readdirplus: need dircount + buffer size.
+		 * We just make sure we make dircount big enough */
+		*p++ = htonl(args->bufsiz >> 3);
+	}
 	*p++ = htonl(args->bufsiz);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
 	/* set up reply iovec */
-	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
-	/*
-	dprintk("RPC: readdirargs: slack is 4 * (%d + %d + %d) = %d\n",
-		RPC_REPHDRSIZE, auth->au_rslack, NFS_readdirres_sz, replen);
-	 */
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
+	buflen = req->rq_rvec[0].iov_len;
 	req->rq_rvec[0].iov_len  = replen;
 	req->rq_rvec[1].iov_base = args->buffer;
 	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rlen = replen + args->bufsiz;
-	req->rq_rnr = 2;
-
-	/*
-	dprintk("RPC:      readdirargs set up reply vec:\n");
-	dprintk("          rvec[0] = %p/%d\n",
-			req->rq_rvec[0].iov_base,
-			req->rq_rvec[0].iov_len);
-	dprintk("          rvec[1] = %p/%d\n",
-			req->rq_rvec[1].iov_base,
-			req->rq_rvec[1].iov_len);
-	 */
+	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[2].iov_len  = buflen - replen;
+	req->rq_rlen = buflen + args->bufsiz;
+	req->rq_rnr += 2;
 
 	return 0;
 }
 
 /*
- * Decode the result of a readdir call. We decode the result in place
- * to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
- * After decoding, the layout in memory looks like this:
- *	entry1 entry2 ... entryN <space> stringN ... string2 string1
- * Each entry consists of three __u32 values, the same space as NFS uses.
- * Note that the strings are not null-terminated so that the entire number
- * of entries returned by the server should fit into the buffer.
- */
-static int
-nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
-{
-	struct iovec		*iov = req->rq_rvec;
-	int			status, nr, len;
-	char			*string, *start;
-	u32			*end;
-	__u32			fileid, cookie, *entry;
-
-	if ((status = ntohl(*p++)))
+ * Decode the result of a readdir call.
+ * We just check for syntactical correctness.
+ */
+static int
+nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
+{
+	struct iovec	*iov = req->rq_rvec;
+	int		hdrlen;
+	int		status, nr;
+	unsigned int	len;
+	u32		*entry, *end;
+
+	status = ntohl(*p++);
+	/* Decode post_op_attrs */
+	p = xdr_decode_post_op_attr(p, res->dir_attr);
+	if (status)
 		return -nfs_stat_to_errno(status);
-	if ((void *) p != ((u8 *) iov->iov_base+iov->iov_len)) {
-		/* Unexpected reply header size. Punt. */
-		printk("NFS: Odd RPC header size in readdirres reply\n");
-		return -errno_NFSERR_IO;
+	/* Decode verifier cookie */
+	if (res->verf) {
+		res->verf[0] = *p++;
+		res->verf[1] = *p++;
+	} else {
+		p += 2;
 	}
 
-	p = (u32 *) iov[1].iov_base;
-	end = (u32 *) ((u8 *) p + iov[1].iov_len);
-
-	if (p != res->buffer) {
-		printk("NFS: p != res->buffer in %s:%d!!!\n",
-					__FILE__, __LINE__);
-		return -errno_NFSERR_IO;
+	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+	if (iov->iov_len > hdrlen) {
+		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
+		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
 	}
 
-	entry  = (__u32 *) res->buffer;
-	start  = (char *) res->buffer;
-	string = start + res->bufsiz;
+	p   = (u32 *) iov[1].iov_base;
+	end = (u32 *) ((u8 *) p + iov[1].iov_len);
 	for (nr = 0; *p++; nr++) {
-		fileid = ntohl(*p++);
-
-		len = ntohl(*p++);
-		if ((p + QUADLEN(len) + 3) > end) {
-			printk(KERN_NOTICE
-				"NFS: short packet in readdir reply!\n");
-			break;
-		}
-		if (len > NFS_MAXNAMLEN) {
-			printk("NFS: giant filename in readdir (len %x)!\n",
+		entry = p - 1;
+		p += 2;				/* inode # */
+		len = ntohl(*p++);		/* string length */
+		p += XDR_QUADLEN(len) + 2;	/* name + cookie */
+		if (len > NFS3_MAXNAMLEN) {
+			printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
 						len);
 			return -errno_NFSERR_IO;
 		}
-		string -= len;
-		if ((void *) (entry+3) > (void *) string) {
-			/* 
-			 * This error is impossible as long as the temp
-			 * buffer is no larger than the user buffer. The 
-			 * current packing algorithm uses the same amount
-			 * of space in the user buffer as in the XDR data,
-			 * so it's guaranteed to fit.
-			 */
-			printk("NFS: incorrect buffer size in %s!\n",
-				__FUNCTION__);
+
+		if (res->plus) {
+			/* post_op_attr */
+			if (*p++)
+				p += 21;
+			/* post_op_fh3 */
+			if (*p++) {
+				len = ntohl(*p++);
+				if (len > NFS3_FHSIZE) {
+					printk(KERN_WARNING "NFS: giant filehandle in "
+						"readdir (len %x)!\n", len);
+					return -errno_NFSERR_IO;
+				}
+				p += XDR_QUADLEN(len);
+			}
+		}
+
+		if (p + 2 > end) {
+			printk(KERN_NOTICE
+				"NFS: short packet in readdir reply!\n");
+			/* truncate listing */
+			entry[0] = entry[1] = 0;
 			break;
 		}
+	}
 
-		memmove(string, p, len);
-		p += QUADLEN(len);
-		cookie = ntohl(*p++);
-		/*
-		 * To make everything fit, we encode the length, offset,
-		 * and eof flag into 32 bits. This works for filenames
-		 * up to 32K and PAGE_SIZE up to 64K.
-		 */
-		status = !p[0] && p[1] ? (1 << 15) : 0; /* eof flag */
-		*entry++ = fileid;
-		*entry++ = cookie;
-		*entry++ = ((string - start) << 16) | status | (len & 0x7FFF);
-		/*
-		dprintk("NFS: decoded dirent %.*s cookie %d eof %d\n",
-			len, string, cookie, status);
-		 */
-	}
-#ifdef NFS_PARANOIA
-printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
-nr, ((char *) entry - start), (start + res->bufsiz - string));
-#endif
 	return nr;
 }
 
+u32 *
+nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+{
+	struct nfs_entry old = *entry;
+
+	if (!*p++) {
+		if (!*p)
+			return ERR_PTR(-EAGAIN);
+		entry->eof = 1;
+		return ERR_PTR(-EBADCOOKIE);
+	}
+
+	p = xdr_decode_hyper(p, &entry->ino);
+	entry->len  = ntohl(*p++);
+	entry->name = (const char *) p;
+	p += XDR_QUADLEN(entry->len);
+	entry->prev_cookie = entry->cookie;
+	p = xdr_decode_hyper(p, &entry->cookie);
+
+	if (plus) {
+		p = xdr_decode_post_op_attr(p, &entry->fattr);
+		/* In fact, a post_op_fh3: */
+		if (*p++) {
+			p = xdr_decode_fhandle(p, &entry->fh);
+			/* Ugh -- server reply was truncated */
+			if (p == NULL) {
+				dprintk("NFS: FH truncated\n");
+				*entry = old;
+				return ERR_PTR(-EAGAIN);
+			}
+		} else {
+			/* If we don't get a file handle, the attrs
+			 * aren't worth a lot. */
+			entry->fattr.valid = 0;
+		}
+	}
+
+	entry->eof = !p[0] && p[1];
+	return p;
+}
+
+/*
+ * Encode COMMIT arguments
+ */
+static int
+nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xdr_encode_hyper(p, args->offset);
+	*p++ = htonl(args->count);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
 /*
  * NFS XDR decode functions
  */
@@ -476,59 +690,92 @@
  * Decode void reply
  */
 static int
-nfs_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs3_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
 {
 	return 0;
 }
 
 /*
- * Decode simple status reply
+ * Decode attrstat reply.
  */
 static int
-nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
 {
 	int	status;
 
-	if ((status = ntohl(*p++)) != 0)
-		status = -nfs_stat_to_errno(status);
-	return status;
+	if ((status = ntohl(*p++)))
+		return -nfs_stat_to_errno(status);
+	xdr_decode_fattr(p, fattr);
+	return 0;
 }
 
 /*
- * Decode attrstat reply
- * GETATTR, SETATTR, WRITE
+ * Decode status+wcc_data reply
+ * SATTR, REMOVE, RMDIR
  */
 static int
-nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
 {
 	int	status;
 
-	dprintk("RPC:      attrstat status %lx\n", ntohl(*p));
 	if ((status = ntohl(*p++)))
-		return -nfs_stat_to_errno(status);
-	xdr_decode_fattr(p, fattr);
-	dprintk("RPC:      attrstat OK type %d mode %o dev %x ino %x\n",
-		fattr->type, fattr->mode, fattr->fsid, fattr->fileid);
-	return 0;
+		status = -nfs_stat_to_errno(status);
+	xdr_decode_wcc_data(p, fattr);
+	return status;
 }
 
 /*
- * Decode diropres reply
- * LOOKUP, CREATE, MKDIR
+ * Decode LOOKUP reply
  */
 static int
-nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
+nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
 {
 	int	status;
 
-	dprintk("RPC:      diropres status %lx\n", ntohl(*p));
-	if ((status = ntohl(*p++)))
+	if ((status = ntohl(*p++))) {
+		status = -nfs_stat_to_errno(status);
+	} else {
+		if (!(p = xdr_decode_fhandle(p, res->fh)))
+			return -errno_NFSERR_IO;
+		p = xdr_decode_post_op_attr(p, res->fattr);
+	}
+	xdr_decode_post_op_attr(p, res->dir_attr);
+	return status;
+}
+
+/*
+ * Decode ACCESS reply
+ */
+static int
+nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
+{
+	int	status = ntohl(*p++);
+
+	p = xdr_decode_post_op_attr(p, res->fattr);
+	if (status)
 		return -nfs_stat_to_errno(status);
-	p = xdr_decode_fhandle(p, res->fh);
-	xdr_decode_fattr(p, res->fattr);
-	dprintk("RPC:      diropres OK type %x mode %o dev %x ino %x\n",
-		res->fattr->type, res->fattr->mode,
-		res->fattr->fsid, res->fattr->fileid);
+	res->access = ntohl(*p++);
+	return 0;
+}
+
+static int
+nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
+{
+	struct rpc_task *task = req->rq_task;
+	struct rpc_auth *auth = task->tk_auth;
+	int		buflen, replen;
+
+	p = xdr_encode_fhandle(p, args->fh);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
+	buflen = req->rq_rvec[0].iov_len;
+	req->rq_rvec[0].iov_len  = replen;
+	req->rq_rvec[1].iov_base = args->buffer;
+	req->rq_rvec[1].iov_len  = args->bufsiz;
+	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[2].iov_len  = buflen - replen;
+	req->rq_rlen = buflen + args->bufsiz;
+	req->rq_rnr += 2;
 	return 0;
 }
 
@@ -536,155 +783,299 @@
  * Decode READLINK reply
  */
 static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
+nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkres *res)
 {
+	struct iovec	*iov = req->rq_rvec;
+	int		hdrlen;
+	u32	*strlen;
+	char	*string;
 	int	status;
+	unsigned int len;
 
-	if ((status = ntohl(*p++)))
+	status = ntohl(*p++);
+	p = xdr_decode_post_op_attr(p, res->fattr);
+
+	if (status != 0)
 		return -nfs_stat_to_errno(status);
-	xdr_decode_string2(p, res->string, res->lenp, res->maxlen);
 
-	/* Caller takes over the buffer here to avoid extra copy */
-	res->buffer = req->rq_task->tk_buffer;
-	req->rq_task->tk_buffer = NULL;
+	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+	if (iov->iov_len > hdrlen) {
+		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
+		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+	}
+
+	strlen = (u32*)res->buffer;
+	/* Convert length of symlink */
+	len = ntohl(*strlen);
+	if (len > res->bufsiz - 5)
+		len = res->bufsiz - 5;
+	*strlen = len;
+	/* NULL terminate the string we got */
+	string = (char *)(strlen + 1);
+	string[len] = 0;
 	return 0;
 }
 
 /*
- * Decode STATFS reply
+ * Decode READ reply
  */
 static int
-nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
 {
-	int	status;
+	struct iovec *iov = req->rq_rvec;
+	int	status, count, ocount, recvd, hdrlen;
 
-	if ((status = ntohl(*p++)))
+	status = ntohl(*p++);
+	p = xdr_decode_post_op_attr(p, res->fattr);
+
+	if (status != 0)
 		return -nfs_stat_to_errno(status);
-	res->tsize = ntohl(*p++);
-	res->bsize = ntohl(*p++);
-	res->blocks = ntohl(*p++);
-	res->bfree = ntohl(*p++);
-	res->bavail = ntohl(*p++);
-	return 0;
+
+	/* Decode reply could and EOF flag. NFSv3 is somewhat redundant
+	 * in that it puts the count both in the res struct and in the
+	 * opaque data count. */
+	count    = ntohl(*p++);
+	res->eof = ntohl(*p++);
+	ocount   = ntohl(*p++);
+
+	if (ocount != count) {
+		printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
+		return -errno_NFSERR_IO;
+	}
+
+	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+	if (iov->iov_len > hdrlen) {
+		dprintk("NFS: READ header is short. iovec will be shifted.\n");
+		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+	}
+
+	recvd = req->rq_rlen - hdrlen;
+	if (count > recvd) {
+		printk(KERN_WARNING "NFS: server cheating in read reply: "
+			"count %d > recvd %d\n", count, recvd);
+		count = recvd;
+	}
+
+	if (count < res->count) {
+		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
+		res->count = count;
+	}
+
+	return count;
 }
 
 /*
- * We need to translate between nfs status return values and
- * the local errno values which may not be the same.
+ * Decode WRITE response
  */
-static struct {
-	int stat;
-	int errno;
-} nfs_errtbl[] = {
-	{ NFS_OK,		0		},
-	{ NFSERR_PERM,		EPERM		},
-	{ NFSERR_NOENT,		ENOENT		},
-	{ NFSERR_IO,		errno_NFSERR_IO	},
-	{ NFSERR_NXIO,		ENXIO		},
-	{ NFSERR_EAGAIN,	EAGAIN		},
-	{ NFSERR_ACCES,		EACCES		},
-	{ NFSERR_EXIST,		EEXIST		},
-	{ NFSERR_XDEV,		EXDEV		},
-	{ NFSERR_NODEV,		ENODEV		},
-	{ NFSERR_NOTDIR,	ENOTDIR		},
-	{ NFSERR_ISDIR,		EISDIR		},
-	{ NFSERR_INVAL,		EINVAL		},
-	{ NFSERR_FBIG,		EFBIG		},
-	{ NFSERR_NOSPC,		ENOSPC		},
-	{ NFSERR_ROFS,		EROFS		},
-	{ NFSERR_NAMETOOLONG,	ENAMETOOLONG	},
-	{ NFSERR_NOTEMPTY,	ENOTEMPTY	},
-	{ NFSERR_DQUOT,		EDQUOT		},
-	{ NFSERR_STALE,		ESTALE		},
-#ifdef EWFLUSH
-	{ NFSERR_WFLUSH,	EWFLUSH		},
-#endif
-	{ -1,			EIO		}
-};
+static int
+nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+{
+	int	status;
 
+	status = ntohl(*p++);
+	p = xdr_decode_wcc_data(p, res->fattr);
+
+	if (status != 0)
+		return -nfs_stat_to_errno(status);
+
+	res->count = ntohl(*p++);
+	res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
+	res->verf->verifier[0] = *p++;
+	res->verf->verifier[1] = *p++;
+
+	return res->count;
+}
+
+/*
+ * Decode a CREATE response
+ */
 static int
-nfs_stat_to_errno(int stat)
+nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
 {
-	int i;
+	int	status;
 
-	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
-		if (nfs_errtbl[i].stat == stat)
-			return nfs_errtbl[i].errno;
+	status = ntohl(*p++);
+	if (status == 0) {
+		if (*p++) {
+			if (!(p = xdr_decode_fhandle(p, res->fh)))
+				return -errno_NFSERR_IO;
+			p = xdr_decode_post_op_attr(p, res->fattr);
+		} else {
+			memset(res->fh, 0, sizeof(*res->fh));
+			/* Do decode post_op_attr but set it to NULL */
+			p = xdr_decode_post_op_attr(p, res->fattr);
+			res->fattr->valid = 0;
+		}
+	} else {
+		status = -nfs_stat_to_errno(status);
 	}
-	printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
-	return nfs_errtbl[i].errno;
+	p = xdr_decode_wcc_data(p, res->dir_attr);
+	return status;
 }
 
-#ifndef MAX
-# define MAX(a, b)	(((a) > (b))? (a) : (b))
-#endif
+/*
+ * Decode RENAME reply
+ */
+static int
+nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
+{
+	int	status;
 
-#define PROC(proc, argtype, restype)	\
-    { "nfs_" #proc,					\
-      (kxdrproc_t) nfs_xdr_##argtype,			\
-      (kxdrproc_t) nfs_xdr_##restype,			\
-      MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2	\
-    }
+	if ((status = ntohl(*p++)) != 0)
+		status = -nfs_stat_to_errno(status);
+	p = xdr_decode_wcc_data(p, res->fromattr);
+	p = xdr_decode_wcc_data(p, res->toattr);
+	return status;
+}
 
-static struct rpc_procinfo	nfs_procedures[18] = {
-    PROC(null,		enc_void,	dec_void),
-    PROC(getattr,	fhandle,	attrstat),
-    PROC(setattr,	sattrargs,	attrstat),
-    PROC(root,		enc_void,	dec_void),
-    PROC(lookup,	diropargs,	diropres),
-    PROC(readlink,	fhandle,	readlinkres),
-    PROC(read,		readargs,	readres),
-    PROC(writecache,	enc_void,	dec_void),
-    PROC(write,		writeargs,	attrstat),
-    PROC(create,	createargs,	diropres),
-    PROC(remove,	diropargs,	stat),
-    PROC(rename,	renameargs,	stat),
-    PROC(link,		linkargs,	stat),
-    PROC(symlink,	symlinkargs,	stat),
-    PROC(mkdir,		createargs,	diropres),
-    PROC(rmdir,		diropargs,	stat),
-    PROC(readdir,	readdirargs,	readdirres),
-    PROC(statfs,	fhandle,	statfsres),
-};
+/*
+ * Decode LINK reply
+ */
+static int
+nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
+{
+	int	status;
 
-static struct rpc_version	nfs_version2 = {
-	2,
-	sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
-	nfs_procedures
-};
+	if ((status = ntohl(*p++)) != 0)
+		status = -nfs_stat_to_errno(status);
+	p = xdr_decode_post_op_attr(p, res->fattr);
+	p = xdr_decode_wcc_data(p, res->dir_attr);
+	return status;
+}
 
-static struct rpc_version *	nfs_version[] = {
-	NULL,
-	NULL,
-	&nfs_version2
-};
+/*
+ * Decode FSSTAT reply
+ */
+static int
+nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+{
+	struct nfs_fattr dummy;
+	int		status;
 
-struct rpc_program	nfs_program = {
-	"nfs",
-	NFS_PROGRAM,
-	sizeof(nfs_version) / sizeof(nfs_version[0]),
-	nfs_version,
-	&nfs_rpcstat,
-};
+	status = ntohl(*p++);
+
+	p = xdr_decode_post_op_attr(p, &dummy);
+	if (status != 0)
+		return -nfs_stat_to_errno(status);
+
+	p = xdr_decode_hyper(p, &res->tbytes);
+	p = xdr_decode_hyper(p, &res->fbytes);
+	p = xdr_decode_hyper(p, &res->abytes);
+	p = xdr_decode_hyper(p, &res->tfiles);
+	p = xdr_decode_hyper(p, &res->ffiles);
+	p = xdr_decode_hyper(p, &res->afiles);
+
+	/* ignore invarsec */
+	return 0;
+}
 
 /*
- * RPC stats support
+ * Decode FSINFO reply
  */
 static int
-nfs_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
 {
-	return rpcstat_get_info(&nfs_rpcstat, buffer, start, offset, length);
+	struct nfs_fattr dummy;
+	int		status;
+
+	status = ntohl(*p++);
+
+	p = xdr_decode_post_op_attr(p, &dummy);
+	if (status != 0)
+		return -nfs_stat_to_errno(status);
+
+	res->rtmax  = ntohl(*p++);
+	res->rtpref = ntohl(*p++);
+	res->rtmult = ntohl(*p++);
+	res->wtmax  = ntohl(*p++);
+	res->wtpref = ntohl(*p++);
+	res->wtmult = ntohl(*p++);
+	res->dtpref = ntohl(*p++);
+	p = xdr_decode_hyper(p, &res->maxfilesize);
+
+	/* ignore time_delta and properties */
+	return 0;
 }
 
-static struct proc_dir_entry	proc_nfsclnt = {
-	0, 3, "nfs",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	6, NULL,
-	nfs_get_info
+/*
+ * Decode PATHCONF reply
+ */
+static int
+nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+{
+	struct nfs_fattr dummy;
+	int		status;
+
+	status = ntohl(*p++);
+
+	p = xdr_decode_post_op_attr(p, &dummy);
+	if (status != 0)
+		return -nfs_stat_to_errno(status);
+	res->linkmax = ntohl(*p++);
+	res->namelen = ntohl(*p++);
+
+	/* ignore remaining fields */
+	return 0;
+}
+
+/*
+ * Decode COMMIT reply
+ */
+static int
+nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+{
+	int		status;
+
+	status = ntohl(*p++);
+	p = xdr_decode_wcc_data(p, res->fattr);
+	if (status != 0)
+		return -nfs_stat_to_errno(status);
+
+	res->verf->verifier[0] = *p++;
+	res->verf->verifier[1] = *p++;
+	return 0;
+}
+
+#ifndef MAX
+# define MAX(a, b)	(((a) > (b))? (a) : (b))
+#endif
+
+#define PROC(proc, argtype, restype)				\
+    { "nfs3_" #proc,						\
+      (kxdrproc_t) nfs3_xdr_##argtype,				\
+      (kxdrproc_t) nfs3_xdr_##restype,				\
+      MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,	\
+      0							\
+    }
+
+static struct rpc_procinfo	nfs3_procedures[22] = {
+  PROC(null,		enc_void,	dec_void),
+  PROC(getattr,		fhandle,	attrstat),
+  PROC(setattr, 	sattrargs,	wccstat),
+  PROC(lookup,		diropargs,	lookupres),
+  PROC(access,		accessargs,	accessres),
+  PROC(readlink,	readlinkargs,	readlinkres),
+  PROC(read,		readargs,	readres),
+  PROC(write,		writeargs,	writeres),
+  PROC(create,		createargs,	createres),
+  PROC(mkdir,		mkdirargs,	createres),
+  PROC(symlink,		symlinkargs,	createres),
+  PROC(mknod,		mknodargs,	createres),
+  PROC(remove,		diropargs,	wccstat),
+  PROC(rmdir,		diropargs,	wccstat),
+  PROC(rename,		renameargs,	renameres),
+  PROC(link,		linkargs,	linkres),
+  PROC(readdir,		readdirargs,	readdirres),
+  PROC(readdirplus,	readdirargs,	readdirres),
+  PROC(fsstat,		fhandle,	fsstatres),
+  PROC(fsinfo,  	fhandle,	fsinfores),
+  PROC(pathconf,	fhandle,	pathconfres),
+  PROC(commit,		commitargs,	commitres),
 };
 
-struct rpc_stat			nfs_rpcstat = {
-	NULL,			/* next */
-	&proc_nfsclnt,		/* /proc/net directory entry */
-	&nfs_program,		/* RPC program */
+struct rpc_version		nfs_version3 = {
+	3,
+	sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
+	nfs3_procedures
 };
+
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- v2.3.99-pre3/linux/fs/nfs/nfsroot.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/nfs/nfsroot.c	Mon Apr 10 23:09:01 2000
@@ -61,8 +61,12 @@
  *	Martin Mares	:	Use root_server_addr appropriately during setup.
  *	Martin Mares	:	Rewrote parameter parsing, now hopefully giving
  *				correct overriding.
+ *	Trond Myklebust :	Add in preliminary support for NFSv3 and TCP.
+ *				Fix bug in root_nfs_addr(). nfs_data.namlen
+ *				is NOT for the length of the hostname.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -145,8 +149,14 @@
 	{ "nocto",	~NFS_MOUNT_NOCTO,	NFS_MOUNT_NOCTO },
 	{ "ac",		~NFS_MOUNT_NOAC,	0 },
 	{ "noac",	~NFS_MOUNT_NOAC,	NFS_MOUNT_NOAC },
-	{ "lock",	~NFS_MOUNT_LOCK,	0 },
+	{ "lock",	~NFS_MOUNT_NONLM,	0 },
 	{ "nolock",	~NFS_MOUNT_NONLM,	NFS_MOUNT_NONLM },
+#ifdef CONFIG_NFS_V3
+	{ "v2",		~NFS_MOUNT_VER3,	0 },
+	{ "v3",		~NFS_MOUNT_VER3,	NFS_MOUNT_VER3 },
+#endif
+	{ "udp",	~NFS_MOUNT_TCP,		0 },
+	{ "tcp",	~NFS_MOUNT_TCP,		NFS_MOUNT_TCP },
 	{ NULL,		0,			0 }
 };
 
@@ -271,7 +281,6 @@
 	}
 
 	strncpy(nfs_data.hostname, in_ntoa(servaddr), sizeof(nfs_data.hostname)-1);
-	nfs_data.namlen = strlen(nfs_data.hostname);
 	return 0;
 }
 
@@ -360,14 +369,14 @@
 /*
  *  Query server portmapper for the port of a daemon program.
  */
-static int __init root_nfs_getport(int program, int version)
+static int __init root_nfs_getport(int program, int version, int proto)
 {
 	struct sockaddr_in sin;
 
 	printk(KERN_NOTICE "Looking up port of RPC %d/%d on %s\n",
 		program, version, in_ntoa(servaddr));
 	set_sockaddr(&sin, servaddr, 0);
-	return rpc_getport_external(&sin, program, version, IPPROTO_UDP);
+	return rpc_getport_external(&sin, program, version, proto);
 }
 
 
@@ -379,22 +388,39 @@
 static int __init root_nfs_ports(void)
 {
 	int port;
+	int nfsd_ver, mountd_ver;
+	int nfsd_port, mountd_port;
+	int proto;
+
+	if (nfs_data.flags & NFS_MOUNT_VER3) {
+		nfsd_ver = NFS3_VERSION;
+		mountd_ver = NFS_MNT3_VERSION;
+		nfsd_port = NFS_PORT;
+		mountd_port = NFS_MNT_PORT;
+	} else {
+		nfsd_ver = NFS2_VERSION;
+		mountd_ver = NFS_MNT_VERSION;
+		nfsd_port = NFS_PORT;
+		mountd_port = NFS_MNT_PORT;
+	}
+
+	proto = (nfs_data.flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
 
 	if (nfs_port < 0) {
-		if ((port = root_nfs_getport(NFS_PROGRAM, NFS_VERSION)) < 0) {
+		if ((port = root_nfs_getport(NFS_PROGRAM, nfsd_ver, proto)) < 0) {
 			printk(KERN_ERR "Root-NFS: Unable to get nfsd port "
 					"number from server, using default\n");
-			port = NFS_PORT;
+			port = nfsd_port;
 		}
 		nfs_port = htons(port);
 		dprintk("Root-NFS: Portmapper on server returned %d "
 			"as nfsd port\n", port);
 	}
 
-	if ((port = root_nfs_getport(NFS_MNT_PROGRAM, NFS_MNT_VERSION)) < 0) {
+	if ((port = root_nfs_getport(NFS_MNT_PROGRAM, nfsd_ver, proto)) < 0) {
 		printk(KERN_ERR "Root-NFS: Unable to get mountd port "
 				"number from server, using default\n");
-		port = NFS_MNT_PORT;
+		port = mountd_port;
 	}
 	mount_port = htons(port);
 	dprintk("Root-NFS: mountd port is %d\n", port);
@@ -413,7 +439,10 @@
 	int status;
 
 	set_sockaddr(&sin, servaddr, mount_port);
-	status = nfs_mount(&sin, nfs_path, &nfs_data.root);
+	if (nfs_data.flags & NFS_MOUNT_VER3)
+		status = nfs3_mount(&sin, nfs_path, &nfs_data.root);
+	else
+		status = nfs_mount(&sin, nfs_path, &nfs_data.root);
 	if (status < 0)
 		printk(KERN_ERR "Root-NFS: Server returned error %d "
 				"while mounting %s\n", status, nfs_path);
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/proc.c linux/fs/nfs/proc.c
--- v2.3.99-pre3/linux/fs/nfs/proc.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/nfs/proc.c	Sat Apr  1 08:04:27 2000
@@ -13,10 +13,6 @@
  *  Note: Error returns are optimized for NFS_OK, which isn't translated via
  *  nfs_stat_to_errno(), but happens to be already the right return code.
  *
- *  FixMe: We ought to define a sensible small max size for
- *  things like getattr that are tiny packets and use the
- *  old get_free_page stuff with it.
- *
  *  Also, the code currently doesn't check the size of the packet, when
  *  it decodes the packet.
  *
@@ -25,209 +21,357 @@
  *  Completely rewritten to support the new RPC call interface;
  *  rewrote and moved the entire XDR stuff to xdr.c
  *  --Olaf Kirch June 1996
+ *
+ *  The code below initializes all auto variables explicitly, otherwise
+ *  it will fail to work as a module (gcc generates a memset call for an
+ *  incomplete struct).
  */
 
-#define NFS_NEED_XDR_TYPES
-
+#include <linux/types.h>
 #include <linux/param.h>
+#include <linux/malloc.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/malloc.h>
 #include <linux/utsname.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/in.h>
 #include <linux/pagemap.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
 
 #include <asm/segment.h>
 
-#ifdef NFS_DEBUG
-# define NFSDBG_FACILITY	NFSDBG_PROC
-#endif
+#define NFSDBG_FACILITY		NFSDBG_PROC
 
+/*
+ * Bare-bones access to getattr: this is for nfs_read_super.
+ */
+static int
+nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+		  struct nfs_fattr *fattr)
+{
+	int		status;
+
+	dprintk("NFS call  getroot\n");
+	fattr->valid = 0;
+	status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
+	dprintk("NFS reply getroot\n");
+	return status;
+}
 
 /*
  * One function for each procedure in the NFS protocol.
  */
-int
-nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fattr *fattr)
+static int
+nfs_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr)
 {
 	int	status;
 
 	dprintk("NFS call  getattr\n");
-	status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_GETATTR,
+				NFS_FH(dentry), fattr, 0);
 	dprintk("NFS reply getattr\n");
 	return status;
 }
 
-int
-nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fattr *fattr, struct iattr *sattr)
+static int
+nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+		 struct iattr *sattr)
 {
-	struct nfs_sattrargs	arg = { fhandle, sattr };
+	struct nfs_sattrargs	arg = { NFS_FH(dentry), sattr };
 	int	status;
 
 	dprintk("NFS call  setattr\n");
-	status = rpc_call(server->client, NFSPROC_SETATTR, &arg, fattr, 0);
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_SETATTR, &arg, fattr, 0);
 	dprintk("NFS reply setattr\n");
 	return status;
 }
 
-int
-nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name,
-		    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int
+nfs_proc_lookup(struct dentry *dir, struct qstr *name,
+		struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
-	struct nfs_diropargs	arg = { dir, name };
+	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
 	struct nfs_diropok	res = { fhandle, fattr };
 	int			status;
 
-	dprintk("NFS call  lookup %s\n", name);
-	status = rpc_call(server->client, NFSPROC_LOOKUP, &arg, &res, 0);
+	dprintk("NFS call  lookup %s\n", name->name);
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_LOOKUP, &arg, &res, 0);
 	dprintk("NFS reply lookup: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, int swap,
-			  unsigned long offset, unsigned int count,
-			  void *buffer, struct nfs_fattr *fattr)
-{
-	struct nfs_readargs	arg = { fhandle, offset, count, buffer };
-	struct nfs_readres	res = { fattr, count };
+static int
+nfs_proc_readlink(struct dentry *dentry, void *buffer, unsigned int bufsiz)
+{
+	struct nfs_readlinkargs	args = { NFS_FH(dentry), buffer, bufsiz };
+	struct nfs_readlinkres	res = { buffer, bufsiz };
 	int			status;
 
-	dprintk("NFS call  read %d @ %ld\n", count, offset);
-	status = rpc_call(server->client, NFSPROC_READ, &arg, &res,
-			swap? NFS_RPC_SWAPFLAGS : 0);
-	dprintk("NFS reply read: %d\n", status);
+	dprintk("NFS call  readlink\n");
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK,
+					&args, &res, 0);
+	dprintk("NFS reply readlink: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, int swap,
-			unsigned long offset, unsigned int count,
-			const void *buffer, struct nfs_fattr *fattr)
-{
-	struct nfs_writeargs	arg = { fhandle, offset, count, 1, 1,
-					{{(void *) buffer, count}, {0,0}, {0,0}, {0,0},
-					{0,0}, {0,0}, {0,0}, {0,0}}};
-	struct nfs_writeverf	verf;
-	struct nfs_writeres	res = {fattr, &verf, count};
+static int
+nfs_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+	      loff_t offset, unsigned int count, void *buffer, int *eofp)
+{
+	struct nfs_readargs	arg = { NFS_FH(dentry), offset, count, 1,
+				       {{ buffer, count }, {0,0}, {0,0}, {0,0},
+					{0,0}, {0,0}, {0,0}, {0,0}} };
+	struct nfs_readres	res = { fattr, count, 0};
+	struct rpc_message	msg = { NFSPROC_READ, &arg, &res, NULL };
 	int			status;
 
-	dprintk("NFS call  write %d @ %ld\n", count, offset);
-	status = rpc_call(server->client, NFSPROC_WRITE, &arg, &res,
-			swap? (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS) : 0);
+	dprintk("NFS call  read %d @ %Ld\n", count, (long long)offset);
+	fattr->valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+
 	dprintk("NFS reply read: %d\n", status);
+	*eofp = res.eof;
+	return status;
+}
+
+static int
+nfs_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, int how,
+	       loff_t offset, unsigned int count,
+	       void *buffer, struct nfs_writeverf *verf)
+{
+	struct nfs_writeargs	arg = {NFS_FH(dentry), offset, count,
+					NFS_FILE_SYNC, 1,
+					{{buffer, count}, {0,0}, {0,0}, {0,0},
+					 {0,0}, {0,0}, {0,0}, {0,0}}};
+	struct nfs_writeres     res = {fattr, verf, count};
+	struct rpc_message	msg = { NFSPROC_WRITE, &arg, &res, NULL };
+	int			status, flags = 0;
+
+	dprintk("NFS call  write %d @ %Ld\n", count, (long long)offset);
+	fattr->valid = 0;
+	if (how & NFS_RW_SWAP)
+		flags |= NFS_RPC_SWAPFLAGS;
+	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+
+	dprintk("NFS reply write: %d\n", status);
+	verf->committed = NFS_FILE_SYNC;      /* NFSv2 always syncs data */
 	return status < 0? status : count;
 }
 
-int
-nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct iattr *sattr,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int
+nfs_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+		int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
-	struct nfs_createargs	arg = { dir, name, sattr };
+	struct nfs_createargs	arg = { NFS_FH(dir), name->name,
+					name->len, sattr };
 	struct nfs_diropok	res = { fhandle, fattr };
 	int			status;
 
-	dprintk("NFS call  create %s\n", name);
-	status = rpc_call(server->client, NFSPROC_CREATE, &arg, &res, 0);
+	fattr->valid = 0;
+	dprintk("NFS call  create %s\n", name->name);
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
 	dprintk("NFS reply create: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name)
+/*
+ * In NFSv2, mknod is grafted onto the create call.
+ */
+static int
+nfs_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+	       dev_t rdev, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	struct nfs_createargs	arg = { NFS_FH(dir), name->name,
+						     name->len, sattr };
+	struct nfs_diropok	res = { fhandle, fattr };
+	int			status, mode;
+
+	dprintk("NFS call  mknod %s\n", name->name);
+
+	mode = sattr->ia_mode;
+	if (S_ISFIFO(mode)) {
+		sattr->ia_mode = (mode & ~S_IFMT) | S_IFCHR;
+		sattr->ia_valid &= ~ATTR_SIZE;
+	} else if (S_ISCHR(rdev) || S_ISBLK(rdev)) {
+		sattr->ia_valid |= ATTR_SIZE;
+		sattr->ia_size   = rdev;	/* get out your barf bag */
+	}
+
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+
+	if (status == -EINVAL && S_ISFIFO(mode)) {
+		sattr->ia_mode = mode;
+		fattr->valid = 0;
+		status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+	}
+	dprintk("NFS reply mknod: %d\n", status);
+	return status;
+}
+  
+static int
+nfs_proc_remove(struct dentry *dir, struct qstr *name)
 {
-	struct nfs_diropargs	arg = { dir, name };
+	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
+	struct rpc_message	msg = { NFSPROC_REMOVE, &arg, NULL, NULL };
 	int			status;
 
-	dprintk("NFS call  remove %s\n", name);
-	status = rpc_call(server->client, NFSPROC_REMOVE, &arg, NULL, 0);
+	dprintk("NFS call  remove %s\n", name->name);
+	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+
 	dprintk("NFS reply remove: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_rename(struct nfs_server *server,
-		struct nfs_fh *old_dir, const char *old_name,
-		struct nfs_fh *new_dir, const char *new_name)
-{
-	struct nfs_renameargs	arg = { old_dir, old_name, new_dir, new_name };
+static int
+nfs_proc_rename(struct dentry *old_dir, struct qstr *old_name,
+		struct dentry *new_dir, struct qstr *new_name)
+{
+	struct nfs_renameargs	arg = { NFS_FH(old_dir), old_name->name,
+					old_name->len,
+					NFS_FH(new_dir), new_name->name,
+					new_name->len};
 	int			status;
 
-	dprintk("NFS call  rename %s -> %s\n", old_name, new_name);
-	status = rpc_call(server->client, NFSPROC_RENAME, &arg, NULL, 0);
+	dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
+	status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFSPROC_RENAME, &arg, NULL, 0);
 	dprintk("NFS reply rename: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fh *dir, const char *name)
+static int
+nfs_proc_link(struct dentry *dentry, struct dentry *dir, struct qstr *name)
 {
-	struct nfs_linkargs	arg = { fhandle, dir, name };
+	struct nfs_linkargs	arg = { NFS_FH(dentry), NFS_FH(dir),
+					name->name, name->len };
 	int			status;
 
-	dprintk("NFS call  link %s\n", name);
-	status = rpc_call(server->client, NFSPROC_LINK, &arg, NULL, 0);
+	dprintk("NFS call  link %s\n", name->name);
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_LINK, &arg, NULL, 0);
 	dprintk("NFS reply link: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, const char *path,
-			struct iattr *sattr)
+static int
+nfs_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path,
+		 struct iattr *sattr, struct nfs_fh *fhandle,
+		 struct nfs_fattr *fattr)
 {
-	struct nfs_symlinkargs	arg = { dir, name, path, sattr };
+	struct nfs_symlinkargs	arg = { NFS_FH(dir), name->name, name->len,
+					path->name, path->len, sattr };
 	int			status;
 
-	dprintk("NFS call  symlink %s -> %s\n", name, path);
-	status = rpc_call(server->client, NFSPROC_SYMLINK, &arg, NULL, 0);
+	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_SYMLINK, &arg, NULL, 0);
 	dprintk("NFS reply symlink: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct iattr *sattr,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int
+nfs_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+	       struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
-	struct nfs_createargs	arg = { dir, name, sattr };
+	struct nfs_createargs	arg = { NFS_FH(dir), name->name, name->len,
+					sattr };
 	struct nfs_diropok	res = { fhandle, fattr };
 	int			status;
 
-	dprintk("NFS call  mkdir %s\n", name);
-	status = rpc_call(server->client, NFSPROC_MKDIR, &arg, &res, 0);
+	dprintk("NFS call  mkdir %s\n", name->name);
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_MKDIR, &arg, &res, 0);
 	dprintk("NFS reply mkdir: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
+static int
+nfs_proc_rmdir(struct dentry *dir, struct qstr *name)
 {
-	struct nfs_diropargs	arg = { dir, name };
+	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
 	int			status;
 
-	dprintk("NFS call  rmdir %s\n", name);
-	status = rpc_call(server->client, NFSPROC_RMDIR, &arg, NULL, 0);
+	dprintk("NFS call  rmdir %s\n", name->name);
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_RMDIR, &arg, NULL, 0);
 	dprintk("NFS reply rmdir: %d\n", status);
 	return status;
 }
 
-int
+/*
+ * The READDIR implementation is somewhat hackish - we pass a temporary
+ * buffer to the encode function, which installs it in the receive
+ * the receive iovec. The decode function just parses the reply to make
+ * sure it is syntactically correct; the entries itself are decoded
+ * from nfs_readdir by calling the decode_entry function directly.
+ */
+static int
+nfs_proc_readdir(struct dentry *dir, __u64 cookie, void *entry, 
+		 unsigned int size, int plus)
+{
+	struct nfs_readdirargs	arg;
+	struct nfs_readdirres	res;
+	struct rpc_message	msg = { NFSPROC_READDIR, &arg, &res, NULL };
+	struct nfs_server       *server = NFS_DSERVER(dir);
+	int			status;
+
+	if (server->rsize < size)
+		size = server->rsize;
+
+	arg.fh = NFS_FH(dir);
+	arg.cookie = cookie;
+	arg.buffer = entry;
+	arg.bufsiz = size;
+	res.buffer = entry;
+	res.bufsiz = size;
+
+	dprintk("NFS call  readdir %d\n", (unsigned int)cookie);
+	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+
+	dprintk("NFS reply readdir: %d\n", status);
+	return status;
+}
+
+static int
 nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
 			struct nfs_fsinfo *info)
 {
 	int	status;
 
 	dprintk("NFS call  statfs\n");
+	memset((char *)info, 0, sizeof(*info));
 	status = rpc_call(server->client, NFSPROC_STATFS, fhandle, info, 0);
 	dprintk("NFS reply statfs: %d\n", status);
 	return status;
 }
+
+extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
+
+struct nfs_rpc_ops     nfs_v2_clientops = {
+       2,		       /* protocol version */
+       nfs_proc_get_root,
+       nfs_proc_getattr,
+       nfs_proc_setattr,
+       nfs_proc_lookup,
+       NULL,		       /* access */
+       nfs_proc_readlink,
+       nfs_proc_read,
+       nfs_proc_write,
+       NULL,		       /* commit */
+       nfs_proc_create,
+       nfs_proc_remove,
+       nfs_proc_rename,
+       nfs_proc_link,
+       nfs_proc_symlink,
+       nfs_proc_mkdir,
+       nfs_proc_rmdir,
+       nfs_proc_readdir,
+       nfs_proc_mknod,
+       nfs_proc_statfs,
+       nfs_decode_dirent,
+};
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.3.99-pre3/linux/fs/nfs/read.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/nfs/read.c	Mon Apr  3 13:24:06 2000
@@ -15,7 +15,6 @@
  * within the RPC code when root squashing is suspected.
  */
 
-#define NFS_NEED_XDR_TYPES
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -52,14 +51,18 @@
  */
 static inline void
 nfs_readreq_setup(struct nfs_rreq *req, struct nfs_fh *fh,
-		  unsigned long offset, void *buffer, unsigned int rsize)
+		  loff_t offset, void *buffer, unsigned int rsize)
 {
 	req->ra_args.fh     = fh;
 	req->ra_args.offset = offset;
 	req->ra_args.count  = rsize;
-	req->ra_args.buffer = buffer;
+	req->ra_args.iov[0].iov_base = (void *)buffer;
+	req->ra_args.iov[0].iov_len = rsize;
+	req->ra_args.nriov  = 1;
+	req->ra_fattr.valid = 0;
 	req->ra_res.fattr   = &req->ra_fattr;
 	req->ra_res.count   = rsize;
+	req->ra_res.eof     = 0;
 }
 
 
@@ -70,11 +73,12 @@
 nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
 {
 	struct nfs_rreq	rqst;
-	unsigned long	offset = page->index << PAGE_CACHE_SHIFT;
+	struct rpc_message msg;
+	loff_t		offset = page_offset(page);
 	char		*buffer;
 	int		rsize = NFS_SERVER(inode)->rsize;
 	int		result, refresh = 0;
-	int		count = PAGE_SIZE;
+	int		count = PAGE_CACHE_SIZE;
 	int		flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0;
 
 	dprintk("NFS: nfs_readpage_sync(%p)\n", page);
@@ -89,16 +93,21 @@
 		if (count < rsize)
 			rsize = count;
 
-		dprintk("NFS: nfs_proc_read(%s, (%s/%s), %ld, %d, %p)\n",
+		dprintk("NFS: nfs_proc_read(%s, (%s/%s), %Ld, %d, %p)\n",
 			NFS_SERVER(inode)->hostname,
 			dentry->d_parent->d_name.name, dentry->d_name.name,
-			offset, rsize, buffer);
+			(long long)offset, rsize, buffer);
 
 		/* Set up arguments and perform rpc call */
 		nfs_readreq_setup(&rqst, NFS_FH(dentry), offset, buffer, rsize);
 		lock_kernel();
-		result = rpc_call(NFS_CLIENT(inode), NFSPROC_READ, &rqst.ra_args, &rqst.ra_res, flags);
+		msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
+		msg.rpc_argp = &rqst.ra_args;
+		msg.rpc_resp = &rqst.ra_res;
+		msg.rpc_cred = NULL;
+		result = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 		unlock_kernel();
+		nfs_refresh_inode(inode, &rqst.ra_fattr);
 
 		/*
 		 * Even if we had a partial success we can't mark the page
@@ -124,9 +133,6 @@
 io_error:
 	kunmap(page);
 	UnlockPage(page);
-	/* Note: we don't refresh if the call returned error */
-	if (refresh && result >= 0)
-		nfs_refresh_inode(inode, &rqst.ra_fattr);
 	return result;
 }
 
@@ -139,19 +145,18 @@
 {
 	struct nfs_rreq	*req = (struct nfs_rreq *) task->tk_calldata;
 	struct page	*page = req->ra_page;
-	unsigned long	address = page_address(page);
+	char		*address = req->ra_args.iov[0].iov_base;
 	int		result = task->tk_status;
 	static int	succ = 0, fail = 0;
 
-	dprintk("NFS: %4d received callback for page %lx, result %d\n",
+	dprintk("NFS: %4d received callback for page %p, result %d\n",
 			task->tk_pid, address, result);
 
+	nfs_refresh_inode(req->ra_inode, &req->ra_fattr);
 	if (result >= 0) {
 		result = req->ra_res.count;
-		if (result < PAGE_SIZE) {
-			memset((char *) address + result, 0, PAGE_SIZE - result);
-		}
-		nfs_refresh_inode(req->ra_inode, &req->ra_fattr);
+		if (result < PAGE_CACHE_SIZE)
+			memset(address + result, 0, PAGE_CACHE_SIZE - result);
 		SetPageUptodate(page);
 		succ++;
 	} else {
@@ -161,9 +166,8 @@
 	}
 	kunmap(page);
 	UnlockPage(page);
-	__free_page(page);
+	page_cache_release(page);
 
-	rpc_release_task(task);
 	kfree(req);
 }
 
@@ -189,15 +193,15 @@
 	address = kmap(page);	
 	/* Initialize request */
 	/* N.B. Will the dentry remain valid for life of request? */
-	nfs_readreq_setup(req, NFS_FH(dentry), page->index << PAGE_CACHE_SHIFT,
-				(void *) address, PAGE_SIZE);
+	nfs_readreq_setup(req, NFS_FH(dentry), page_offset(page),
+				(void *) address, PAGE_CACHE_SIZE);
 	req->ra_inode = inode;
 	req->ra_page = page; /* count has been incremented by caller */
 
 	/* Start the async call */
 	dprintk("NFS: executing async READ request.\n");
 
-	msg.rpc_proc = NFSPROC_READ;
+	msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
 	msg.rpc_argp = &req->ra_args;
 	msg.rpc_resp = &req->ra_res;
 	msg.rpc_cred = NULL;
@@ -225,7 +229,7 @@
  * We read the page synchronously in the following cases:
  *  -	The file is a swap file. Swap-ins are always sync operations,
  *	so there's no need bothering to make async reads 100% fail-safe.
- *  -	The NFS rsize is smaller than PAGE_SIZE. We could kludge our way
+ *  -	The NFS rsize is smaller than PAGE_CACHE_SIZE. We could kludge our way
  *	around this by creating several consecutive read requests, but
  *	that's hardly worth it.
  *  -	The error flag is set for this page. This happens only when a
@@ -240,7 +244,7 @@
 
 	lock_kernel();
 	dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
-		page, PAGE_SIZE, page->index);
+		page, PAGE_CACHE_SIZE, page->index);
 	get_page(page);
 
 	/*
@@ -256,7 +260,7 @@
 
 	error = -1;
 	if (!IS_SWAPFILE(inode) && !PageError(page) &&
-	    NFS_SERVER(inode)->rsize >= PAGE_SIZE)
+	    NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
 		error = nfs_readpage_async(dentry, inode, page);
 	if (error >= 0)
 		goto out;
@@ -269,7 +273,7 @@
 out_error:
 	UnlockPage(page);
 out_free:
-	__free_page(page);
+	page_cache_release(page);
 out:
 	unlock_kernel();
 	return error;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c
--- v2.3.99-pre3/linux/fs/nfs/symlink.c	Sat Feb 26 22:31:53 2000
+++ linux/fs/nfs/symlink.c	Fri Apr  7 13:38:00 2000
@@ -14,8 +14,9 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/sunrpc/clnt.h>
-#include <linux/nfs_fs.h>
 #include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs_fs.h>
 #include <linux/pagemap.h>
 #include <linux/stat.h>
 #include <linux/mm.h>
@@ -27,16 +28,17 @@
  */
 static int nfs_symlink_filler(struct dentry *dentry, struct page *page)
 {
-	struct nfs_readlinkargs rl_args;
-	kmap(page);
+	struct inode *inode = dentry->d_inode;
+	void *buffer = (void *)kmap(page);
+	int error;
+
 	/* We place the length at the beginning of the page,
 	 * in host byte order, followed by the string.  The
 	 * XDR response verification will NULL terminate it.
 	 */
-	rl_args.fh = NFS_FH(dentry);
-	rl_args.buffer = (const void *)page_address(page);
-	if (rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK,
-		     &rl_args, NULL, 0) < 0)
+	error = NFS_PROTO(inode)->readlink(dentry, buffer,
+					   PAGE_CACHE_SIZE - sizeof(u32)-4);
+	if (error < 0)
 		goto error;
 	SetPageUptodate(page);
 	kunmap(page);
@@ -85,12 +87,10 @@
 	return res;
 }
 
-static struct dentry *
-nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
+static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct page *page = NULL;
-	struct dentry *res = vfs_follow_link(dentry, base, follow,
-					     nfs_getlink(dentry, &page));
+	int res = vfs_follow_link(nd, nfs_getlink(dentry,&page));
 	if (page) {
 		kunmap(page);
 		page_cache_release(page);
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.3.99-pre3/linux/fs/nfs/write.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/nfs/write.c	Mon Apr 10 23:02:45 2000
@@ -55,6 +55,7 @@
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
 #include <linux/nfs_flushd.h>
 #include <asm/uaccess.h>
 #include <linux/smp_lock.h>
@@ -160,7 +161,6 @@
 static void nfs_writedata_release(struct rpc_task *task)
 {
 	struct nfs_write_data	*wdata = (struct nfs_write_data *)task->tk_calldata;
-	rpc_release_task(task);
 	nfs_writedata_free(wdata);
 }
 
@@ -172,6 +172,12 @@
 static __inline__ int
 nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr)
 {
+	if ((fattr->valid & NFS_ATTR_FATTR) && !(fattr->valid & NFS_ATTR_WCC)) {
+		fattr->pre_size  = NFS_CACHE_ISIZE(inode);
+		fattr->pre_mtime = NFS_CACHE_MTIME(inode);
+		fattr->pre_ctime = NFS_CACHE_CTIME(inode);
+		fattr->valid |= NFS_ATTR_WCC;
+	}
 	return nfs_refresh_inode(inode, fattr);
 }
 
@@ -183,10 +189,12 @@
 nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
 		struct page *page, unsigned long offset, unsigned int count)
 {
+	loff_t		base;
 	unsigned int	wsize = NFS_SERVER(inode)->wsize;
-	int		result, refresh = 0, written = 0;
+	int		result, refresh = 0, written = 0, flags;
 	u8		*buffer;
 	struct nfs_fattr fattr;
+	struct nfs_writeverf verf;
 
 	lock_kernel();
 	dprintk("NFS:      nfs_writepage_sync(%s/%s %d@%lu/%ld)\n",
@@ -194,15 +202,17 @@
 		count, page->index, offset);
 
 	buffer = (u8 *) kmap(page) + offset;
-	offset += page->index << PAGE_CACHE_SHIFT;
+	base = page_offset(page) + offset;
+
+	flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;
 
 	do {
 		if (count < wsize && !IS_SWAPFILE(inode))
 			wsize = count;
 
-		result = nfs_proc_write(NFS_DSERVER(dentry), NFS_FH(dentry),
-					IS_SWAPFILE(inode), offset, wsize,
-					buffer, &fattr);
+		result = NFS_PROTO(inode)->write(dentry, &fattr, flags,
+						 base, wsize, buffer, &verf);
+		nfs_write_attributes(inode, &fattr);
 
 		if (result < 0) {
 			/* Must mark the page invalid after I/O error */
@@ -214,41 +224,19 @@
 			wsize, result);
 		refresh = 1;
 		buffer  += wsize;
-		offset  += wsize;
+	        base    += wsize;
 		written += wsize;
 		count   -= wsize;
 		/*
 		 * If we've extended the file, update the inode
 		 * now so we don't invalidate the cache.
 		 */
-		if (offset > inode->i_size)
-			inode->i_size = offset;
+		if (base > inode->i_size)
+			inode->i_size = base;
 	} while (count);
 
 io_error:
 	kunmap(page);
-	/* Note: we don't refresh if the call failed (fattr invalid) */
-	if (refresh && result >= 0) {
-		/* See comments in nfs_wback_result */
-		/* N.B. I don't think this is right -- sync writes in order */
-		if (fattr.size < inode->i_size)
-			fattr.size = inode->i_size;
-		if (fattr.mtime.seconds < inode->i_mtime)
-			printk("nfs_writepage_sync: prior time??\n");
-		/* Solaris 2.5 server seems to send garbled
-		 * fattrs occasionally */
-		if (inode->i_ino == fattr.fileid) {
-			/*
-			 * We expect the mtime value to change, and
-			 * don't want to invalidate the caches.
-			 */
-			inode->i_mtime = fattr.mtime.seconds;
-			nfs_refresh_inode(inode, &fattr);
-		} 
-		else
-			printk("nfs_writepage_sync: inode %ld, got %u?\n",
-				inode->i_ino, fattr.fileid);
-	}
 
 	unlock_kernel();
 	return written? written : result;
@@ -290,7 +278,7 @@
 region_locked(struct inode *inode, struct nfs_page *req)
 {
 	struct file_lock	*fl;
-	unsigned long		rqstart, rqend;
+	loff_t			rqstart, rqend;
 
 	/* Don't optimize writes if we don't use NLM */
 	if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)
@@ -665,20 +653,18 @@
  * Interruptible by signals only if mounted with intr flag.
  */
 static int
-nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long start, unsigned int count)
+nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages)
 {
 	struct list_head	*p, *head;
-	unsigned long		idx_start, idx_end;
-	unsigned int		pages = 0;
+	unsigned long		idx_end;
+	unsigned int		res = 0;
 	int			error;
 
-	idx_start = start >> PAGE_CACHE_SHIFT;
-	if (count == 0)
+	if (npages == 0)
 		idx_end = ~0;
-	else {
-		unsigned long idx_count = (count-1) >> PAGE_CACHE_SHIFT;
-		idx_end = idx_start + idx_count;
-	}
+	else
+		idx_end = idx_start + npages - 1;
+
 	spin_lock(&nfs_wreq_lock);
 	head = &inode->u.nfs_i.writeback;
 	p = head->next;
@@ -705,10 +691,10 @@
 			return error;
 		spin_lock(&nfs_wreq_lock);
 		p = head->next;
-		pages++;
+		res++;
 	}
 	spin_unlock(&nfs_wreq_lock);
-	return pages;
+	return res;
 }
 
 /*
@@ -769,19 +755,18 @@
 #endif
 
 static int
-nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long start, unsigned int count)
+nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
 {
 	struct list_head	*p;
 	struct nfs_page		*req;
-	unsigned long		idx_start, idx_end;
-	int			pages;
+	unsigned long		idx_end;
+	int			res;
 
-	pages = 0;
-	idx_start = start >> PAGE_CACHE_SHIFT;
-	if (count == 0)
+	res = 0;
+	if (npages == 0)
 		idx_end = ~0;
 	else
-		idx_end = idx_start + ((count-1) >> PAGE_CACHE_SHIFT);
+		idx_end = idx_start + npages - 1;
 	p = src->next;
 	while (p != src) {
 		unsigned long pg_idx;
@@ -800,36 +785,36 @@
 			continue;
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, dst);
-		pages++;
+		res++;
 	}
-	return pages;
+	return res;
 }
 
 static int
-nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long start, unsigned int count)
+nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
 {
-	int	pages;
+	int	res;
 	spin_lock(&nfs_wreq_lock);
-	pages = nfs_scan_list(&inode->u.nfs_i.dirty, dst, file, start, count);
-	inode->u.nfs_i.ndirty -= pages;
+	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))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");
 	spin_unlock(&nfs_wreq_lock);
-	return pages;
+	return res;
 }
 
 #ifdef CONFIG_NFS_V3
 static int
-nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long start, unsigned int count)
+nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
 {
-	int	pages;
+	int	res;
 	spin_lock(&nfs_wreq_lock);
-	pages = nfs_scan_list(&inode->u.nfs_i.commit, dst, file, start, count);
-	inode->u.nfs_i.ncommit -= pages;
+	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))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
 	spin_unlock(&nfs_wreq_lock);
-	return pages;
+	return res;
 }
 #endif
 
@@ -1038,7 +1023,7 @@
 
 	dprintk("NFS:      nfs_updatepage(%s/%s %d@%Ld)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
-		count, page_offset(page) +offset);
+		count, (long long)(page_offset(page) +offset));
 
 	/*
 	 * If wsize is smaller than page size, update and write
@@ -1071,7 +1056,7 @@
 	if (synchronous) {
 		int error;
 
-		error = nfs_sync_file(inode, file, page_offset(page) + offset, count, FLUSH_SYNC|FLUSH_STABLE);
+		error = nfs_sync_file(inode, file, page_index(page), 1, FLUSH_SYNC|FLUSH_STABLE);
 		if (error < 0 || (error = file->f_error) < 0)
 			status = error;
 		file->f_error = 0;
@@ -1086,7 +1071,7 @@
 	nfs_release_request(req);
 done:
         dprintk("NFS:      nfs_updatepage returns %d (isize %Ld)\n",
-                                                status, inode->i_size);
+                                                status, (long long)inode->i_size);
 	if (status < 0)
 		clear_bit(PG_uptodate, &page->flags);
 	return status;
@@ -1173,6 +1158,8 @@
 	/* Finalize the task. */
 	rpc_init_task(task, clnt, nfs_writeback_done, flags);
 	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_writedata_release;
 
 #ifdef CONFIG_NFS_V3
 	msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_WRITE : NFSPROC_WRITE;
@@ -1266,22 +1253,25 @@
 		/* We tried a write call, but the server did not
 		 * commit data to stable storage even though we
 		 * requested it.
+		 * Note: There is a known bug in Tru64 < 5.0 in which
+		 *	 the server reports NFS_DATA_SYNC, but performs
+		 *	 NFS_FILE_SYNC. We therefore implement this checking
+		 *	 as a dprintk() in order to avoid filling syslog.
 		 */
 		static unsigned long    complain = 0;
 
 		if (time_before(complain, jiffies)) {
-			printk(KERN_NOTICE "NFS: faulty NFSv3 server %s:"
-			       " (committed = %d) != (stable = %d)\n",
-			       NFS_SERVER(inode)->hostname,
-			       resp->verf->committed, argp->stable);
+			dprintk("NFS: faulty NFSv3 server %s:"
+				" (committed = %d) != (stable = %d)\n",
+				NFS_SERVER(inode)->hostname,
+				resp->verf->committed, argp->stable);
 			complain = jiffies + 300 * HZ;
 		}
 	}
 #endif
 
 	/* Update attributes as result of writeback. */
-	if (task->tk_status >= 0)
-		nfs_write_attributes(inode, resp->fattr);
+	nfs_write_attributes(inode, resp->fattr);
 
 	while (!list_empty(&data->pages)) {
 		req = nfs_list_entry(data->pages.next);
@@ -1293,7 +1283,7 @@
 			req->wb_file->f_dentry->d_parent->d_name.name,
 			req->wb_file->f_dentry->d_name.name,
 			req->wb_bytes,
-			page_offset(req->wb_page) + req->wb_offset);
+			(long long)(page_offset(req->wb_page) + req->wb_offset));
 
 		if (task->tk_status < 0) {
 			req->wb_file->f_error = task->tk_status;
@@ -1318,7 +1308,6 @@
 	next:
 		nfs_unlock_request(req);
 	}
-	nfs_writedata_release(task);
 }
 
 
@@ -1332,7 +1321,7 @@
 	struct nfs_page		*req;
 	struct dentry		*dentry;
 	struct inode		*inode;
-	unsigned long		start, end, len;
+	loff_t			start, end, len;
 
 	/* Set up the RPC argument and reply structs
 	 * NB: take care not to mess about with data->commit et al. */
@@ -1346,7 +1335,7 @@
 	inode = dentry->d_inode;
 	while (!list_empty(head)) {
 		struct nfs_page	*req;
-		unsigned long	rqstart, rqend;
+		loff_t	rqstart, rqend;
 		req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
@@ -1360,6 +1349,7 @@
 	data->args.fh     = NFS_FH(dentry);
 	data->args.offset = start;
 	len = end - start;
+	/* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */
 	if (end >= inode->i_size || len > (~((u32)0) >> 1))
 		len = 0;
 	data->res.count   = data->args.count = (u32)len;
@@ -1399,6 +1389,8 @@
 
 	rpc_init_task(task, clnt, nfs_commit_done, flags);
 	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_writedata_release;
 
 	msg.rpc_proc = NFS3PROC_COMMIT;
 	msg.rpc_argp = &data->args;
@@ -1441,11 +1433,11 @@
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
 
-		dprintk("NFS: commit (%s/%s %d@%ld)",
+		dprintk("NFS: commit (%s/%s %d@%Ld)",
 			req->wb_file->f_dentry->d_parent->d_name.name,
 			req->wb_file->f_dentry->d_name.name,
 			req->wb_bytes,
-			page_offset(req->wb_page) + req->wb_offset);
+			(long long)(page_offset(req->wb_page) + req->wb_offset));
 		if (task->tk_status < 0) {
 			req->wb_file->f_error = task->tk_status;
 			nfs_inode_remove_request(req);
@@ -1467,23 +1459,22 @@
 	next:
 		nfs_unlock_request(req);
 	}
-	nfs_writedata_release(task);
 }
 #endif
 
-int nfs_flush_file(struct inode *inode, struct file *file, unsigned long start,
-		   unsigned int count, int how)
+int nfs_flush_file(struct inode *inode, struct file *file, unsigned long idx_start,
+		   unsigned int npages, int how)
 {
 	LIST_HEAD(head);
-	int			pages,
+	int			res,
 				error = 0;
 
-	pages = nfs_scan_dirty(inode, &head, file, start, count);
-	if (pages)
+	res = nfs_scan_dirty(inode, &head, file, idx_start, npages);
+	if (res)
 		error = nfs_flush_list(inode, &head, how);
 	if (error < 0)
 		return error;
-	return pages;
+	return res;
 }
 
 int nfs_flush_timeout(struct inode *inode, int how)
@@ -1501,19 +1492,19 @@
 }
 
 #ifdef CONFIG_NFS_V3
-int nfs_commit_file(struct inode *inode, struct file *file, unsigned long start,
-		    unsigned int count, int how)
+int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start,
+		    unsigned int npages, int how)
 {
 	LIST_HEAD(head);
-	int			pages,
+	int			res,
 				error = 0;
 
-	pages = nfs_scan_commit(inode, &head, file, start, count);
-	if (pages)
+	res = nfs_scan_commit(inode, &head, file, idx_start, npages);
+	if (res)
 		error = nfs_commit_list(&head, how);
 	if (error < 0)
 		return error;
-	return pages;
+	return res;
 }
 
 int nfs_commit_timeout(struct inode *inode, int how)
@@ -1533,8 +1524,8 @@
 }
 #endif
 
-int nfs_sync_file(struct inode *inode, struct file *file, unsigned long start,
-		  unsigned int count, int how)
+int nfs_sync_file(struct inode *inode, struct file *file, unsigned long idx_start,
+		  unsigned int npages, int how)
 {
 	int	error,
 		wait;
@@ -1548,12 +1539,12 @@
 	do {
 		error = 0;
 		if (wait)
-			error = nfs_wait_on_requests(inode, file, start, count);
+			error = nfs_wait_on_requests(inode, file, idx_start, npages);
 		if (error == 0)
-			error = nfs_flush_file(inode, file, start, count, how);
+			error = nfs_flush_file(inode, file, idx_start, npages, how);
 #ifdef CONFIG_NFS_V3
 		if (error == 0)
-			error = nfs_commit_file(inode, file, start, count, how);
+			error = nfs_commit_file(inode, file, idx_start, npages, how);
 #endif
 	} while (error > 0);
 	return error;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.3.99-pre3/linux/fs/nfsd/export.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/nfsd/export.c	Fri Apr  7 13:38:00 2000
@@ -246,14 +246,11 @@
 
 	/* Look up the dentry */
 	err = -EINVAL;
-	dentry = lookup_dentry(nxp->ex_path, NULL, 0);
+	dentry = lookup_dentry(nxp->ex_path, LOOKUP_POSITIVE);
 	if (IS_ERR(dentry))
 		goto out_unlock;
 
-	err = -ENOENT;
 	inode = dentry->d_inode;
-	if (!inode)
-		goto finish;
 	err = -EINVAL;
 	if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
 		printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
@@ -443,7 +440,7 @@
 
 	err = -EPERM;
 	if (path) {
-		if (!(dentry = lookup_dentry(path, NULL, 0))) {
+		if (!(dentry = lookup_dentry(path, 0))) {
 			printk("nfsd: exp_rootfh path not found %s", path);
 			return -EPERM;
 		}
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfsd/lockd.c linux/fs/nfsd/lockd.c
--- v2.3.99-pre3/linux/fs/nfsd/lockd.c	Fri Mar 10 16:40:48 2000
+++ linux/fs/nfsd/lockd.c	Mon Apr 10 23:02:46 2000
@@ -27,7 +27,8 @@
 
 	/* must initialize before using! but maxsize doesn't matter */
 	fh_init(&fh,0);
-	memcpy((char*)&fh.fh_handle.fh_base, (char*)f, NFS_FHSIZE);
+	fh.fh_handle.fh_size = f->size;
+	memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size);
 	fh.fh_export = NULL;
 
 	nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp);
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c
--- v2.3.99-pre3/linux/fs/nfsd/nfs3xdr.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/nfsd/nfs3xdr.c	Mon Apr 10 23:02:46 2000
@@ -74,22 +74,11 @@
 static inline u32 *
 encode_fh(u32 *p, struct svc_fh *fhp)
 {
-#if 0
 	int size = fhp->fh_handle.fh_size;
 	*p++ = htonl(size);
 	if (size) p[XDR_QUADLEN(size)-1]=0;
 	memcpy(p, &fhp->fh_handle.fh_base, size);
 	return p + XDR_QUADLEN(size);
-#else
-	/* until locked knows about var-length file handles,
-	 * we always return NFS_FHSIZE handles
-	 */
-	int size = fhp->fh_handle.fh_size;
-	*p++ = htonl(NFS_FHSIZE);
-	memset(p, 0, NFS_FHSIZE);
-	memcpy(p, &fhp->fh_handle.fh_base, size);
-	return p + XDR_QUADLEN(NFS_FHSIZE);
-#endif
 }
 
 /*
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c
--- v2.3.99-pre3/linux/fs/nfsd/nfsctl.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/nfsd/nfsctl.c	Mon Apr 10 23:02:46 2000
@@ -130,7 +130,6 @@
 	else
 		err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen);
 	exp_unlock();
-	/*HACK*/ res->fh_size = NFS_FHSIZE; /* HACK until lockd handles var-length handles */
 	return err;
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.99-pre3/linux/fs/nfsd/vfs.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/nfsd/vfs.c	Fri Apr  7 13:38:00 2000
@@ -91,7 +91,8 @@
 					int len, struct svc_fh *resfh)
 {
 	struct svc_export	*exp;
-	struct dentry		*dparent, *dchild;
+	struct dentry		*dparent;
+	struct nameidata nd;
 	int			err;
 
 	dprintk("nfsd: nfsd_lookup(fh %s, %s)\n", SVCFH_fmt(fhp), name);
@@ -116,49 +117,51 @@
 		/* checking mountpoint crossing is very different when stepping up */
 		if (dparent == exp->ex_dentry) {
 			if (!EX_CROSSMNT(exp))
-				dchild = dget(dparent); /* .. == . just like at / */
+				nd.dentry = dget(dparent); /* .. == . just like at / */
 			else
 			{
 				struct svc_export *exp2 = NULL;
 				struct dentry *dp;
-				dchild = dparent->d_covers->d_parent;
-				for (dp=dchild;
+				nd.dentry = dparent->d_covers->d_parent;
+				for (dp=nd.dentry;
 				     exp2 == NULL && dp->d_covers->d_parent != dp;
 				     dp=dp->d_covers->d_parent)
 					exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
-				if (exp2==NULL || dchild->d_sb != exp2->ex_dentry->d_sb) {
-					dchild = dget(dparent);
+				if (exp2==NULL || nd.dentry->d_sb != exp2->ex_dentry->d_sb) {
+					nd.dentry = dget(dparent);
 				} else {
-					dget(dchild);
+					dget(nd.dentry);
 					exp = exp2;
 				}
 			}
 		} else
-			dchild = dget(dparent->d_parent);
+			nd.dentry = dget(dparent->d_parent);
 	} else {
-		dchild = lookup_dentry(name, dget(dparent), 0);
-		if (IS_ERR(dchild))
+		nd.mnt = NULL;
+		nd.dentry = dget(dparent);
+		err = walk_name(name, 0, &nd);
+		if (err)
 			goto out_nfserr;
 		/*
 		 * check if we have crossed a mount point ...
 		 */
-		if (dchild->d_sb != dparent->d_sb) {
+		if (nd.dentry->d_sb != dparent->d_sb) {
 			struct svc_export *exp2 = NULL;
 			exp2 = exp_get(rqstp->rq_client,
-				       dchild->d_inode->i_dev,
-				       dchild->d_inode->i_ino);
+				       nd.dentry->d_inode->i_dev,
+				       nd.dentry->d_inode->i_ino);
 			if (exp2 && EX_CROSSMNT(exp2))
 				/* successfully crossed mount point */
 				exp = exp2;
-			else if (dchild->d_covers->d_sb == dparent->d_sb) {
+			else if (nd.dentry->d_covers->d_sb == dparent->d_sb) {
 				/* stay in the original filesystem */
-				struct dentry *tdentry = dget(dchild->d_covers);
-				dput(dchild);
-				dchild = tdentry;
+				struct dentry *tdentry = dget(nd.dentry->d_covers);
+				dput(nd.dentry);
+				nd.dentry = tdentry;
 			} else {
 				/* This cannot possibly happen */
-				printk("nfsd_lookup: %s/%s impossible mount point!\n", dparent->d_name.name, dchild->d_name.name);
-				dput(dchild);
+				printk("nfsd_lookup: %s/%s impossible mount point!\n", dparent->d_name.name, nd.dentry->d_name.name);
+				dput(nd.dentry);
 				err = nfserr_acces;
 				goto out;
 
@@ -169,14 +172,14 @@
 	 * Note: we compose the file handle now, but as the
 	 * dentry may be negative, it may need to be updated.
 	 */
-	err = fh_compose(resfh, exp, dchild);
-	if (!err && !dchild->d_inode)
+	err = fh_compose(resfh, exp, nd.dentry);
+	if (!err && !nd.dentry->d_inode)
 		err = nfserr_noent;
 out:
 	return err;
 
 out_nfserr:
-	err = nfserrno(PTR_ERR(dchild));
+	err = nfserrno(err);
 	goto out;
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/ntfs/Makefile linux/fs/ntfs/Makefile
--- v2.3.99-pre3/linux/fs/ntfs/Makefile	Mon Apr 12 10:05:58 1999
+++ linux/fs/ntfs/Makefile	Mon Apr 10 23:02:59 2000
@@ -3,7 +3,7 @@
 O_TARGET := ntfs.o
 O_OBJS   := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o
 M_OBJS   := $(O_TARGET)
-EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"990411\"
+EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"000410\"
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- v2.3.99-pre3/linux/fs/ntfs/fs.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/ntfs/fs.c	Mon Apr 10 23:02:59 2000
@@ -1,7 +1,8 @@
 /*
  *  fs.c
- *  NTFS driver for Linux 2.1
+ *  NTFS driver for Linux 2.3.x
  *
+ *  Copyright (C) 2000, Anton Altaparmakov
  *  Copyright (C) 1995-1997, 1999 Martin von Löwis
  *  Copyright (C) 1996 Richard Russon
  *  Copyright (C) 1996-1997 Régis Duchesne
@@ -53,7 +54,6 @@
 {
 	struct ntfs_getuser_update_vm_s *p = src->param;
 	copy_from_user (dest, p->user, len);
-	update_vm_cache (p->ino, p->off, dest, len);
 	p->user += len;
 	p->off += len;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/open.c linux/fs/open.c
--- v2.3.99-pre3/linux/fs/open.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/open.c	Fri Apr  7 13:41:53 2000
@@ -141,11 +141,8 @@
 	file = fget(fd);
 	if (!file)
 		goto out;
-	error = -ENOENT;
-	if (!(dentry = file->f_dentry))
-		goto out_putf;
-	if (!(inode = dentry->d_inode))
-		goto out_putf;
+	dentry = file->f_dentry;
+	inode = dentry->d_inode;
 	error = -EACCES;
 	if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
 		goto out_putf;
@@ -330,35 +327,41 @@
 	return res;
 }
 
+/* MOUNT_REWRITE: pass &mnt to lookup_dentry */
 asmlinkage long sys_chdir(const char * filename)
 {
 	int error;
-	struct inode *inode;
 	struct dentry *dentry, *tmp;
+	struct vfsmount *mnt = NULL, *tmp_mnt;
+	char *name;
 
 	lock_kernel();
 	
-	dentry = namei(filename);
+	name = getname(filename);
+	error = PTR_ERR(name);
+	if (IS_ERR(name))
+		goto out;
+
+	dentry = lookup_dentry(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW | LOOKUP_DIRECTORY);
+	putname(name);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto out;
 
-	inode = dentry->d_inode;
-
-	error = -ENOTDIR;
-	if (!S_ISDIR(inode->i_mode))
-		goto dput_and_out;
-
-	error = permission(inode,MAY_EXEC);
+	error = permission(dentry->d_inode,MAY_EXEC);
 	if (error)
 		goto dput_and_out;
 
 	/* exchange dentries */
 	tmp = current->fs->pwd;
+	tmp_mnt = current->fs->pwdmnt;
 	current->fs->pwd = dentry;
+	current->fs->pwdmnt = mnt;
 	dentry = tmp;
+	mnt = tmp_mnt;
 
 dput_and_out:
+	mntput(mnt);
 	dput(dentry);
 out:
 	unlock_kernel();
@@ -370,6 +373,7 @@
 	struct file *file;
 	struct dentry *dentry;
 	struct inode *inode;
+	struct vfsmount *mnt;
 	int error;
 
 	error = -EBADF;
@@ -377,11 +381,9 @@
 	if (!file)
 		goto out;
 
-	error = -ENOENT;
-	if (!(dentry = file->f_dentry))
-		goto out_putf;
-	if (!(inode = dentry->d_inode))
-		goto out_putf;
+	dentry = file->f_dentry;
+	mnt = file->f_vfsmnt;
+	inode = dentry->d_inode;
 
 	error = -ENOTDIR;
 	if (!S_ISDIR(inode->i_mode))
@@ -391,7 +393,10 @@
 	error = permission(inode, MAY_EXEC);
 	if (!error) {
 		struct dentry *tmp = current->fs->pwd;
+		struct vfsmount *tmp_mnt = current->fs->pwdmnt;
 		current->fs->pwd = dget(dentry);
+		current->fs->pwdmnt = mntget(mnt);
+		mntput(tmp_mnt);
 		dput(tmp);
 	}
 	unlock_kernel();
@@ -401,26 +406,28 @@
 	return error;
 }
 
+/* MOUNT_REWRITE: pass &mnt to lookup_dentry */
 asmlinkage long sys_chroot(const char * filename)
 {
 	int error;
-	struct inode *inode;
 	struct dentry *dentry, *tmp;
+	struct vfsmount *mnt = NULL, *tmp_mnt;
+	char *name;
 
 	lock_kernel();
 	
-	dentry = namei(filename);
+	name = getname(filename);
+	error = PTR_ERR(name);
+	if (IS_ERR(name))
+		goto out;
+
+	dentry = lookup_dentry(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW | LOOKUP_DIRECTORY);
+	putname(name);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto out;
 
-	inode = dentry->d_inode;
-
-	error = -ENOTDIR;
-	if (!S_ISDIR(inode->i_mode))
-		goto dput_and_out;
-
-	error = permission(inode,MAY_EXEC);
+	error = permission(dentry->d_inode,MAY_EXEC);
 	if (error)
 		goto dput_and_out;
 
@@ -430,11 +437,15 @@
 
 	/* exchange dentries */
 	tmp = current->fs->root;
+	tmp_mnt = current->fs->rootmnt;
 	current->fs->root = dentry;
+	current->fs->rootmnt = mnt;
 	dentry = tmp;
+	mnt = tmp_mnt;
 	error = 0;
 
 dput_and_out:
+	mntput(mnt);
 	dput(dentry);
 out:
 	unlock_kernel();
@@ -453,11 +464,8 @@
 	if (!file)
 		goto out;
 
-	err = -ENOENT;
-	if (!(dentry = file->f_dentry))
-		goto out_putf;
-	if (!(inode = dentry->d_inode))
-		goto out_putf;
+	dentry = file->f_dentry;
+	inode = dentry->d_inode;
 
 	err = -EROFS;
 	if (IS_RDONLY(inode))
@@ -612,20 +620,16 @@
 
 asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
 {
-	struct dentry * dentry;
 	struct file * file;
 	int error = -EBADF;
 
 	file = fget(fd);
 	if (!file)
 		goto out;
-	error = -ENOENT;
 	lock_kernel();
-	if ((dentry = file->f_dentry) != NULL)
-		error = chown_common(dentry, user, group);
+	error = chown_common(file->f_dentry, user, group);
 	unlock_kernel();
 	fput(file);
-
 out:
 	return error;
 }
@@ -644,26 +648,25 @@
  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
  * used by symlinks.
  */
-struct file *filp_open(const char * filename, int flags, int mode, struct dentry * base)
+struct file *filp_open(const char * filename, int flags, int mode)
 {
-	struct dentry * dentry;
-	int flag,error;
+	int namei_flags, error;
+	struct nameidata nd;
 
-	flag = flags;
-	if ((flag+1) & O_ACCMODE)
-		flag++;
-	if (flag & O_TRUNC)
-		flag |= 2;
+	namei_flags = flags;
+	if ((namei_flags+1) & O_ACCMODE)
+		namei_flags++;
+	if (namei_flags & O_TRUNC)
+		namei_flags |= 2;
 
-	dentry = __open_namei(filename, flag, mode, base);
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry))
-		return dentry_open(dentry, flags);
+	error = open_namei(filename, namei_flags, mode, &nd);
+	if (!error)
+		return dentry_open(nd.dentry, nd.mnt, flags);
 
 	return ERR_PTR(error);
 }
 
-struct file *dentry_open(struct dentry *dentry, int flags)
+struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
 {
 	struct file * f;
 	struct inode *inode;
@@ -679,15 +682,14 @@
 	if (f->f_mode & FMODE_WRITE) {
 		error = get_write_access(inode);
 		if (error)
-			goto cleanup_dentry;
+			goto cleanup_file;
 	}
 
 	f->f_dentry = dentry;
+	f->f_vfsmnt = mnt;
 	f->f_pos = 0;
 	f->f_reada = 0;
-	f->f_op = NULL;
-	if (inode->i_op)
-		f->f_op = inode->i_fop;
+	f->f_op = inode->i_fop;
 	if (inode->i_sb)
 		file_move(f, &inode->i_sb->s_files);
 	if (f->f_op && f->f_op->open) {
@@ -703,9 +705,12 @@
 	if (f->f_mode & FMODE_WRITE)
 		put_write_access(inode);
 	f->f_dentry = NULL;
+	f->f_vfsmnt = NULL;
+cleanup_file:
+	put_filp(f);
 cleanup_dentry:
 	dput(dentry);
-	put_filp(f);
+	mntput(mnt);
 	return ERR_PTR(error);
 }
 
@@ -795,7 +800,7 @@
 		if (fd >= 0) {
 			struct file * f;
 			lock_kernel();
-			f = filp_open(tmp, flags, mode, NULL);
+			f = filp_open(tmp, flags, mode);
 			unlock_kernel();
 			error = PTR_ERR(f);
 			if (IS_ERR(f))
@@ -833,7 +838,6 @@
 int filp_close(struct file *filp, fl_owner_t id)
 {
 	int retval;
-	struct dentry *dentry = filp->f_dentry;
 
 	if (!file_count(filp)) {
 		printk("VFS: Close: file count is 0\n");
@@ -842,8 +846,7 @@
 	retval = 0;
 	if (filp->f_op && filp->f_op->flush)
 		retval = filp->f_op->flush(filp);
-	if (dentry->d_inode)
-		locks_remove_posix(filp, id);
+	locks_remove_posix(filp, id);
 	fput(filp);
 	return retval;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/partitions/Config.in linux/fs/partitions/Config.in
--- v2.3.99-pre3/linux/fs/partitions/Config.in	Sat Feb 12 11:22:11 2000
+++ linux/fs/partitions/Config.in	Mon Mar 27 09:39:22 2000
@@ -21,8 +21,8 @@
       bool '    Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
       bool '    Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
    fi
-   bool 'SGI partition support' CONFIG_SGI_PARTITION
-   bool 'Sun partition tables support' CONFIG_SUN_PARTITION
+   bool '  SGI partition support' CONFIG_SGI_PARTITION
+   bool '  Sun partition tables support' CONFIG_SUN_PARTITION
 else
    if [ "$ARCH" = "alpha" ]; then
       define_bool CONFIG_OSF_PARTITION y
@@ -33,6 +33,9 @@
    fi
    if [ "$CONFIG_AMIGA" = "y" ]; then
       define_bool CONFIG_AMIGA_PARTITION y
+   fi
+   if [ "$CONFIG_MAC" = "y" ]; then
+      define_bool CONFIG_MAC_PARTITION y
    fi
    if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
       define_bool CONFIG_ACORN_PARTITION y
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.3.99-pre3/linux/fs/proc/array.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/proc/array.c	Sun Apr  2 15:53:28 2000
@@ -574,7 +574,9 @@
 		if (map->vm_file != NULL) {
 			dev = map->vm_file->f_dentry->d_inode->i_dev;
 			ino = map->vm_file->f_dentry->d_inode->i_ino;
-			line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+			line = d_path(map->vm_file->f_dentry,
+				      map->vm_file->f_vfsmnt,
+				      buffer, PAGE_SIZE);
 			buffer[PAGE_SIZE-1] = '\n';
 			line -= maxlen;
 			if(line < buffer)
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.3.99-pre3/linux/fs/proc/base.c	Tue Mar  7 14:32:26 2000
+++ linux/fs/proc/base.c	Fri Apr  7 13:38:00 2000
@@ -38,22 +38,28 @@
 int proc_pid_statm(struct task_struct*,char*);
 int proc_pid_cpu(struct task_struct*,char*);
 
-static struct dentry *proc_fd_link(struct inode *inode)
+/* MOUNT_REWRITE: make all files have non-NULL ->f_vfsmnt (pipefs, sockfs) */
+static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-	if (inode->u.proc_i.file)
-		return dget(inode->u.proc_i.file->f_dentry);
-	return NULL;
+	if (inode->u.proc_i.file) {
+		if (inode->u.proc_i.file->f_vfsmnt) {
+			*mnt = mntget(inode->u.proc_i.file->f_vfsmnt);
+		}
+		*dentry = dget(inode->u.proc_i.file->f_dentry);
+		return 0;
+	}
+	return -ENOENT;
 }
 
-static struct dentry *proc_exe_link(struct inode *inode)
+static int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
 	struct mm_struct * mm;
 	struct vm_area_struct * vma;
-	struct dentry *result = NULL;
+	int result = -ENOENT;
 	struct task_struct *task = inode->u.proc_i.task;
 
 	if (!task_lock(task))
-		return NULL;
+		return result;
 	mm = task->mm;
 	if (!mm)
 		goto out;
@@ -62,7 +68,9 @@
 	while (vma) {
 		if ((vma->vm_flags & VM_EXECUTABLE) && 
 		    vma->vm_file) {
-			result = dget(vma->vm_file->f_dentry);
+			*mnt = mntget(vma->vm_file->f_vfsmnt);
+			*dentry = dget(vma->vm_file->f_dentry);
+			result = 0;
 			break;
 		}
 		vma = vma->vm_next;
@@ -73,25 +81,31 @@
 	return result;
 }
 
-static struct dentry *proc_cwd_link(struct inode *inode)
+static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-	struct dentry *result = NULL;
+	int result = -ENOENT;
 	if (task_lock(inode->u.proc_i.task)) {
 		struct fs_struct *fs = inode->u.proc_i.task->fs;
-		if (fs)
-			result = dget(fs->pwd);
+		if (fs) {
+			*mnt = mntget(fs->pwdmnt);
+			*dentry = dget(fs->pwd);
+			result = 0;
+		}
 		task_unlock(inode->u.proc_i.task);
 	}
 	return result;
 }
 
-static struct dentry *proc_root_link(struct inode *inode)
+static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-	struct dentry *result = NULL;
+	int result = -ENOENT;
 	if (task_lock(inode->u.proc_i.task)) {
 		struct fs_struct *fs = inode->u.proc_i.task->fs;
-		if (fs)
-			result = dget(fs->root);
+		if (fs) {
+			*mnt = mntget(fs->rootmnt);
+			*dentry = dget(fs->root);
+			result = 0;
+		}
 		task_unlock(inode->u.proc_i.task);
 	}
 	return result;
@@ -160,16 +174,18 @@
 {
 	struct dentry *de, *base, *root;
 	struct super_block *our_sb, *sb, *below;
+	struct vfsmount *our_vfsmnt, *vfsmnt, *mnt;
 
 	if (standard_permission(inode, mask) != 0)
 		return -EACCES;
 
 	base = current->fs->root;
-	de = root = proc_root_link(inode); /* Ewww... */
-
-	if (!de)
+	our_vfsmnt = current->fs->rootmnt;
+	if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
 		return -ENOENT;
 
+	de = root;
+	mnt = vfsmnt;
 	our_sb = base->d_inode->i_sb;
 	sb = de->d_inode->i_sb;
 	while (sb != our_sb) {
@@ -184,9 +200,11 @@
 		goto out;
 
 	dput(root);
+	mntput(mnt);
 	return 0;
 out:
 	dput(root);
+	mntput(mnt);
 	return -EACCES;
 }
 
@@ -345,30 +363,26 @@
 	permission:	proc_permission,
 };
 
-static struct dentry * proc_pid_follow_link(struct dentry *dentry,
-					struct dentry *base,
-					unsigned int follow)
+static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct inode *inode = dentry->d_inode;
-	struct dentry * result;
 	int error;
 
 	/* We don't need a base pointer in the /proc filesystem */
-	dput(base);
+	dput(nd->dentry);
+	mntput(nd->mnt);
 
 	error = proc_permission(inode, MAY_EXEC);
-	result = ERR_PTR(error);
 	if (error)
 		goto out;
 
-	result = inode->u.proc_i.op.proc_get_link(inode);
+	error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
 out:
-	if (!result)
-		result = ERR_PTR(-ENOENT);
-	return result;
+	return error;
 }
 
-static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
+static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt,
+			    char * buffer, int buflen)
 {
 	struct inode * inode;
 	char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
@@ -391,7 +405,7 @@
 		len = sprintf(tmp, pattern, inode->i_ino);
 		path = tmp;
 	} else {
-		path = d_path(dentry, tmp, PAGE_SIZE);
+		path = d_path(dentry, mnt, tmp, PAGE_SIZE);
 		len = tmp + PAGE_SIZE - 1 - path;
 	}
 
@@ -406,22 +420,19 @@
 {
 	int error;
 	struct inode *inode = dentry->d_inode;
+	struct vfsmount *mnt;
 
 	error = proc_permission(inode, MAY_EXEC);
 	if (error)
 		goto out;
 
-	dentry = inode->u.proc_i.op.proc_get_link(inode);
-	error = -ENOENT;
-	if (!dentry)
-		goto out;
-
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	error = inode->u.proc_i.op.proc_get_link(inode, &dentry, &mnt);
+	if (error)
 		goto out;
 
-	error = do_proc_readlink(dentry, buffer, buflen);
+	error = do_proc_readlink(dentry, mnt, buffer, buflen);
 	dput(dentry);
+	mntput(mnt);
 out:
 	return error;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/proc/generic.c linux/fs/proc/generic.c
--- v2.3.99-pre3/linux/fs/proc/generic.c	Tue Mar  7 14:32:26 2000
+++ linux/fs/proc/generic.c	Fri Apr  7 13:38:00 2000
@@ -201,10 +201,10 @@
 	return vfs_readlink(dentry, buffer, buflen, s);
 }
 
-static struct dentry *proc_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags)
+static int proc_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data;
-	return vfs_follow_link(dentry, base, flags, s);
+	return vfs_follow_link(nd, s);
 }
 
 static struct inode_operations proc_link_inode_operations = {
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.3.99-pre3/linux/fs/proc/root.c	Tue Mar  7 14:32:26 2000
+++ linux/fs/proc/root.c	Fri Apr  7 13:38:00 2000
@@ -32,13 +32,11 @@
 	return vfs_readlink(dentry,buffer,buflen,tmp);
 }
 
-static struct dentry * proc_self_follow_link(struct dentry *dentry,
-						struct dentry *base,
-						unsigned int follow)
+static int proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	char tmp[30];
 	sprintf(tmp, "%d", current->pid);
-	return vfs_follow_link(dentry,base,follow,tmp);
+	return vfs_follow_link(nd,tmp);
 }	
 
 static struct inode_operations proc_self_inode_operations = {
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/ramfs/Makefile linux/fs/ramfs/Makefile
--- v2.3.99-pre3/linux/fs/ramfs/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/fs/ramfs/Makefile	Tue Apr 11 10:58:05 2000
@@ -0,0 +1,11 @@
+#
+# Makefile for the linux ramfs routines.
+#
+
+O_TARGET := ramfs.o
+
+O_OBJS := inode.o
+
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/ramfs/inode.c linux/fs/ramfs/inode.c
--- v2.3.99-pre3/linux/fs/ramfs/inode.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ramfs/inode.c	Tue Apr 11 11:02:10 2000
@@ -0,0 +1,393 @@
+/*
+ * Resizable simple ram filesystem for Linux.
+ *
+ * Copyright (C) 2000 Linus Torvalds.
+ *               2000 Transmeta Corp.
+ *
+ * This file is released under the GPL.
+ */
+
+/*
+ * NOTE! This filesystem is probably most useful
+ * not as a real filesystem, but as an example of
+ * how virtual filesystems can be written.
+ *
+ * It doesn't get much simpler than this. Consider
+ * that this file implements the full semantics of
+ * a POSIX-compliant read-write filesystem.
+ *
+ * Note in particular how the filesystem does not
+ * need to implement any data structures of its own
+ * to keep track of the virtual data: using the VFS
+ * caches is sufficient.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include <asm/uaccess.h>
+
+/* some random number */
+#define RAMFS_MAGIC	0x858458f6
+
+static struct super_operations ramfs_ops;
+static struct address_space_operations ramfs_aops;
+static struct file_operations ramfs_dir_operations;
+static struct file_operations ramfs_file_operations;
+static struct inode_operations ramfs_dir_inode_operations;
+
+static int ramfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	buf->f_type = RAMFS_MAGIC;
+	buf->f_bsize = PAGE_CACHE_SIZE;
+	buf->f_namelen = 255;
+	return 0;
+}
+
+/*
+ * Lookup the data. This is trivial - if the dentry didn't already
+ * exist, we know it is negative.
+ */
+static struct dentry * ramfs_lookup(struct inode *dir, struct dentry *dentry)
+{
+	d_add(dentry, NULL);
+	return NULL;
+}
+
+/*
+ * Read a page. Again trivial. If it didn't already exist
+ * in the page cache, it is zero-filled.
+ */
+static int ramfs_readpage(struct dentry *dentry, struct page * page)
+{
+	if (!Page_Uptodate(page)) {
+		memset((void *) page_address(page), 0, PAGE_CACHE_SIZE);
+		SetPageUptodate(page);
+	}
+	UnlockPage(page);
+	return 0;
+}
+
+/*
+ * Writing: just make sure the page gets marked dirty, so that
+ * the page stealer won't grab it.
+ */
+static int ramfs_writepage(struct dentry * dentry, struct page *page)
+{
+	SetPageDirty(page);
+	return 0;
+}
+
+static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+{
+	void *addr;
+
+	addr = (void *) kmap(page);
+	if (!Page_Uptodate(page)) {
+		memset(addr, 0, PAGE_CACHE_SIZE);
+		SetPageUptodate(page);
+	}
+	SetPageDirty(page);
+	return 0;
+}
+
+static int ramfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+{
+	struct inode *inode = (struct inode*)page->mapping->host;
+	loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+
+	kunmap(page);
+	if (pos > inode->i_size)
+		inode->i_size = pos;
+	return 0;
+}
+
+struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev)
+{
+	struct inode * inode = get_empty_inode();
+
+	if (inode) {
+		inode->i_sb = sb;
+		inode->i_dev = sb->s_dev;
+		inode->i_mode = mode;
+		inode->i_uid = current->fsuid;
+		inode->i_gid = current->fsgid;
+		inode->i_size = 0;
+		inode->i_blksize = PAGE_CACHE_SIZE;
+		inode->i_blocks = 0;
+		inode->i_rdev = dev;
+		inode->i_nlink = 1;
+		inode->i_op = NULL;
+		inode->i_fop = NULL;
+		inode->i_mapping->a_ops = &ramfs_aops;
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+		switch (mode & S_IFMT) {
+		default:
+			init_special_inode(inode, mode, dev);
+			break;
+		case S_IFREG:
+			inode->i_fop = &ramfs_file_operations;
+			break;
+		case S_IFDIR:
+			inode->i_op = &ramfs_dir_inode_operations;
+			inode->i_fop = &ramfs_dir_operations;
+			break;
+		case S_IFLNK:
+			inode->i_op = &page_symlink_inode_operations;
+			break;
+		}
+	}
+	return inode;
+}
+
+/*
+ * File creation. Allocate an inode, and we're done..
+ */
+static int ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev)
+{
+	struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev);
+	int error = -ENOSPC;
+
+	if (inode) {
+		d_instantiate(dentry, inode);
+		dget(dentry);		/* Extra count - pin the dentry in core */
+		error = 0;
+	}
+	return error;
+}
+
+static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+	return ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
+}
+
+static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+	return ramfs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+/*
+ * Link a file..
+ */
+static int ramfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry)
+{
+	struct inode *inode = old_dentry->d_inode;
+
+	if (S_ISDIR(inode->i_mode))
+		return -EPERM;
+
+	inode->i_nlink++;
+	inode->i_count++;	/* New dentry reference */
+	dget(dentry);		/* Extra pinning count for the created dentry */
+	d_instantiate(dentry, inode);
+	return 0;
+}
+
+static inline int ramfs_positive(struct dentry *dentry)
+{
+	return dentry->d_inode && !d_unhashed(dentry);
+}
+
+/*
+ * Check that a directory is empty (this works
+ * for regular files too, they'll just always be
+ * considered empty..).
+ *
+ * Note that an empty directory can still have
+ * children, they just all have to be negative..
+ */
+static int ramfs_empty(struct dentry *dentry)
+{
+	struct list_head *list = dentry->d_subdirs.next;
+
+	while (list != &dentry->d_subdirs) {
+		struct dentry *de = list_entry(list, struct dentry, d_child);
+
+		if (ramfs_positive(de))
+			return 0;
+		list = list->next;
+	}
+	return 1;
+}
+
+/*
+ * This works for both directories and regular files.
+ * (non-directories will always have empty subdirs)
+ */
+static int ramfs_unlink(struct inode * dir, struct dentry *dentry)
+{
+	int retval = -ENOTEMPTY;
+
+	if (ramfs_empty(dentry)) {
+		struct inode *inode = dentry->d_inode;
+
+		inode->i_nlink--;
+		dput(dentry);			/* Undo the count from "create" - this does all the work */
+		d_delete(dentry);
+		retval = 0;
+	}
+	return retval;
+}
+
+#define ramfs_rmdir ramfs_unlink
+
+/*
+ * The VFS layer already does all the dentry stuff for rename,
+ * we just have to decrement the usage count for the target if
+ * it exists so that the VFS layer correctly free's it when it
+ * gets overwritten.
+ */
+static int ramfs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry)
+{
+	int error = -ENOTEMPTY;
+
+	if (ramfs_empty(new_dentry)) {
+		struct inode *inode = new_dentry->d_inode;
+		if (inode) {
+			inode->i_nlink--;
+			dput(new_dentry);
+		}
+		error = 0;
+	}
+	return error;
+}
+
+static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
+{
+	int error;
+
+	error = ramfs_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0);
+	if (!error) {
+		int l = strlen(symname)+1;
+		struct inode *inode = dentry->d_inode;
+		error = block_symlink(inode, symname, l);
+	}
+	return error;
+}
+
+/*
+ * This really should be the same as the proc filldir,
+ * once proc does the "one dentry tree" thing..
+ */
+static int ramfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+	int i;
+	struct dentry *dentry = filp->f_dentry;
+
+	i = filp->f_pos;
+	switch (i) {
+		case 0:
+			if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino) < 0)
+				break;
+			i++;
+			filp->f_pos++;
+			/* fallthrough */
+		case 1:
+			if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino) < 0)
+				break;
+			i++;
+			filp->f_pos++;
+			/* fallthrough */
+		default: {
+			struct list_head *list = dentry->d_subdirs.next;
+
+			int j = i-2;
+			for (;;) {
+				if (list == &dentry->d_subdirs)
+					return 0;
+				if (!j)
+					break;
+				j--;
+				list = list->next;
+			}
+
+			do {
+				struct dentry *de = list_entry(list, struct dentry, d_child);
+
+				if (ramfs_positive(de)) {
+					if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino) < 0)
+						break;
+				}
+				filp->f_pos++;
+				list = list->next;
+			} while (list != &dentry->d_subdirs);
+		}
+	}
+	return 0;
+}
+
+static struct address_space_operations ramfs_aops = {
+	readpage:	ramfs_readpage,
+	writepage:	ramfs_writepage,
+	prepare_write:	ramfs_prepare_write,
+	commit_write:	ramfs_commit_write
+};
+
+static struct file_operations ramfs_file_operations = {
+	read:		generic_file_read,
+	write:		generic_file_write,
+	mmap:		generic_file_mmap
+};
+
+static struct file_operations ramfs_dir_operations = {
+	read:		generic_read_dir,
+	readdir:	ramfs_readdir,
+};
+
+static struct inode_operations ramfs_dir_inode_operations = {
+	create:		ramfs_create,
+	lookup:		ramfs_lookup,
+	link:		ramfs_link,
+	unlink:		ramfs_unlink,
+	symlink:	ramfs_symlink,
+	mkdir:		ramfs_mkdir,
+	rmdir:		ramfs_rmdir,
+	mknod:		ramfs_mknod,
+	rename:		ramfs_rename,
+};
+
+
+static struct super_operations ramfs_ops = {
+	statfs:	 ramfs_statfs,
+};
+
+static struct super_block *ramfs_read_super(struct super_block * sb, void * data, int silent)
+{
+	struct inode * inode;
+	struct dentry * root;
+
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = RAMFS_MAGIC;
+	sb->s_op = &ramfs_ops;
+	inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);
+	if (!inode)
+		return NULL;
+
+	root = d_alloc_root(inode);
+	if (!root) {
+		iput(inode);
+		return NULL;
+	}
+	sb->s_root = root;
+	return sb;
+}
+
+static DECLARE_FSTYPE(ramfs_fs_type, "ramfs", ramfs_read_super, 0);
+
+static int __init init_ramfs_fs(void)
+{
+	return register_filesystem(&ramfs_fs_type);
+}
+
+static void __exit exit_ramfs_fs(void)
+{
+	unregister_filesystem(&ramfs_fs_type);
+}
+
+module_init(init_ramfs_fs)
+module_exit(exit_ramfs_fs)
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/read_write.c linux/fs/read_write.c
--- v2.3.99-pre3/linux/fs/read_write.c	Sat Feb 26 22:31:54 2000
+++ linux/fs/read_write.c	Sun Apr  2 17:41:03 2000
@@ -64,17 +64,11 @@
 {
 	off_t retval;
 	struct file * file;
-	struct dentry * dentry;
-	struct inode * inode;
 
 	retval = -EBADF;
 	file = fget(fd);
 	if (!file)
 		goto bad;
-	/* N.B. Shouldn't this be ENOENT?? */
-	if (!(dentry = file->f_dentry) ||
-	    !(inode = dentry->d_inode))
-		goto out_putf;
 	retval = -EINVAL;
 	if (origin <= 2) {
 		loff_t res = llseek(file, offset, origin);
@@ -82,7 +76,6 @@
 		if (res != (loff_t)retval)
 			retval = -EOVERFLOW;	/* LFS: should only happen on 32 bit platforms */
 	}
-out_putf:
 	fput(file);
 bad:
 	return retval;
@@ -95,18 +88,12 @@
 {
 	int retval;
 	struct file * file;
-	struct dentry * dentry;
-	struct inode * inode;
 	loff_t offset;
 
 	retval = -EBADF;
 	file = fget(fd);
 	if (!file)
 		goto bad;
-	/* N.B. Shouldn't this be ENOENT?? */
-	if (!(dentry = file->f_dentry) ||
-	    !(inode = dentry->d_inode))
-		goto out_putf;
 	retval = -EINVAL;
 	if (origin > 2)
 		goto out_putf;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/super.c linux/fs/super.c
--- v2.3.99-pre3/linux/fs/super.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/super.c	Fri Apr  7 13:38:00 2000
@@ -91,6 +91,19 @@
 	return p;
 }
 
+/**
+ *	register_filesystem - register a new filesystem
+ *	@fs: the file system structure
+ *
+ *	Adds the file system passed to the list of file systems the kernel
+ *	is aware of for by mount and other syscalls. Returns 0 on success,
+ *	or a negative errno code on an error.
+ *
+ *	The file_system_type that is passed is linked into the kernel 
+ *	structures and must not be freed until the file system has been
+ *	unregistered.
+ */
+ 
 int register_filesystem(struct file_system_type * fs)
 {
 	int res = 0;
@@ -110,6 +123,18 @@
 	return res;
 }
 
+/**
+ *	unregister_filesystem - unregister a file system
+ *	@fs: filesystem to unregister
+ *
+ *	Remove a file system that was previously successfully registered
+ *	with the kernel. An error is returned if the file system is not found.
+ *	Zero is returned on a success.
+ *	
+ *	Once this function has returned the file_system_type structure may be
+ *	freed or reused.
+ */
+ 
 int unregister_filesystem(struct file_system_type * fs)
 {
 	struct file_system_type ** tmp;
@@ -192,7 +217,6 @@
 {
 	int retval = -EINVAL;
 
-	lock_kernel();
 	switch (option) {
 		case 1:
 			retval = fs_index((const char *) arg1);
@@ -206,7 +230,6 @@
 			retval = fs_maxindex();
 			break;
 	}
-	unlock_kernel();
 	return retval;
 }
 
@@ -253,7 +276,7 @@
 			const char *dev_name, const char *dir_name)
 {
 	struct vfsmount *lptr;
-	char *tmp, *name;
+	char *name;
 
 	lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
 	if (!lptr)
@@ -264,21 +287,19 @@
 	lptr->mnt_dev = sb->s_dev;
 
 	/* N.B. Is it really OK to have a vfsmount without names? */
-	if (dev_name && !IS_ERR(tmp = getname(dev_name))) {
-		name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL);
+	if (dev_name) {
+		name = (char *) kmalloc(strlen(dev_name)+1, GFP_KERNEL);
 		if (name) {
-			strcpy(name, tmp);
+			strcpy(name, dev_name);
 			lptr->mnt_devname = name;
 		}
-		putname(tmp);
 	}
-	if (dir_name && !IS_ERR(tmp = getname(dir_name))) {
-		name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL);
+	if (dir_name) {
+		name = (char *) kmalloc(strlen(dir_name)+1, GFP_KERNEL);
 		if (name) {
-			strcpy(name, tmp);
+			strcpy(name, dir_name);
 			lptr->mnt_dirname = name;
 		}
-		putname(tmp);
 	}
 
 	if (vfsmntlist == (struct vfsmount *)NULL) {
@@ -343,13 +364,16 @@
 static struct proc_nfs_info {
 	int flag;
 	char *str;
+	char *nostr;
 } nfs_info[] = {
-	{ NFS_MOUNT_SOFT, ",soft" },
-	{ NFS_MOUNT_INTR, ",intr" },
-	{ NFS_MOUNT_POSIX, ",posix" },
-	{ NFS_MOUNT_NOCTO, ",nocto" },
-	{ NFS_MOUNT_NOAC, ",noac" },
-	{ 0, NULL }
+	{ NFS_MOUNT_SOFT, ",soft", ",hard" },
+	{ NFS_MOUNT_INTR, ",intr", "" },
+	{ NFS_MOUNT_POSIX, ",posix", "" },
+	{ NFS_MOUNT_TCP, ",tcp", ",udp" },
+	{ NFS_MOUNT_NOCTO, ",nocto", "" },
+	{ NFS_MOUNT_NOAC, ",noac", "" },
+	{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
+	{ 0, NULL, NULL }
 };
 
 int get_filesystem_info( char *buf )
@@ -362,9 +386,10 @@
 	char *path,*buffer = (char *) __get_free_page(GFP_KERNEL);
 
 	if (!buffer) return 0;
-	for (tmp = vfsmntlist; tmp && len < PAGE_SIZE - 160;
-	    tmp = tmp->mnt_next) {
-		path = d_path(tmp->mnt_sb->s_root, buffer, PAGE_SIZE);
+	for (tmp = vfsmntlist; tmp && len < PAGE_SIZE - 160; tmp = tmp->mnt_next) {
+		if (!tmp->mnt_sb || !tmp->mnt_sb->s_root)
+			continue;
+		path = d_path(tmp->mnt_sb->s_root, tmp, buffer, PAGE_SIZE);
 		if (!path)
 			continue;
 		len += sprintf( buf + len, "%s %s %s %s",
@@ -379,14 +404,11 @@
 		}
 		if (!strcmp("nfs", tmp->mnt_sb->s_type->name)) {
 			nfss = &tmp->mnt_sb->u.nfs_sb.s_server;
-			if (nfss->rsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
-				len += sprintf(buf+len, ",rsize=%d",
-					       nfss->rsize);
-			}
-			if (nfss->wsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
-				len += sprintf(buf+len, ",wsize=%d",
-					       nfss->wsize);
-			}
+			len += sprintf(buf+len, ",v%d", nfss->rpc_ops->version);
+
+			len += sprintf(buf+len, ",rsize=%d", nfss->rsize);
+
+			len += sprintf(buf+len, ",wsize=%d", nfss->wsize);
 #if 0
 			if (nfss->timeo != 7*HZ/10) {
 				len += sprintf(buf+len, ",timeo=%d",
@@ -414,10 +436,13 @@
 					       nfss->acdirmax/HZ);
 			}
 			for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
-				if (nfss->flags & nfs_infop->flag) {
-					strcpy(buf + len, nfs_infop->str);
-					len += strlen(nfs_infop->str);
-				}
+				char *str;
+				if (nfss->flags & nfs_infop->flag)
+					str = nfs_infop->str;
+				else
+					str = nfs_infop->nostr;
+				strcpy(buf + len, str);
+				len += strlen(str);
 			}
 			len += sprintf(buf+len, ",addr=%s",
 				       nfss->hostname);
@@ -429,6 +454,14 @@
 	return len;
 }
 
+/**
+ *	__wait_on_super	- wait on a superblock
+ *	@sb: superblock to wait on
+ *
+ *	Waits for a superblock to become unlocked and then returns. It does
+ *	not take the lock. This is an internal function. See wait_on_super.
+ */
+ 
 void __wait_on_super(struct super_block * sb)
 {
 	DECLARE_WAITQUEUE(wait, current);
@@ -473,6 +506,14 @@
 	}
 }
 
+/**
+ *	get_super	-	get the superblock of a device
+ *	@dev: device to get the super block for
+ *	
+ *	Scans the superblock list and finds the superblock of the file system
+ *	mounted on the device given. NULL is returned if no match is found.
+ */
+ 
 struct super_block * get_super(kdev_t dev)
 {
 	struct super_block * s;
@@ -517,9 +558,15 @@
 	return err;
 }
 
-/*
- * Find a super_block with no device assigned.
+/**
+ *	get_empty_super	-	find empty superblocks
+ *
+ *	Find a super_block with no device assigned. A free superblock is 
+ *	found and returned. If neccessary new superblocks are allocated.
+ *	NULL is returned if there are insufficient resources to complete
+ *	the request
  */
+ 
 struct super_block *get_empty_super(void)
 {
 	struct super_block *s;
@@ -850,7 +897,7 @@
  * Anyone using this new feature must know what he/she is doing.
  */
 
-int do_mount(struct block_device *bdev, const char *dev_name,
+static int do_mount(struct block_device *bdev, const char *dev_name,
 	     const char *dir_name, const char * type, int flags, void * data)
 {
 	kdev_t dev;
@@ -881,7 +928,7 @@
 	/*
 	 * Do the lookup first to force automounting.
 	 */
-	dir_d = namei(dir_name);
+	dir_d = lookup_dentry(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
 	error = PTR_ERR(dir_d);
 	if (IS_ERR(dir_d))
 		goto out;
@@ -981,11 +1028,10 @@
 	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
 
 	/*
-	 * Invalidate the inodes, as some mount options may be changed.
-	 * N.B. If we are changing media, we should check the return
-	 * from invalidate_inodes ... can't allow _any_ open files.
+	 * We can't invalidate inodes as we can loose data when remounting
+	 * (someone might manage to alter data while we are waiting in lock_super()
+	 * or in foo_remount_fs()))
 	 */
-	invalidate_inodes(sb);
 
 	return 0;
 }
@@ -995,11 +1041,10 @@
 	struct dentry *dentry;
 	int retval;
 
-	dentry = namei(dir);
+	dentry = lookup_dentry(dir, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
 	retval = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
 		struct super_block * sb = dentry->d_inode->i_sb;
-
 		retval = -ENODEV;
 		if (sb) {
 			retval = -EINVAL;
@@ -1062,8 +1107,8 @@
  * aren't used, as the syscall assumes we are talking to an older
  * version that didn't understand them.
  */
-long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page,
-		  unsigned long new_flags, unsigned long data_page)
+long do_sys_mount(char * dev_name, char * dir_name, char *type_page,
+		  unsigned long new_flags, void *data_page)
 {
 	struct file_system_type * fstype;
 	struct dentry * dentry = NULL;
@@ -1071,6 +1116,15 @@
 	struct block_device *bdev = NULL;
 	int retval;
 	unsigned long flags = 0;
+ 
+	/* Basic sanity checks */
+
+	if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
+		return -EINVAL;
+	if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
+		return -EINVAL;
+	if (dev_name && !memchr(dev_name, 0, PAGE_SIZE))
+		return -EINVAL;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -1083,7 +1137,7 @@
 		goto out;
 	}
 
-	fstype = get_fs_type((char *) type_page);
+	fstype = get_fs_type(type_page);
 	retval = -ENODEV;
 	if (!fstype)		
 		goto out;
@@ -1091,7 +1145,10 @@
 	if (fstype->fs_flags & FS_REQUIRES_DEV) {
 		struct block_device_operations *bdops;
 
-		dentry = namei(dev_name);
+		retval = -EINVAL;
+		if (!dev_name || !*dev_name)
+			goto fs_out;
+		dentry = lookup_dentry(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
 		retval = PTR_ERR(dentry);
 		if (IS_ERR(dentry))
 			goto fs_out;
@@ -1114,7 +1171,7 @@
 		flags = new_flags & ~MS_MGC_MSK;
 
 	retval = do_mount(bdev, dev_name, dir_name, fstype->name, flags,
-				(void *) data_page);
+				data_page);
 
 dput_and_out:
 	dput(dentry);
@@ -1130,6 +1187,8 @@
 	int retval;
 	unsigned long data_page = 0;
 	unsigned long type_page = 0;
+	unsigned long dev_page = 0;
+	char *dir_page;
 
 	lock_kernel();
 	retval = copy_mount_options (type, &type_page);
@@ -1146,12 +1205,24 @@
 		goto out;
 	}
 
+	dir_page = getname(dir_name);
+	retval = PTR_ERR(dir_page);
+	if (IS_ERR(dir_page))
+		goto out1;
+
+	retval = copy_mount_options (dev_name, &dev_page);
+	if (retval < 0)
+		goto out2;
 	retval = copy_mount_options (data, &data_page);
 	if (retval >= 0) {
-		retval = do_sys_mount(dev_name, dir_name, type_page,
-				      new_flags, data_page);
+		retval = do_sys_mount((char*)dev_page,dir_page,(char*)type_page,
+				      new_flags, (void*)data_page);
 		free_page(data_page);
 	}
+	free_page(dev_page);
+out2:
+	putname(dir_page);
+out1:
 	free_page(type_page);
 out:
 	unlock_kernel();
@@ -1162,7 +1233,7 @@
 {
 	struct file_system_type * fs_type;
 	struct super_block * sb;
-	struct vfsmount *vfsmnt;
+	struct vfsmount *vfsmnt = NULL;
 	struct block_device *bdev = NULL;
 	mode_t mode;
 	int retval;
@@ -1186,7 +1257,9 @@
 					sb->s_dirt = 0;
 					sb->s_type = fs_type;
 					current->fs->root = dget(sb->s_root);
+					current->fs->rootmnt = mntget(vfsmnt);
 					current->fs->pwd = dget(sb->s_root);
+					current->fs->pwdmnt = mntget(vfsmnt);
 					ROOT_DEV = sb->s_dev;
 			                printk (KERN_NOTICE "VFS: Mounted root (NFS filesystem)%s.\n", (sb->s_flags & MS_RDONLY) ? " readonly" : "");
 					return;
@@ -1298,7 +1371,9 @@
 mount_it:
 	sb->s_flags = root_mountflags;
 	current->fs->root = dget(sb->s_root);
+	current->fs->rootmnt = mntget(vfsmnt);
 	current->fs->pwd = dget(sb->s_root);
+	current->fs->pwdmnt = mntget(vfsmnt);
 	printk ("VFS: Mounted root (%s filesystem)%s.\n",
 		fs_type->name,
 		(sb->s_flags & MS_RDONLY) ? " readonly" : "");
@@ -1321,22 +1396,28 @@
 
 
 static void chroot_fs_refs(struct dentry *old_root,
-    struct dentry *new_root)
+			   struct vfsmount *old_rootmnt,
+			   struct dentry *new_root,
+			   struct vfsmount *new_rootmnt)
 {
 	struct task_struct *p;
 
 	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		if (!p->fs) continue;
-		if (p->fs->root == old_root) {
-			dput(old_root);
+		if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt) {
 			p->fs->root = dget(new_root);
+			p->fs->rootmnt = mntget(new_rootmnt);
+			mntput(old_rootmnt);
+			dput(old_root);
 			printk(KERN_DEBUG "chroot_fs_refs: changed root of "
 			    "process %d\n",p->pid);
 		}
-		if (p->fs->pwd == old_root) {
-			dput(old_root);
+		if (p->fs->pwd == old_root && p->fs->pwdmnt == old_rootmnt) {
 			p->fs->pwd = dget(new_root);
+			p->fs->pwdmnt = mntget(new_rootmnt);
+			mntput(old_rootmnt);
+			dput(old_root);
 			printk(KERN_DEBUG "chroot_fs_refs: changed cwd of "
 			    "process %d\n",p->pid);
 		}
@@ -1344,7 +1425,6 @@
 	read_unlock(&tasklist_lock);
 }
 
-
 /*
  * Moves the current root to put_root, and sets root/cwd of all processes
  * which had them on the old root to new_root.
@@ -1360,9 +1440,11 @@
 asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
 {
 	struct dentry *root = current->fs->root;
+	struct vfsmount *root_mnt = current->fs->rootmnt;
 	struct dentry *d_new_root, *d_put_old, *covered;
 	struct dentry *root_dev_root, *new_root_dev_root;
 	struct dentry *walk, *next;
+	struct vfsmount *new_root_mnt = NULL;
 	int error;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -1414,7 +1496,7 @@
 	root_dev_root = root->d_sb->s_root;
 	root_dev_root->d_covers = dget(d_put_old);
 	d_put_old->d_mounts = root_dev_root;
-	chroot_fs_refs(root,d_new_root);
+	chroot_fs_refs(root,root_mnt,d_new_root,new_root_mnt);
 	error = 0;
 out2:
 	up(&mount_sem);
@@ -1444,7 +1526,7 @@
 		return -EBUSY;
 	}
 	/*  First unmount devfs if mounted  */
-	dir_d = lookup_dentry ("/dev", NULL, 1);
+	dir_d = lookup_dentry ("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE);
 	if (!IS_ERR(dir_d)) {
 		struct super_block *sb = dir_d->d_inode->i_sb;
 
@@ -1467,12 +1549,9 @@
 	/*
 	 * Get the new mount directory
 	 */
-	dir_d = lookup_dentry(put_old, NULL, 1);
+	dir_d = lookup_dentry(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
 	if (IS_ERR(dir_d)) {
 		error = PTR_ERR(dir_d);
-	} else if (!dir_d->d_inode) {
-		dput(dir_d);
-		error = -ENOENT;
 	} else {
 		error = 0;
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/udf/file.c linux/fs/udf/file.c
--- v2.3.99-pre3/linux/fs/udf/file.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/udf/file.c	Mon Apr 10 22:50:40 2000
@@ -315,7 +315,7 @@
  */
 static int udf_open_file(struct inode * inode, struct file * filp)
 {
-	if ((inode->i_size & 0xFFFFFFFF00000000UL) && !(filp->f_flags & O_LARGEFILE))
+	if ((inode->i_size & 0xFFFFFFFF00000000ULL) && !(filp->f_flags & O_LARGEFILE))
 		return -EFBIG;
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/udf/inode.c linux/fs/udf/inode.c
--- v2.3.99-pre3/linux/fs/udf/inode.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/udf/inode.c	Mon Apr 10 22:50:40 2000
@@ -78,7 +78,9 @@
 	{
 		lock_kernel();
 		udf_discard_prealloc(inode);
-		write_inode_now(inode);
+		/* write the root inode on put, if dirty */
+		if (!inode->i_sb->s_root && inode->i_state & I_DIRTY)
+			udf_update_inode(inode, IS_SYNC(inode));
 		unlock_kernel();
 	}
 }
@@ -111,7 +113,7 @@
 
 	inode->i_size = 0;
 	udf_truncate(inode);
-	write_inode_now(inode);
+	udf_update_inode(inode, IS_SYNC(inode));
 	udf_free_inode(inode);
 out:
 	unlock_kernel();
@@ -1005,10 +1007,6 @@
 		inode->i_nlink = 1;
 	
 	inode->i_size = le64_to_cpu(fe->informationLength);
-#if BITS_PER_LONG < 64
-	if (le64_to_cpu(fe->informationLength) & 0xFFFFFFFF00000000ULL)
-		inode->i_size = (Uint32)-1;
-#endif
 
 	inode->i_mode = udf_convert_permissions(fe);
 	inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/ufs/symlink.c linux/fs/ufs/symlink.c
--- v2.3.99-pre3/linux/fs/ufs/symlink.c	Thu Feb 10 17:11:19 2000
+++ linux/fs/ufs/symlink.c	Fri Apr  7 13:38:00 2000
@@ -33,10 +33,10 @@
 	return vfs_readlink(dentry, buffer, buflen, s);
 }
 
-static struct dentry *ufs_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags)
+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(dentry, base, flags, s);
+	return vfs_follow_link(nd, s);
 }
 
 struct inode_operations ufs_fast_symlink_inode_operations = {
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.3.99-pre3/linux/fs/umsdos/dir.c	Tue Mar  7 14:32:26 2000
+++ linux/fs/umsdos/dir.c	Sun Apr  2 15:53:28 2000
@@ -651,9 +651,7 @@
 	struct dentry * old_root = current->fs->root;
 	char * path;
 
-	/* N.B. not safe -- fix this soon! */
-	current->fs->root = dentry->d_sb->s_root;
-	path = d_path(dentry, buffer, len);
+	path = __d_path(dentry, NULL, dentry->d_sb->s_root, NULL, buffer, len);
 
 	if (*path == '/')
 		path++; /* skip leading '/' */
@@ -665,7 +663,6 @@
 		memcpy(path, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN);
 	}
 
-	current->fs->root = old_root;
 	return path;
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-alpha/namei.h linux/include/asm-alpha/namei.h
--- v2.3.99-pre3/linux/include/asm-alpha/namei.h	Mon Nov 16 10:38:09 1998
+++ linux/include/asm-alpha/namei.h	Sun Apr  2 15:49:07 2000
@@ -12,7 +12,6 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_lookup_dentry(name, lookup_flags) \
-        do {} while (0)
+#define __emul_prefix() NULL
 
 #endif /* __ALPHA_NAMEI_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-arc/system.h	Fri Jan 21 18:19:17 2000
+++ linux/include/asm-arm/arch-arc/system.h	Mon Mar 27 10:46:29 2000
@@ -20,7 +20,11 @@
 
 #endif
 
-#define arch_do_idle()		do { } while (0)
+extern __inline__ void arch_idle(void)
+{
+	while (!current->need_resched && !hlt_counter);
+}
+
 #define arch_power_off()	do { } while (0)
 
 extern __inline__ void arch_reset(char mode)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-cl7500/system.h linux/include/asm-arm/arch-cl7500/system.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-cl7500/system.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-arm/arch-cl7500/system.h	Mon Mar 27 10:46:29 2000
@@ -8,8 +8,11 @@
 
 #include <asm/iomd.h>
 
-#define arch_do_idle()				\
-	outb(0, IOMD_SUSMODE)
+extern __inline__ void arch_idle(void)
+{
+	while (!current->need_resched && !hlt_counter)
+		outb(0, IOMD_SUSMODE);
+}
 
 #define arch_reset(mode)			\
 	do {					\
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-cl7500/vmalloc.h linux/include/asm-arm/arch-cl7500/vmalloc.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-cl7500/vmalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-cl7500/vmalloc.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-cl7500/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	  (8*1024*1024)
+#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-ebsa110/hardware.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/arch-ebsa110/hardware.h	Mon Mar 27 10:46:29 2000
@@ -27,6 +27,7 @@
  * RAM definitions
  */
 #define FLUSH_BASE_PHYS		0x40000000
+#define UNCACHEABLE_ADDR	0xf3000000
 
 #else	/* __ASSEMBLY__ */
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-ebsa110/system.h linux/include/asm-arm/arch-ebsa110/system.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-ebsa110/system.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-arm/arch-ebsa110/system.h	Mon Mar 27 10:46:29 2000
@@ -6,7 +6,31 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-#define arch_do_idle()		cpu_do_idle()
+/*
+ * This machine must never stop it MCLK.  However, if we are
+ * idle for a long time, slow the processor clock to MCLK.
+ */
+extern __inline__ void arch_idle(void)
+{
+	unsigned long start_idle;
+
+	start_idle = jiffies;
+
+	do {
+		if (current->need_resched || hlt_counter)
+			goto slow_out;
+	} while (time_before(start_idle, jiffies + HZ/3));
+
+	cpu_do_idle(IDLE_CLOCK_SLOW);
+
+	while (!current->need_resched && !hlt_counter) {
+		/* do nothing slowly */
+	}
+
+	cpu_do_idle(IDLE_CLOCK_FAST);
+slow_out:
+}
+
 #define arch_power_off()	do { } while (0)
 #define arch_reset(mode)	cpu_reset(0x80000000)
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-ebsa110/vmalloc.h linux/include/asm-arm/arch-ebsa110/vmalloc.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-ebsa110/vmalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa110/vmalloc.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	  (8*1024*1024)
+#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-ebsa285/hardware.h linux/include/asm-arm/arch-ebsa285/hardware.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-ebsa285/hardware.h	Tue Dec 14 01:27:24 1999
+++ linux/include/asm-arm/arch-ebsa285/hardware.h	Mon Mar 27 10:46:29 2000
@@ -58,7 +58,7 @@
 #define FLASH_BASE		0xf8000000
 
 #define PCIMEM_SIZE		0x01000000
-#define PCIMEM_BASE		0xe0000000
+#define PCIMEM_BASE		0xf0000000
 
 #elif defined(CONFIG_ARCH_CO285)
 
@@ -105,6 +105,7 @@
 #define PARAMS_BASE		(PAGE_OFFSET + PARAMS_OFFSET)
 
 #define FLUSH_BASE_PHYS		0x50000000
+#define UNCACHEABLE_ADDR	(ARMCSR_BASE + 0x108)
 
 
 /* PIC irq control */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-ebsa285/system.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-arm/arch-ebsa285/system.h	Mon Mar 27 10:46:29 2000
@@ -8,7 +8,28 @@
 #include <asm/hardware.h>
 #include <asm/leds.h>
 
-#define arch_do_idle()		cpu_do_idle()
+extern __inline__ void arch_idle(void)
+{
+	unsigned long start_idle;
+
+	start_idle = jiffies;
+
+	do {
+		if (current->need_resched || hlt_counter)
+			goto slow_out;
+		cpu_do_idle(IDLE_WAIT_FAST);
+	} while (time_before(start_idle, jiffies + HZ/3));
+
+	cpu_do_idle(IDLE_CLOCK_SLOW);
+
+	while (!current->need_resched && !hlt_counter) {
+		cpu_do_idle(IDLE_WAIT_SLOW);
+	}
+
+	cpu_do_idle(IDLE_CLOCK_FAST);
+slow_out:
+}
+
 #define arch_power_off()	do { } while (0)
 
 extern __inline__ void arch_reset(char mode)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-ebsa285/vmalloc.h linux/include/asm-arm/arch-ebsa285/vmalloc.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-ebsa285/vmalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/vmalloc.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	  (8*1024*1024)
+#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x20000000)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-nexuspci/system.h linux/include/asm-arm/arch-nexuspci/system.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-nexuspci/system.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-arm/arch-nexuspci/system.h	Mon Mar 27 10:46:29 2000
@@ -6,7 +6,12 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-#define arch_do_idle()		cpu_do_idle()
+extern __inline__ void arch_idle(void)
+{
+	while (!current->need_resched && !hlt_counter)
+		cpu_do_idle(IDLE_WAIT_SLOW);
+}
+
 #define arch_reset(mode)	do { } while (0)
 #define arch_power_off()	do { } while (0)
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-nexuspci/vmalloc.h linux/include/asm-arm/arch-nexuspci/vmalloc.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-nexuspci/vmalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-nexuspci/vmalloc.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-nexuspci/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	  (8*1024*1024)
+#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x20000000)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-rpc/hardware.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/arch-rpc/hardware.h	Mon Mar 27 10:46:29 2000
@@ -39,6 +39,7 @@
 #define SCREEN1_BASE		0xd0000000
 
 #define FLUSH_BASE		0xdf000000
+#define UNCACHEABLE_ADDR	0xdf010000
 
 
 #ifndef __ASSEMBLY__
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-rpc/system.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-arm/arch-rpc/system.h	Mon Mar 27 10:46:29 2000
@@ -7,7 +7,28 @@
 #include <asm/iomd.h>
 #include <asm/io.h>
 
-#define arch_do_idle()		cpu_do_idle()
+extern __inline__ void arch_idle(void)
+{
+	unsigned long start_idle;
+
+	start_idle = jiffies;
+
+	do {
+		if (current->need_resched || hlt_counter)
+			goto slow_out;
+		cpu_do_idle(IDLE_WAIT_FAST);
+	} while (time_before(start_idle, jiffies + HZ/3));
+
+	cpu_do_idle(IDLE_CLOCK_SLOW);
+
+	while (!current->need_resched && !hlt_counter) {
+		cpu_do_idle(IDLE_WAIT_SLOW);
+	}
+
+	cpu_do_idle(IDLE_CLOCK_FAST);
+slow_out:
+}
+
 #define arch_power_off()	do { } while (0)
 
 extern __inline__ void arch_reset(char mode)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-rpc/vmalloc.h linux/include/asm-arm/arch-rpc/vmalloc.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-rpc/vmalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-rpc/vmalloc.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-rpc/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	  (8*1024*1024)
+#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-sa1100/hardware.h linux/include/asm-arm/arch-sa1100/hardware.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-sa1100/hardware.h	Fri Jan 21 18:19:17 2000
+++ linux/include/asm-arm/arch-sa1100/hardware.h	Mon Mar 27 10:46:29 2000
@@ -13,6 +13,7 @@
 #define FLUSH_BASE_PHYS		0xe0000000	/* SA1100 zero bank */
 #define FLUSH_BASE		0xdf000000
 #define FLUSH_BASE_MINICACHE	0xdf800000
+#define UNCACHEABLE_ADDR	0xfa050000
 
 /*
  * PCMCIA IO is mapped to 0xe0000000.  We are likely to use in*()/out*()
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-sa1100/keyboard.h linux/include/asm-arm/arch-sa1100/keyboard.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-sa1100/keyboard.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/arch-sa1100/keyboard.h	Mon Mar 27 10:46:29 2000
@@ -1,27 +1,51 @@
 /*
- * linux/include/asm-arm/arch-sa1100/keyboard.h
- *
- * Keyboard driver definitions for SA1100 architecture
- *
- * This really has to be cleaned up somehow...
- * 
+ *  linux/include/asm-arm/arch-sa1100/keyboard.h
+ *  Created 16 Dec 1999 by Nicolas Pitre <nico@cam.org>
+ *  This file contains the SA1100 architecture specific keyboard definitions
  */
 
-#define KEYBOARD_IRQ 
+#ifndef _SA1100_KEYBOARD_H
+#define _SA1100_KEYBOARD_H
 
-#define NR_SCANCODES 128
+#include <linux/config.h>
 
-#define kbd_setkeycode(sc,kc)  (-EINVAL)
-#define kbd_getkeycode(sc)     (-EINVAL)
-#define kbd_pretranslate(sc,kc)       1
-#define kbd_translate(sc, kcp, raw)   kbd_drv_translate(sc, kcp, raw)
-#define kbd_init_hw()	kbd_drv_init()
-#define kbd_unexpected_up		
 
-#define kbd_leds(leds)	
+#ifdef CONFIG_SA1100_BRUTUS
 
-#define kbd_sysrq_xlate			
-#define kbd_disable_irq()
-#define kbd_enable_irq()
+extern int Brutus_kbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern void Brutus_kbd_leds(unsigned char leds);
+extern void Brutus_kbd_init_hw(void);
+extern void Brutus_kbd_enable_irq(void);
+extern void Brutus_kbd_disable_irq(void);
+extern unsigned char Brutus_kbd_sysrq_xlate[128];
+
+#define kbd_setkeycode(x...)	(-ENOSYS)
+#define kbd_getkeycode(x...)	(-ENOSYS)
+#define kbd_translate		Brutus_kbd_translate
+#define kbd_unexpected_up(x...)	(1)
+#define kbd_leds		Brutus_kbd_leds
+#define kbd_init_hw		Brutus_kbd_init_hw
+#define kbd_enable_irq		Brutus_kbd_enable_irq
+#define kbd_disable_irq		Brutus_kbd_disable_irq
+#define kbd_sysrq_xlate		Brutus_kbd_sysrq_xlate
+
+#define SYSRQ_KEY 0x54
+
+#else
+
+/* dummy i.e. no real keyboard */
+#define kbd_setkeycode(x...)	(-ENOSYS)
+#define kbd_getkeycode(x...)	(-ENOSYS)
+#define kbd_translate(x...)	(0)
+#define kbd_unexpected_up(x...)	(1)
+#define kbd_leds(x...)		(0)
+#define kbd_init_hw(x...)	(0)
+#define kbd_enable_irq(x...)	(0)
+#define kbd_disable_irq(x...)	(0)
+
+#endif
+
+
+#endif  /* _SA1100_KEYBOARD_H */
 
-#define SYSRQ_KEY	0x54
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-sa1100/system.h linux/include/asm-arm/arch-sa1100/system.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-sa1100/system.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-arm/arch-sa1100/system.h	Mon Mar 27 10:46:29 2000
@@ -5,43 +5,43 @@
  */
 #include <linux/config.h>
 
-#ifdef CONFIG_SA1100_VICTOR
-
-#define arch_reset( x ) {					\
-	/* switch off power supply */				\
-	mdelay(2000); 						\
-	GPCR = GPIO_GPIO23;					\
-	while(1);						\
+extern __inline__ void arch_idle(void)
+{
+	while (!current->need_resched && !hlt_counter) {
+		cpu_do_idle(IDLE_CLOCK_SLOW);
+		cpu_do_idle(IDLE_WAIT_FAST);
+		cpu_do_idle(IDLE_CLOCK_FAST);
 	}
+}
 
-#else
-
-#define arch_reset(x)	cpu_reset(0)
+#ifdef CONFIG_SA1100_VICTOR
 
-#endif
+extern inline void arch_power_off(void)
+{
+	/* switch off power supply */
+	mdelay(2000);
+	GPCR = GPIO_GPIO23;
+	while(1);
+}
 
+/* power off unconditionally */
+#define arch_reset(x) arch_power_off()
 
-#if 0
-#define arch_do_idle()          cpu_do_idle()
 #else
-/* Enter SA1100 idle mode (see data sheet sec 9.5).
- * It seems that the wait-on-interrupt just hang the CPU forever if it's
- * on the end of a cache line.  Workaround: we force an explicit alignment
- * before it.
- */
-#define arch_do_idle() \
-	do { \
-	__asm__ __volatile__( \
-"	mcr	p15, 0, %0, c15, c2, 2	@ Disable clock switching \n" \
-"	ldr	%0, [%0]		@ Must perform a non-cached access \n" \
-"	b	1f			@ Seems we must align the next \n" \
-"	.align 5			@ instruction on a cache line \n" \
-"1:	mcr	p15, 0, %0, c15, c8, 2	@ Wait for interrupts \n" \
-"	mov	r0, r0			@ insert NOP to ensure SA1100 re-awakes\n" \
-"	mcr	p15, 0, %0, c15, c1, 2	@ Reenable clock switching \n" \
-	: : "r" (&ICIP) : "cc" ); \
-	} while (0)
-#endif
+
+extern inline void arch_reset(char mode)
+{
+	if (mode == 's') {
+		/* Jump into ROM at address 0 */
+		cpu_reset(0);
+	} else {
+		/* Activate SA1100 watchdog and wait for the trigger... */
+		OSMR3 = OSCR + 3686400/2;	/* in 1/2 sec */
+		OWER |= OWER_WME;
+		OIER |= OIER_E3;
+	}
+}
 
 #define arch_power_off()	do { } while (0)
 
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-sa1100/vmalloc.h linux/include/asm-arm/arch-sa1100/vmalloc.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-sa1100/vmalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/vmalloc.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	  (8*1024*1024)
+#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/dma.h linux/include/asm-arm/arch-shark/dma.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/dma.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/dma.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,18 @@
+/*
+ * linux/include/asm-arm/arch-shark/dma.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+/* Use only the lowest 4MB, nothing else works.
+ * The rest is not DMAable. See dev /  .properties
+ * in OpenFirmware.
+ */
+#define MAX_DMA_ADDRESS		0xC0400000
+#define MAX_DMA_CHANNELS	8
+#define DMA_ISA_CASCADE         4
+
+#endif /* _ASM_ARCH_DMA_H */
+
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/hardware.h linux/include/asm-arm/arch-shark/hardware.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/hardware.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/hardware.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,49 @@
+/*
+ * linux/include/asm-arm/arch-shark/hardware.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * derived from:
+ * linux/include/asm-arm/arch-ebsa110/hardware.h
+ * Copyright (C) 1996-1999 Russell King.
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#ifndef __ASSEMBLER__
+
+/*
+ * Mapping areas
+ */
+#define IO_BASE			0xe0000000
+
+/*
+ * RAM definitions
+ */
+#define FLUSH_BASE_PHYS		0x60000000
+
+#else
+
+#define IO_BASE			0
+
+#endif
+
+#define IO_SIZE			0x10000000
+#define IO_START		0x40000000
+
+#define FLUSH_BASE		0xdf000000
+#define PCIO_BASE		0xe0000000
+
+
+/* defines for the Framebuffer */
+#define FB_BASE                 0xd0000000
+#define FB_START                0x06000000
+#define FB_SIZE                 0x00200000
+
+/* Registers for Framebuffer */
+#define FBREG_BASE              (FB_BASE + FB_SIZE)
+#define FBREG_START             0x06800000
+#define FBREG_SIZE              0x000c0000
+
+#endif
+
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/ide.h linux/include/asm-arm/arch-shark/ide.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/ide.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/ide.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,45 @@
+/*
+ * linux/include/asm-arm/arch-shark/ide.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * derived from:
+ * linux/include/asm-arm/arch-ebsa285/ide.h
+ * Copyright (c) 1998 Russell King
+ */
+
+#include <asm/irq.h>
+
+/*
+ * Set up a hw structure for a specified data port, control port and IRQ.
+ * This should follow whatever the default interface uses.
+ */
+static __inline__ void
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+{
+	ide_ioreg_t reg = (ide_ioreg_t) data_port;
+	int i;
+
+	memset(hw, 0, sizeof(*hw));
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+	hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
+	hw->irq = irq;
+}
+
+/*
+ * This registers the standard ports for this architecture with the IDE
+ * driver.
+ */
+static __inline__ void
+ide_init_default_hwifs(void)
+{
+	hw_regs_t hw;
+
+	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, 14);
+	ide_register_hw(&hw, NULL);
+}
+
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/io.h linux/include/asm-arm/arch-shark/io.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/io.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/io.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,207 @@
+/*
+ * linux/include/asm-arm/arch-shark/io.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * derived from:
+ * linux/include/asm-arm/arch-ebsa110/io.h
+ * Copyright (C) 1997,1998 Russell King
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We use two different types of addressing - PC style addresses, and ARM
+ * addresses.  PC style accesses the PC hardware with the normal PC IO
+ * addresses, eg 0x3f8 for serial#1.  ARM addresses are 0x80000000+
+ * and are translated to the start of IO.
+ */
+#define __PORT_PCIO(x)	(!((x) & 0x80000000))
+
+/*
+ * Dynamic IO functions - let the compiler
+ * optimize the expressions
+ */
+#define DECLARE_DYN_OUT(fnsuffix,instr)						\
+extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port)	\
+{										\
+	unsigned long temp;							\
+	__asm__ __volatile__(							\
+	"tst	%2, #0x80000000\n\t"						\
+	"mov	%0, %4\n\t"							\
+	"addeq	%0, %0, %3\n\t"							\
+	"str" ##instr## "	%1, [%0, %2]	@ out"###fnsuffix	\
+	: "=&r" (temp)								\
+	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)	\
+	: "cc");								\
+}
+
+#define DECLARE_DYN_IN(sz,fnsuffix,instr)					\
+extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)		\
+{										\
+	unsigned long temp, value;						\
+	__asm__ __volatile__(							\
+	"tst	%2, #0x80000000\n\t"						\
+	"mov	%0, %4\n\t"							\
+	"addeq	%0, %0, %3\n\t"							\
+	"ldr" ##instr## "	%1, [%0, %2]	@ in"###fnsuffix	\
+	: "=&r" (temp), "=r" (value)						\
+	: "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)		\
+	: "cc");								\
+	return (unsigned sz)value;						\
+}
+
+extern __inline__ unsigned int __ioaddr (unsigned int port)			\
+{										\
+	if (__PORT_PCIO(port))							\
+		return (unsigned int)(PCIO_BASE + (port));			\
+	else									\
+		return (unsigned int)(IO_BASE + (port));			\
+}
+
+#define DECLARE_IO(sz,fnsuffix,instr)	\
+	DECLARE_DYN_OUT(fnsuffix,instr)	\
+	DECLARE_DYN_IN(sz,fnsuffix,instr)
+
+DECLARE_IO(char,b,"b")
+DECLARE_IO(short,w,"h")
+DECLARE_IO(long,l,"")
+
+#undef DECLARE_IO
+#undef DECLARE_DYN_OUT
+#undef DECLARE_DYN_IN
+
+/*
+ * Constant address IO functions
+ *
+ * These have to be macros for the 'J' constraint to work -
+ * +/-4096 immediate operand.
+ */
+#define __outbc(value,port)							\
+({										\
+	if (__PORT_PCIO((port)))						\
+		__asm__ __volatile__(						\
+		"strb	%0, [%1, %2]		@ outbc"			\
+		: : "r" (value), "r" (PCIO_BASE), "Jr" (port));		\
+	else									\
+		__asm__ __volatile__(						\
+		"strb	%0, [%1, %2]		@ outbc"			\
+		: : "r" (value), "r" (IO_BASE), "r" (port));		\
+})
+
+#define __inbc(port)								\
+({										\
+	unsigned char result;                                                   \
+	if (__PORT_PCIO((port)))						\
+		__asm__ __volatile__(						\
+		"ldrb	%0, [%1, %2]		@ inbc"				\
+		: "=r" (result) : "r" (PCIO_BASE), "Jr" (port));		\
+	else									\
+		__asm__ __volatile__(						\
+		"ldrb	%0, [%1, %2]		@ inbc"				\
+		: "=r" (result) : "r" (IO_BASE), "r" (port));		\
+	result;									\
+})
+
+#define __outwc(value,port)							\
+({										\
+	unsigned long v = value;						\
+	if (__PORT_PCIO((port)))						\
+		__asm__ __volatile__(						\
+		"strh	%0, [%1, %2]		@ outwc"			\
+		: : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" (port));	\
+	else									\
+		__asm__ __volatile__(						\
+		"strh	%0, [%1, %2]		@ outwc"			\
+		: : "r" (v|v<<16), "r" (IO_BASE), "r" (port));		\
+})
+
+#define __inwc(port)								\
+({										\
+	unsigned short result;							\
+	if (__PORT_PCIO((port)))						\
+		__asm__ __volatile__(						\
+		"ldrh	%0, [%1, %2]		@ inwc"				\
+		: "=r" (result) : "r" (PCIO_BASE), "Jr" (port));		\
+	else									\
+		__asm__ __volatile__(						\
+		"ldrh	%0, [%1, %2]		@ inwc"				\
+		: "=r" (result) : "r" (IO_BASE), "r" (port));		\
+	result & 0xffff;							\
+})
+
+#define __outlc(value,port)								\
+({										\
+	unsigned long v = value;						\
+	if (__PORT_PCIO((port)))						\
+		__asm__ __volatile__(						\
+		"str	%0, [%1, %2]		@ outlc"			\
+		: : "r" (v), "r" (PCIO_BASE), "Jr" (port));		\
+	else									\
+		__asm__ __volatile__(						\
+		"str	%0, [%1, %2]		@ outlc"			\
+		: : "r" (v), "r" (IO_BASE), "r" (port));			\
+})
+
+#define __inlc(port)								\
+({										\
+	unsigned long result;							\
+	if (__PORT_PCIO((port)))						\
+		__asm__ __volatile__(						\
+		"ldr	%0, [%1, %2]		@ inlc"				\
+		: "=r" (result) : "r" (PCIO_BASE), "Jr" (port));		\
+	else									\
+		__asm__ __volatile__(						\
+		"ldr	%0, [%1, %2]		@ inlc"				\
+		: "=r" (result) : "r" (IO_BASE), "r" (port));		\
+	result;									\
+})
+
+#define __ioaddrc(port)								\
+({										\
+	unsigned long addr;							\
+	if (__PORT_PCIO((port)))						\
+		addr = PCIO_BASE + (port);				\
+	else									\
+		addr = IO_BASE + (port);					\
+	addr;									\
+})
+
+#define __mem_pci(addr) addr
+
+#define inb(p)	 	(__builtin_constant_p((p)) ? __inbc(p)    : __inb(p))
+#define inw(p)	 	(__builtin_constant_p((p)) ? __inwc(p)    : __inw(p))
+#define inl(p)	 	(__builtin_constant_p((p)) ? __inlc(p)    : __inl(p))
+#define outb(v,p)	(__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
+#define outw(v,p)	(__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
+#define outl(v,p)	(__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
+
+#define __arch_getb(addr)	(*(volatile unsigned char *)(addr))
+#define __arch_getw(addr)	(*(volatile unsigned short *)(addr))
+#define __arch_getl(addr)	(*(volatile unsigned long *)(addr))
+
+#define __arch_putb(b,addr)	(*(volatile unsigned char *)(addr) = (b))
+#define __arch_putw(b,addr)	(*(volatile unsigned short *)(addr) = (b))
+#define __arch_putl(b,addr)	(*(volatile unsigned long *)(addr) = (b))
+
+/*
+ * Translated address IO functions
+ *
+ * IO address has already been translated to a virtual address
+ */
+#define outb_t(v,p)								\
+	(*(volatile unsigned char *)(p) = (v))
+
+#define inb_t(p)								\
+	(*(volatile unsigned char *)(p))
+
+#define outl_t(v,p)								\
+	(*(volatile unsigned long *)(p) = (v))
+
+#define inl_t(p)								\
+	(*(volatile unsigned long *)(p))
+
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/irq.h linux/include/asm-arm/arch-shark/irq.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/irq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/irq.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,123 @@
+/*
+ * linux/include/asm-arm/arch-shark/irq.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * derived from linux/arch/ppc/kernel/i8259.c and:
+ * include/asm-arm/arch-ebsa110/irq.h
+ * Copyright (C) 1996-1998 Russell King
+ */
+
+#define fixup_irq(x) (x)
+
+/*
+ * 8259A PIC functions to handle ISA devices:
+ */
+
+/*
+ * This contains the irq mask for both 8259A irq controllers,
+ * Let through the cascade-interrupt no. 2 (ff-(1<<2)==fb)
+ */
+static unsigned char cached_irq_mask[2] = { 0xfb, 0xff };
+
+/*
+ * These have to be protected by the irq controller spinlock
+ * before being called.
+ */
+static void shark_disable_8259A_irq(unsigned int irq)
+{
+	unsigned int mask;
+	if (irq<8) {
+	  mask = 1 << irq;
+	  cached_irq_mask[0] |= mask;
+	} else {
+	  mask = 1 << (irq-8);
+	  cached_irq_mask[1] |= mask;
+	}
+	outb(cached_irq_mask[1],0xA1);
+	outb(cached_irq_mask[0],0x21);
+}
+
+static void shark_enable_8259A_irq(unsigned int irq)
+{
+	unsigned int mask;
+	if (irq<8) {
+	  mask = ~(1 << irq);
+	  cached_irq_mask[0] &= mask;
+	} else {
+	  mask = ~(1 << (irq-8));
+	  cached_irq_mask[1] &= mask;
+	}
+	outb(cached_irq_mask[1],0xA1);
+	outb(cached_irq_mask[0],0x21);
+}
+
+/*
+ * Careful! The 8259A is a fragile beast, it pretty
+ * much _has_ to be done exactly like this (mask it
+ * first, _then_ send the EOI, and the order of EOI
+ * to the two 8259s is important!
+ */
+static void shark_mask_and_ack_8259A_irq(unsigned int irq)
+{
+        if (irq & 8) {
+                cached_irq_mask[1] |= 1 << (irq-8);
+		inb(0xA1);              /* DUMMY */
+                outb(cached_irq_mask[1],0xA1);
+        } else {
+                cached_irq_mask[0] |= 1 << irq;
+                outb(cached_irq_mask[0],0x21);
+	}
+}
+
+static void bogus_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	printk("Got interrupt %i!\n",irq);
+}
+
+static struct irqaction cascade;
+
+static __inline__ void irq_init_irq(void)
+{
+	int irq;
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= shark_mask_and_ack_8259A_irq;
+		irq_desc[irq].mask	= shark_disable_8259A_irq;
+		irq_desc[irq].unmask	= shark_enable_8259A_irq;
+	}
+
+	/* The PICs are initialized to level triggered and auto eoi!
+	 * If they are set to edge triggered they lose some IRQs,
+	 * if they are set to manual eoi they get locked up after
+	 * a short time
+	 */
+
+	/* init master interrupt controller */
+	outb(0x19, 0x20); /* Start init sequence, level triggered */
+        outb(0x00, 0x21); /* Vector base */
+        outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
+        outb(0x03, 0x21); /* Select 8086 mode , auto eoi*/
+	outb(0x0A, 0x20);
+	/* init slave interrupt controller */
+        outb(0x19, 0xA0); /* Start init sequence, level triggered */
+        outb(0x08, 0xA1); /* Vector base */
+        outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
+        outb(0x03, 0xA1); /* Select 8086 mode, auto eoi */
+	outb(0x0A, 0xA0);
+	outb(cached_irq_mask[1],0xA1);
+	outb(cached_irq_mask[0],0x21);
+	//request_region(0x20,0x2,"pic1");
+	//request_region(0xA0,0x2,"pic2");
+
+	cascade.handler = bogus_int;
+	cascade.flags = 0;
+	cascade.mask = 0;
+	cascade.name = "cascade";
+	cascade.next = NULL;
+	cascade.dev_id = NULL;
+	setup_arm_irq(2,&cascade);
+	
+}
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/irqs.h linux/include/asm-arm/arch-shark/irqs.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/irqs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/irqs.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,11 @@
+/*
+ * linux/include/asm-arm/arch-shark/irqs.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ */
+
+#define NR_IRQS			16
+
+#define IRQ_ISA_KEYBOARD	 1
+#define AUX_IRQ			12
+#define IRQ_HARDDISK            14
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/keyboard.h linux/include/asm-arm/arch-shark/keyboard.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/keyboard.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,95 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/keyboard.h
+ *
+ * Keyboard driver definitions for EBSA285 architecture
+ *
+ * (C) 1998 Russell King
+ * (C) 1998 Phil Blundell
+ */
+#include <linux/ioport.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+extern int have_isa_bridge;
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+
+#define KEYBOARD_IRQ			IRQ_ISA_KEYBOARD
+
+#define NR_SCANCODES 128
+
+#define kbd_setkeycode(sc,kc)				\
+	({						\
+		int __ret;				\
+		if (have_isa_bridge)			\
+			__ret = pckbd_setkeycode(sc,kc);\
+		else					\
+			__ret = -EINVAL;		\
+		__ret;					\
+	})
+
+#define kbd_getkeycode(sc)				\
+	({						\
+		int __ret;				\
+		if (have_isa_bridge)			\
+			__ret = pckbd_getkeycode(sc);	\
+		else					\
+			__ret = -EINVAL;		\
+		__ret;					\
+	})
+
+#define kbd_translate(sc, kcp, rm)			\
+	({						\
+		pckbd_translate(sc, kcp, rm);		\
+	})
+
+#define kbd_unexpected_up		pckbd_unexpected_up
+
+#define kbd_leds(leds)					\
+	do {						\
+		if (have_isa_bridge)			\
+			pckbd_leds(leds);		\
+	} while (0)
+
+#define kbd_init_hw()					\
+	do {						\
+		if (have_isa_bridge)			\
+			pckbd_init_hw();		\
+	} while (0)
+
+#define kbd_sysrq_xlate			pckbd_sysrq_xlate
+
+#define kbd_disable_irq()
+#define kbd_enable_irq()
+
+#define SYSRQ_KEY	0x54
+
+/* resource allocation */
+#define kbd_request_region() request_region(0x60, 16, "keyboard")
+#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+                                             "keyboard", NULL)
+
+/* How to access the keyboard macros on this platform.  */
+#define kbd_read_input() inb(KBD_DATA_REG)
+#define kbd_read_status() inb(KBD_STATUS_REG)
+#define kbd_write_output(val) outb(val, KBD_DATA_REG)
+#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
+
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do { } while(0)
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+#define aux_request_irq(hand, dev_id)					\
+	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
+
+#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/memory.h linux/include/asm-arm/arch-shark/memory.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/memory.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,35 @@
+/*
+ * linux/include/asm-arm/arch-shark/memory.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * derived from:
+ * linux/include/asm-arm/arch-ebsa110/memory.h
+ * Copyright (c) 1996-1999 Russell King.
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+#define TASK_SIZE_26	(0x04000000UL)
+
+/*
+ * Page offset: = 3GB
+ */
+#define PAGE_OFFSET	(0xC0000000UL)
+#define PHYS_OFFSET     (0x08000000UL)
+
+#define __virt_to_phys__is_a_macro
+#define __phys_to_virt__is_a_macro
+#define __virt_to_phys(vpage) (vpage - PAGE_OFFSET + PHYS_OFFSET)
+#define __phys_to_virt(ppage) (ppage - PHYS_OFFSET + PAGE_OFFSET)
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	__virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	__phys_to_virt(x)
+
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/param.h linux/include/asm-arm/arch-shark/param.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/param.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/param.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,10 @@
+/*
+ * linux/include/asm-arm/arch-shark/param.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ */
+
+/* This must be a power of 2 because the RTC
+ * can't use anything else.
+ */
+#define HZ 64
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/processor.h linux/include/asm-arm/arch-shark/processor.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/processor.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/processor.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,28 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/processor.h
+ *
+ * Copyright (C) 1996-1999 Russell King
+ *
+ * Changelog:
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
+ */
+
+#ifndef __ASM_ARCH_PROCESSOR_H
+#define __ASM_ARCH_PROCESSOR_H
+
+#include <asm/arch/memory.h>
+
+/*
+ * Bus types
+ */
+#define EISA_bus 0
+#define EISA_bus__is_a_macro /* for versions in ksyms.c */
+#define MCA_bus 0
+#define MCA_bus__is_a_macro /* for versions in ksyms.c */
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/serial.h linux/include/asm-arm/arch-shark/serial.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/serial.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/serial.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,33 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/serial.h
+ *
+ * Copyright (c) 1996,1997,1998 Russell King.
+ *
+ * Changelog:
+ *  15-10-1996	RMK	Created
+ */
+#ifndef __ASM_ARCH_SERIAL_H
+#define __ASM_ARCH_SERIAL_H
+
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD (1843200 / 16)
+
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+#define RS_TABLE_SIZE 2
+
+     /* UART CLK        PORT  IRQ     FLAGS        */
+#define STD_SERIAL_PORT_DEFNS \
+	{ 0, BASE_BAUD, 0x3F8,  4, STD_COM_FLAGS },	/* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x2F8,  3, STD_COM_FLAGS },	/* ttyS1 */
+
+#define EXTRA_SERIAL_PORT_DEFNS
+
+#endif
+
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/system.h linux/include/asm-arm/arch-shark/system.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/system.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/system.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,21 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/system.h
+ *
+ * Copyright (c) 1996-1998 Russell King.
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+extern __inline__ void arch_reset(char mode)
+{
+	/*
+	 * loop endlessly
+	 */
+	cli();
+}
+
+#define arch_power_off()   do { } while (0)
+#define arch_do_idle() do {} while (0)
+/*cpu_do_idle()*/
+
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/time.h linux/include/asm-arm/arch-shark/time.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/time.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/time.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,101 @@
+/*
+ * linux/include/asm-arm/arch-shark/time.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * Uses the real time clock because you can't run
+ * the timer with level triggered interrupts and
+ * you can't run the shark with edge triggered
+ * inetrrupts (loses ints and hangs).
+ *
+ * derived from linux/drivers/char/rtc.c and:
+ * linux/include/asm-arm/arch-ebsa110/time.h
+ * Copyright (c) 1996,1997,1998 Russell King.
+ */
+
+#include <linux/config.h>
+#include <asm/leds.h>
+#include <linux/mc146818rtc.h>
+
+#define IRQ_TIMER 8
+
+extern void get_rtc_time(struct rtc_time *rtc_tm);
+extern void set_rtc_irq_bit(unsigned char bit);
+extern unsigned long epoch;
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+	CMOS_READ(RTC_INTR_FLAGS);	
+
+#ifdef CONFIG_LEDS
+	{
+		static int count = 50;
+		if (--count == 0) {
+			count = 50;
+			leds_event(led_timer);
+		}
+	}
+#endif
+
+	{
+#ifdef DIVISOR
+		static unsigned int divisor;
+
+		if (divisor-- == 0) {
+			divisor = DIVISOR - 1;
+#else
+		{
+#endif
+			do_timer(regs);
+		}
+	}
+}
+
+static struct irqaction timerirq = {
+	timer_interrupt,
+	SA_INTERRUPT,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+extern __inline__ void setup_timer(void)
+{
+        struct rtc_time r_time;
+        unsigned long flags;
+	int tmp = 0;
+	unsigned char val;
+
+        /*
+	 * Set the clock to 128 Hz, we already have a valid
+	 * vector now:
+	 */
+
+	while (HZ > (1<<tmp))
+	  tmp++;
+
+	/*
+	 * Check that the input was really a power of 2.
+	 */
+	if (HZ != (1<<tmp))
+	  panic("Please set HZ to a power of 2!");
+
+	save_flags(flags);
+	cli();
+	val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
+	val |= (16 - tmp);
+	CMOS_WRITE(val, RTC_FREQ_SELECT);
+	restore_flags(flags);
+	set_rtc_irq_bit(RTC_PIE);
+
+	get_rtc_time(&r_time);
+	xtime.tv_sec = mktime(r_time.tm_year+epoch, r_time.tm_mon+1, r_time.tm_mday,
+			      r_time.tm_hour, r_time.tm_min, r_time.tm_sec);
+
+	setup_arm_irq(IRQ_TIMER, &timerirq);
+}
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/timex.h linux/include/asm-arm/arch-shark/timex.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/timex.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/timex.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,5 @@
+/*
+ * linux/include/asm-arm/arch-shark/timex.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/arch-shark/uncompress.h linux/include/asm-arm/arch-shark/uncompress.h
--- v2.3.99-pre3/linux/include/asm-arm/arch-shark/uncompress.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-shark/uncompress.h	Mon Mar 27 10:46:29 2000
@@ -0,0 +1,34 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/uncompress.h
+ *
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
+
+/*
+ * This does not append a newline
+ */
+static void puts(const char *s)
+{
+	__asm__ __volatile__("
+	ldrb	%0, [%2], #1
+	teq	%0, #0
+	beq	3f
+1:	strb	%0, [%3]
+2:	ldrb	%1, [%3, #0x14]
+	and	%1, %1, #0x60
+	teq	%1, #0x60
+	bne	2b
+	teq	%0, #'\n'
+	moveq	%0, #'\r'
+	beq	1b
+	ldrb	%0, [%2], #1
+	teq	%0, #0
+	bne	1b
+3:	" : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc");
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/checksum.h linux/include/asm-arm/checksum.h
--- v2.3.99-pre3/linux/include/asm-arm/checksum.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-arm/checksum.h	Mon Mar 27 10:46:29 2000
@@ -123,12 +123,14 @@
 	adcs	%0, %0, %3
 	adcs	%0, %0, %4
 	adcs	%0, %0, %5
+	adc	%0, %0, #0
 	adds	%0, %0, %0, lsl #16
-	addcs	%0, %0, #0x10000"
+	addcs	%0, %0, #0x10000
+	mvn	%0, %0"
 	: "=&r"(sum)
-	: "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len) << 16), "Ir" (proto << 8)
+	: "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len)), "Ir" (proto << 8)
 	: "cc");
-	return (~sum) >> 16;
+	return sum >> 16;
 }
 
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/cpu-multi32.h linux/include/asm-arm/cpu-multi32.h
--- v2.3.99-pre3/linux/include/asm-arm/cpu-multi32.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-arm/cpu-multi32.h	Mon Mar 27 10:46:29 2000
@@ -95,7 +95,7 @@
 	/*
 	 * Idle the processor
 	 */
-	int (*_do_idle)(void);
+	int (*_do_idle)(int mode);
 	/*
 	 * flush I cache for a page
 	 */
@@ -110,7 +110,7 @@
 #define cpu_check_bugs()			processor._check_bugs()
 #define cpu_proc_init()				processor._proc_init()
 #define cpu_proc_fin()				processor._proc_fin()
-#define cpu_do_idle()				processor._do_idle()
+#define cpu_do_idle(mode)			processor._do_idle(mode)
 
 #define cpu_flush_cache_all()			processor._flush_cache_all()
 #define cpu_flush_cache_area(start,end,flags)	processor._flush_cache_area(start,end,flags)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/cpu-single.h linux/include/asm-arm/cpu-single.h
--- v2.3.99-pre3/linux/include/asm-arm/cpu-single.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-arm/cpu-single.h	Mon Mar 27 10:46:29 2000
@@ -49,7 +49,7 @@
 extern void cpu_check_bugs(void);
 extern void cpu_proc_init(void);
 extern void cpu_proc_fin(void);
-extern int cpu_do_idle(void);
+extern int cpu_do_idle(int mode);
 
 extern void cpu_flush_cache_all(void);
 extern void cpu_flush_cache_area(unsigned long address, unsigned long end, int flags);
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/namei.h linux/include/asm-arm/namei.h
--- v2.3.99-pre3/linux/include/asm-arm/namei.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/namei.h	Sun Apr  2 15:49:07 2000
@@ -12,51 +12,14 @@
 
 #define ARM_BSD_EMUL "usr/gnemul/bsd/"
 
-static inline struct dentry *
-__arm_lookup_dentry(const char *name, int lookup_flags)
+static inline char *__emul_prefix(void)
 {
-	struct dentry *base;
-	char *emul;
-
 	switch (current->personality) {
 	case PER_BSD:
-		emul = ARM_BSD_EMUL; break;
+		return ARM_BSD_EMUL;
 	default:
 		return NULL;
 	}
-
-	base = lookup_dentry (emul, dget (current->fs->root),
-		      (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
-			
-	if (IS_ERR (base)) return NULL;
-	
-	base = lookup_dentry (name, base, lookup_flags);
-	
-	if (IS_ERR (base)) return NULL;
-	
-	if (!base->d_inode) {
-		struct dentry *fromroot;
-		
-		fromroot = lookup_dentry (name, dget (current->fs->root), 
-					  lookup_flags);
-		
-		if (IS_ERR (fromroot)) return base;
-		
-		if (fromroot->d_inode) {
-			dput(base);
-			return fromroot;
-		}
-		
-		dput(fromroot);
-	}
-	
-	return base;
 }
-
-#define __prefix_lookup_dentry(name, lookup_flags)			\
-	if (current->personality) {					\
-		dentry = __arm_lookup_dentry (name, lookup_flags);	\
-		if (dentry) return dentry;				\
-	}
 
 #endif /* __ASMARM_NAMEI_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.3.99-pre3/linux/include/asm-arm/proc-armv/pgtable.h	Mon Nov  1 13:56:27 1999
+++ linux/include/asm-arm/proc-armv/pgtable.h	Mon Mar 27 10:46:29 2000
@@ -12,6 +12,7 @@
 #define __ASM_PROC_PGTABLE_H
 
 #include <asm/proc/domain.h>
+#include <asm/arch/vmalloc.h>
 
 /*
  * entries per page directory level: they are two-level, so
@@ -21,19 +22,6 @@
 #define PTRS_PER_PMD		1
 #define PTRS_PER_PGD		4096
 
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	  (8*1024*1024)
-#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
-
 /****************
 * PMD functions *
 ****************/
@@ -139,7 +127,7 @@
 #define PAGE_NONE       __pgprot(_L_PTE_DEFAULT)
 #define PAGE_COPY       __pgprot(_L_PTE_DEFAULT | _L_PTE_READ  | L_PTE_BUFFERABLE)
 #define PAGE_SHARED     __pgprot(_L_PTE_DEFAULT | _L_PTE_READ  | L_PTE_BUFFERABLE | L_PTE_WRITE)
-#define PAGE_READONLY   __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+#define PAGE_READONLY   __pgprot(_L_PTE_DEFAULT | _L_PTE_READ  | L_PTE_BUFFERABLE)
 #define PAGE_KERNEL     __pgprot(_L_PTE_DEFAULT | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_DIRTY | L_PTE_WRITE)
 
 #define _PAGE_CHG_MASK	(PAGE_MASK | L_PTE_DIRTY | L_PTE_YOUNG)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-i386/namei.h linux/include/asm-i386/namei.h
--- v2.3.99-pre3/linux/include/asm-i386/namei.h	Mon Nov 16 10:38:09 1998
+++ linux/include/asm-i386/namei.h	Sun Apr  2 15:49:07 2000
@@ -12,7 +12,6 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_lookup_dentry(name, lookup_flags) \
-        do {} while (0)
+#define __emul_prefix() NULL
 
 #endif /* __I386_NAMEI_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-ia64/namei.h linux/include/asm-ia64/namei.h
--- v2.3.99-pre3/linux/include/asm-ia64/namei.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/namei.h	Sun Apr  2 15:49:07 2000
@@ -11,7 +11,6 @@
  * for /usr/gnemul/ emulation stuff.
  * Look at asm-sparc/namei.h for details.
  */
-#define __prefix_lookup_dentry(name, lookup_flags) \
-        do {} while (0)
+#define __emul_prefix() NULL
 
 #endif /* _ASM_IA64_NAMEI_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-m68k/namei.h linux/include/asm-m68k/namei.h
--- v2.3.99-pre3/linux/include/asm-m68k/namei.h	Mon Nov 16 10:38:09 1998
+++ linux/include/asm-m68k/namei.h	Sun Apr  2 15:49:07 2000
@@ -12,7 +12,6 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_lookup_dentry(name, lookup_flags) \
-        do {} while (0)
+#define __emul_prefix() NULL
 
 #endif
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-mips/namei.h linux/include/asm-mips/namei.h
--- v2.3.99-pre3/linux/include/asm-mips/namei.h	Sat Feb 26 22:31:56 2000
+++ linux/include/asm-mips/namei.h	Sun Apr  2 15:49:07 2000
@@ -13,42 +13,18 @@
 /* Only one at this time. */
 #define IRIX32_EMUL "usr/gnemul/irix/"
 
-static inline struct dentry *
-__mips_lookup_dentry(const char *name, int lookup_flags)
-{
-	struct dentry *base;
+#ifdef CONFIG_BINFMT_IRIX
 
+static inline char *__emul_prefix(void)
+{
 	if (current->personality != PER_IRIX32)
-		return ERR_PTR(-ENOENT);
-
-	base = lookup_dentry (IRIX32_EMUL,
-			dget (current->fs->root), 
-			(LOOKUP_FOLLOW | LOOKUP_DIRECTORY));
-			
-	if (IS_ERR (base)) return base;
-	
-	base = lookup_dentry (name, base, lookup_flags);
-
-	if (IS_ERR (base)) return base;
-
-	if (!base->d_inode) {
-		dput(base);
-		return ERR_PTR(-ENOENT);
-	}
-        
-        return base;
+		return NULL;
+	return IRIX32_EMUL;
 }
 
-#ifdef CONFIG_BINFMT_IRIX
-
-#define __prefix_lookup_dentry(name, lookup_flags)				\
-	dentry = __mips_lookup_dentry (name, lookup_flags);			\
-	if (!IS_ERR (dentry)) return dentry;
-
 #else /* !defined(CONFIG_BINFMT_IRIX) */
 
-#define __prefix_lookup_dentry(name, lookup_flags) \
-        do {} while (0)
+#define __emul_prefix() NULL
 
 #endif /* !defined(CONFIG_BINFMT_IRIX) */
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-mips64/namei.h linux/include/asm-mips64/namei.h
--- v2.3.99-pre3/linux/include/asm-mips64/namei.h	Sat Feb 26 22:31:57 2000
+++ linux/include/asm-mips64/namei.h	Sun Apr  2 15:49:07 2000
@@ -13,7 +13,6 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_lookup_dentry(name, lookup_flags) \
-	do {} while (0)
+#define __emul_prefix() NULL
 
 #endif /* _ASM_NAMEI_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-ppc/namei.h linux/include/asm-ppc/namei.h
--- v2.3.99-pre3/linux/include/asm-ppc/namei.h	Sun Nov 15 10:51:50 1998
+++ linux/include/asm-ppc/namei.h	Sun Apr  2 15:49:07 2000
@@ -13,7 +13,6 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_lookup_dentry(name, lookup_flags) \
-	do {} while (0)
+#define __emul_prefix() NULL
 
 #endif /* __PPC_NAMEI_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/bitops.h linux/include/asm-sh/bitops.h
--- v2.3.99-pre3/linux/include/asm-sh/bitops.h	Sun Nov  7 16:37:34 1999
+++ linux/include/asm-sh/bitops.h	Mon Mar 27 10:26:15 2000
@@ -103,7 +103,7 @@
 {
 	unsigned long result;
 
-	__asm__("1:\n"
+	__asm__("1:\n\t"
 		"shlr	%1\n\t"
 		"bt/s	1b\n\t"
 		" add	#1, %0"
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/byteorder.h linux/include/asm-sh/byteorder.h
--- v2.3.99-pre3/linux/include/asm-sh/byteorder.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/byteorder.h	Mon Mar 27 10:26:15 2000
@@ -19,7 +19,7 @@
 
 static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
 {
-	__asm__("swap.b %0,%0"
+	__asm__("swap.b %0, %0"
 		: "=r" (x)
 		:  "0" (x));
 	return x;
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/checksum.h linux/include/asm-sh/checksum.h
--- v2.3.99-pre3/linux/include/asm-sh/checksum.h	Tue Feb  1 01:35:44 2000
+++ linux/include/asm-sh/checksum.h	Mon Mar 27 10:26:15 2000
@@ -55,24 +55,6 @@
 	return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
 }
 
-#if 0
-
-/* Not used at the moment. It is difficult to imagine for what purpose
-   it can be used :-) Please, do not forget to verify_area before it --ANK
- */
-
-/*
- * This combination is currently not used, but possible:
- */
-
-extern __inline__
-unsigned int csum_partial_copy_to_user ( const char *src, char *dst,
-					int len, int sum, int *err_ptr)
-{
-	return csum_partial_copy_generic ( src, dst, len, sum, NULL, err_ptr);
-}
-#endif
-
 /*
  * These are the old (and unsafe) way of doing checksums, a warning message will be
  * printed if they are used and an exeption occurs.
@@ -91,12 +73,12 @@
 {
 	unsigned int __dummy;
 	__asm__("clrt\n\t"
-		"mov	%0,%1\n\t"
+		"mov	%0, %1\n\t"
 		"shll16	%0\n\t"
-		"addc	%0,%1\n\t"
+		"addc	%0, %1\n\t"
 		"movt	%0\n\t"
 		"shlr16	%1\n\t"
-		"add	%1,%0"
+		"add	%1, %0"
 		: "=r" (sum), "=&r" (__dummy)
 		: "0" (sum));
 	return ~sum;
@@ -114,24 +96,24 @@
 	unsigned int sum, __dummy;
 
 	__asm__ __volatile__(
-		"mov.l	@%1+,%0\n\t"
-		"add	#-4,%2\n\t"
+		"mov.l	@%1+, %0\n\t"
+		"add	#-4, %2\n\t"
 		"clrt\n\t"
-		"mov.l	@%1+,%3\n\t"
-		"addc	%3,%0\n\t"
-		"mov.l	@%1+,%3\n\t"
-		"addc	%3,%0\n\t"
-		"mov.l	@%1+,%3\n\t"
-		"addc	%3,%0\n"
+		"mov.l	@%1+, %3\n\t"
+		"addc	%3, %0\n\t"
+		"mov.l	@%1+, %3\n\t"
+		"addc	%3, %0\n\t"
+		"mov.l	@%1+, %3\n\t"
+		"addc	%3, %0\n"
 		"1:\t"
-		"mov.l	@%1+,%3\n\t"
-		"addc	%3,%0\n\t"
+		"mov.l	@%1+, %3\n\t"
+		"addc	%3, %0\n\t"
 		"movt	%3\n\t"
 		"dt	%2\n\t"
 		"bf/s	1b\n\t"
-		" cmp/eq #1,%3\n\t"
-		"mov	#0,%3\n\t"
-		"addc	%3,%0\n\t"
+		" cmp/eq #1, %3\n\t"
+		"mov	#0, %3\n\t"
+		"addc	%3, %0\n\t"
 	/* Since the input registers which are loaded with iph and ihl
 	   are modified, we must also specify them as outputs, or gcc
 	   will assume they contain their original values. */
@@ -153,11 +135,11 @@
 	unsigned long len_proto = (proto<<16)+len;
 #endif
 	__asm__("clrt\n\t"
-		"addc	%0,%1\n\t"
-		"addc	%2,%1\n\t"
-		"addc	%3,%1\n\t"
+		"addc	%0, %1\n\t"
+		"addc	%2, %1\n\t"
+		"addc	%3, %1\n\t"
 		"movt	%0\n\t"
-		"add	%1,%0"
+		"add	%1, %0"
 		: "=r" (sum), "=r" (len_proto)
 		: "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum));
 	return sum;
@@ -195,26 +177,26 @@
 {
 	unsigned int __dummy;
 	__asm__("clrt\n\t"
-		"mov.l	@(0,%2),%1\n\t"
-		"addc	%1,%0\n\t"
-		"mov.l	@(4,%2),%1\n\t"
-		"addc	%1,%0\n\t"
-		"mov.l	@(8,%2),%1\n\t"
-		"addc	%1,%0\n\t"
-		"mov.l	@(12,%2),%1\n\t"
-		"addc	%1,%0\n\t"
-		"mov.l	@(0,%3),%1\n\t"
-		"addc	%1,%0\n\t"
-		"mov.l	@(4,%3),%1\n\t"
-		"addc	%1,%0\n\t"
-		"mov.l	@(8,%3),%1\n\t"
-		"addc	%1,%0\n\t"
-		"mov.l	@(12,%3),%1\n\t"
-		"addc	%1,%0\n\t"
-		"addc	%4,%0\n\t"
-		"addc	%5,%0\n\t"
+		"mov.l	@(0,%2), %1\n\t"
+		"addc	%1, %0\n\t"
+		"mov.l	@(4,%2), %1\n\t"
+		"addc	%1, %0\n\t"
+		"mov.l	@(8,%2), %1\n\t"
+		"addc	%1, %0\n\t"
+		"mov.l	@(12,%2), %1\n\t"
+		"addc	%1, %0\n\t"
+		"mov.l	@(0,%3), %1\n\t"
+		"addc	%1, %0\n\t"
+		"mov.l	@(4,%3), %1\n\t"
+		"addc	%1, %0\n\t"
+		"mov.l	@(8,%3), %1\n\t"
+		"addc	%1, %0\n\t"
+		"mov.l	@(12,%3), %1\n\t"
+		"addc	%1, %0\n\t"
+		"addc	%4, %0\n\t"
+		"addc	%5, %0\n\t"
 		"movt	%1\n\t"
-		"add	%1,%0\n"
+		"add	%1, %0\n"
 		: "=r" (sum), "=&r" (__dummy)
 		: "r" (saddr), "r" (daddr), 
 		  "r" (htonl(len)), "r" (htonl(proto)), "0" (sum));
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/current.h linux/include/asm-sh/current.h
--- v2.3.99-pre3/linux/include/asm-sh/current.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/current.h	Mon Mar 27 10:26:15 2000
@@ -12,8 +12,8 @@
 {
 	struct task_struct *current;
 
-	__asm__("stc	r4_bank,%0\n\t"
-		"add	%1,%0"
+	__asm__("stc	$r4_bank, %0\n\t"
+		"add	%1, %0"
 		:"=&r" (current)
 		:"r" (-8192));
 	return current;
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/delay.h linux/include/asm-sh/delay.h
--- v2.3.99-pre3/linux/include/asm-sh/delay.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/delay.h	Mon Mar 27 10:26:15 2000
@@ -8,7 +8,7 @@
 extern __inline__ void __delay(unsigned long loops)
 {
 	__asm__ __volatile__(
-		"tst	%0,%0\n\t"
+		"tst	%0, %0\n\t"
 		"1:\t"
 		"bf/s	1b\n\t"
 		" dt	%0"
@@ -19,8 +19,8 @@
 extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
 {
 	usecs *= 0x000010c6;		/* 2**32 / 1000000 */
-	__asm__("dmulu.l	%0,%2\n\t"
-		"sts	mach,%0"
+	__asm__("dmulu.l	%0, %2\n\t"
+		"sts	$mach, %0"
 		: "=r" (usecs)
 		: "0" (usecs), "r" (lps)
 		: "macl", "mach");
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/mman.h linux/include/asm-sh/mman.h
--- v2.3.99-pre3/linux/include/asm-sh/mman.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/mman.h	Mon Mar 27 10:26:15 2000
@@ -25,6 +25,12 @@
 #define MCL_CURRENT	1		/* lock all current mappings */
 #define MCL_FUTURE	2		/* lock all future mappings */
 
+#define MADV_NORMAL	0x0		/* default page-in behavior */
+#define MADV_RANDOM	0x1		/* page-in minimum required */
+#define MADV_SEQUENTIAL	0x2		/* read-ahead aggressively */
+#define MADV_WILLNEED	0x3		/* pre-fault pages */
+#define MADV_DONTNEED	0x4		/* discard these pages */
+
 /* compatibility flags */
 #define MAP_ANON	MAP_ANONYMOUS
 #define MAP_FILE	0
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/namei.h linux/include/asm-sh/namei.h
--- v2.3.99-pre3/linux/include/asm-sh/namei.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/namei.h	Sun Apr  2 15:49:07 2000
@@ -12,7 +12,6 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_lookup_dentry(name, lookup_flags) \
-        do {} while (0)
+#define __emul_prefix() NULL
 
 #endif /* __ASM_SH_NAMEI_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/processor.h linux/include/asm-sh/processor.h
--- v2.3.99-pre3/linux/include/asm-sh/processor.h	Tue Mar  7 14:32:26 2000
+++ linux/include/asm-sh/processor.h	Mon Mar 27 10:26:15 2000
@@ -45,8 +45,10 @@
 
 /*
  * User space process size: 2GB.
+ *
+ * Since SH7709 and SH7750 have "area 7", we can't use 0x7c000000--0x7fffffff
  */
-#define TASK_SIZE	0x80000000
+#define TASK_SIZE	0x7c000000UL
 
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
@@ -54,19 +56,25 @@
 #define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
 
 /*
- * FPU structure and data
- */
-/* FD-bit of SR register.
- * When it's set, it means the processor doesn't have right to use FPU,
- * and it results exception when the floating operation is executed.
+ * Bit of SR register
+ *
+ * FD-bit:
+ *     When it's set, it means the processor doesn't have right to use FPU,
+ *     and it results exception when the floating operation is executed.
+ *
+ * IMASK-bit:
+ *     Interrupt level mask
  */
-#define SR_FD	0x00008000
+#define SR_FD    0x00008000
+#define SR_IMASK 0x000000f0
 
-#define NUM_FPU_REGS	16
+/*
+ * FPU structure and data
+ */
 
 struct sh_fpu_hard_struct {
-	unsigned long fp_regs[NUM_FPU_REGS];
-	unsigned long xf_regs[NUM_FPU_REGS];
+	unsigned long fp_regs[16];
+	unsigned long long xd_regs[8];
 	unsigned long fpscr;
 	unsigned long fpul;
 
@@ -75,13 +83,13 @@
 
 /* Dummy fpu emulator  */
 struct sh_fpu_soft_struct {
-	unsigned long fp_regs[NUM_FPU_REGS];
+	unsigned long fp_regs[16];
+	unsigned long long xd_regs[8];
 	unsigned long fpscr;
 	unsigned long fpul;
-	unsigned long xf_regs[NUM_FPU_REGS];
 
-	unsigned char	lookahead;
-	unsigned long	entry_pc;
+	unsigned char lookahead;
+	unsigned long entry_pc;
 };
 
 union sh_fpu_union {
@@ -120,7 +128,7 @@
 	regs->pr = 0;   		 	 \
 	regs->sr = 0;		/* User mode. */ \
 	regs->pc = new_pc;			 \
-	regs->sp = new_sp
+	regs->regs[15] = new_sp
 
 /* Forward declaration, a strange C thing */
 struct task_struct;
@@ -188,6 +196,9 @@
 	if ((tsk)->flags & PF_USEDFPU)	 	\
 		(tsk)->flags &= ~PF_USEDFPU; 	\
 } while (0)
+
+/* Double presision, NANS as NANS, rounding to nearest, no exceptions */
+#define FPSCR_INIT  0x00080000
 
 /*
  * Return saved PC of a blocked thread.
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/ptrace.h linux/include/asm-sh/ptrace.h
--- v2.3.99-pre3/linux/include/asm-sh/ptrace.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/ptrace.h	Mon Mar 27 10:26:15 2000
@@ -2,19 +2,49 @@
 #define __ASM_SH_PTRACE_H
 
 /*
- * Copyright (C) 1999  Niibe Yutaka
+ * Copyright (C) 1999, 2000  Niibe Yutaka
  *
  */
 
 /*
+ * As GCC does:
+ *  0 - 15 are integer registers
+ * 17 - 22 are control/special registers
+ * 24 - 39 fp registers
+ * 40 - 47 xd registers
+ * 48 -    fpscr register
+ * -----------------------------
+ * Not as GCC:
+ * 16 --- program counter PC
+ * 23 --- syscall #
+ */
+#define REG_REG0	 0
+#define REG_REG15	15
+#define REG_PC		16
+
+#define REG_PR		17
+#define REG_SR		18
+#define REG_GBR      	19
+#define REG_MACH	20
+#define REG_MACL	21
+#define REG_FPUL	22
+
+#define REG_SYSCALL	23
+
+#define REG_FPREG0	24
+#define REG_FPREG15	39
+#define REG_XDREG0	40
+#define REG_XDREG14	47
+#define REG_FPSCR	48
+
+/*
  * This struct defines the way the registers are stored on the
  * kernel stack during a system call or other kernel entry.
  */
 struct pt_regs {
 	long syscall_nr;
 	unsigned long sr;
-	unsigned long sp;
-	unsigned long regs[15];
+	unsigned long regs[16];
 	unsigned long gbr;
 	unsigned long mach;
 	unsigned long macl;
@@ -26,6 +56,60 @@
 #define user_mode(regs) (((regs)->sr & 0x40000000)==0)
 #define instruction_pointer(regs) ((regs)->pc)
 extern void show_regs(struct pt_regs *);
+
+/* User Break Controller */
+
+#if defined(__sh3__)
+/* The value is for sh4, please fix... */
+#define UBC_BARA		0xff200000
+#define UBC_BAMRA		0xff200004
+#define UBC_BBRA		0xff200008
+#define UBC_BASRA		0xff000014
+#define UBC_BARB		0xff20000c
+#define UBC_BAMRB		0xff200010
+#define UBC_BBRB		0xff200014
+#define UBC_BASRB		0xff000018
+#define UBC_BDRB		0xff200018
+#define UBC_BDMRB		0xff20001c
+#define UBC_BRCR		0xff200020
+#elif defined(__SH4__)
+#define UBC_BARA		0xff200000
+#define UBC_BAMRA		0xff200004
+#define UBC_BBRA		0xff200008
+#define UBC_BASRA		0xff000014
+#define UBC_BARB		0xff20000c
+#define UBC_BAMRB		0xff200010
+#define UBC_BBRB		0xff200014
+#define UBC_BASRB		0xff000018
+#define UBC_BDRB		0xff200018
+#define UBC_BDMRB		0xff20001c
+#define UBC_BRCR		0xff200020
+#endif
+
+#define BAMR_ASID		(1 << 2)
+#define BAMR_NONE		0
+#define BAMR_10		0x1
+#define BAMR_12		0x2
+#define BAMR_ALL		0x3
+#define BAMR_16		0x8
+#define BAMR_20		0x9
+
+#define BBR_INST		(1 << 4)
+#define BBR_DATA		(2 << 4)
+#define BBR_READ		(1 << 2)
+#define BBR_WRITE		(2 << 4)
+#define BBR_BYTE		0x1
+#define BBR_HALF		0x2
+#define BBR_LONG		0x3
+#define BBR_QUAD		(1 << 6)
+
+#define BRCR_CMFA		(1 << 15)
+#define BRCR_CMFB		(1 << 14)
+#define BRCR_PCBA		(1 << 10)	/* 1: after execution */
+#define BRCR_DBEB		(1 << 7)
+#define BRCR_PCBB		(1 << 6)
+#define BRCR_SEQ		(1 << 3)
+#define BRCR_UBDE		(1 << 0)
 #endif
 
 #endif /* __ASM_SH_PTRACE_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/sigcontext.h linux/include/asm-sh/sigcontext.h
--- v2.3.99-pre3/linux/include/asm-sh/sigcontext.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/sigcontext.h	Mon Mar 27 10:26:15 2000
@@ -5,14 +5,22 @@
 	unsigned long	oldmask;
 
 	/* CPU registers */
-	unsigned long sc_regs[15];
+	unsigned long sc_regs[16];
 	unsigned long sc_gbr;
 	unsigned long sc_mach;
 	unsigned long sc_macl;
 	unsigned long sc_pr;
-	unsigned long sc_sp;
 	unsigned long sc_sr;
 	unsigned long sc_pc;
+
+#if defined(__SH4__)
+	/* FPU registers */
+	unsigned long sc_fpregs[16];
+	unsigned long long sc_xdregs[8];
+	unsigned int sc_fpscr;
+	unsigned int sc_fpul;
+	unsigned int sc_ownedfp;
+#endif
 };
 
 #endif /* __ASM_SH_SIGCONTEXT_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/string.h linux/include/asm-sh/string.h
--- v2.3.99-pre3/linux/include/asm-sh/string.h	Sun Nov  7 16:37:34 1999
+++ linux/include/asm-sh/string.h	Mon Mar 27 10:26:15 2000
@@ -13,11 +13,11 @@
 	unsigned long __dummy;
 
 	__asm__ __volatile__("1:\n\t"
-			     "mov.b	@%1+,%2\n\t"
-			     "mov.b	%2,@%0\n\t"
-			     "cmp/eq	#0,%2\n\t"
+			     "mov.b	@%1+, %2\n\t"
+			     "mov.b	%2, @%0\n\t"
+			     "cmp/eq	#0, %2\n\t"
 			     "bf/s	1b\n\t"
-			     " add	#1,%0\n\t"
+			     " add	#1, %0\n\t"
 			     : "=r" (__dest), "=r" (__src), "=&z" (__dummy)
 			     : "0" (__dest), "1" (__src)
 			     : "memory");
@@ -36,13 +36,13 @@
 
 	__asm__ __volatile__(
 		"1:\n"
-		"mov.b	@%1+,%2\n\t"
-		"mov.b	%2,@%0\n\t"
-		"cmp/eq	#0,%2\n\t"
+		"mov.b	@%1+, %2\n\t"
+		"mov.b	%2, @%0\n\t"
+		"cmp/eq	#0, %2\n\t"
 		"bt/s	2f\n\t"
 		" cmp/eq	%5,%1\n\t"
 		"bf/s	1b\n\t"
-		" add	#1,%0\n"
+		" add	#1, %0\n"
 		"2:"
 		: "=r" (__dest), "=r" (__src), "=&z" (__dummy)
 		: "0" (__dest), "1" (__src), "r" (__src+__n)
@@ -58,17 +58,17 @@
 	unsigned long __dummy;
 
 	__asm__ __volatile__(
-		"mov.b	@%1+,%3\n"
+		"mov.b	@%1+, %3\n"
 		"1:\n\t"
-		"mov.b	@%0+,%2\n\t"
-		"cmp/eq #0,%3\n\t"
+		"mov.b	@%0+, %2\n\t"
+		"cmp/eq #0, %3\n\t"
 		"bt	2f\n\t"
-		"cmp/eq %2,%3\n\t"
+		"cmp/eq %2, %3\n\t"
 		"bt/s	1b\n\t"
-		" mov.b	@%1+,%3\n\t"
-		"add	#-2,%1\n\t"
-		"mov.b	@%1,%3\n\t"
-		"sub	%3,%2\n"
+		" mov.b	@%1+, %3\n\t"
+		"add	#-2, %1\n\t"
+		"mov.b	@%1, %3\n\t"
+		"sub	%3, %2\n"
 		"2:"
 		: "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy)
 		: "0" (__cs), "1" (__ct));
@@ -83,20 +83,20 @@
 	unsigned long __dummy;
 
 	__asm__ __volatile__(
-		"mov.b	@%1+,%3\n"
+		"mov.b	@%1+, %3\n"
 		"1:\n\t"
-		"mov.b	@%0+,%2\n\t"
-		"cmp/eq %6,%0\n\t"
+		"mov.b	@%0+, %2\n\t"
+		"cmp/eq %6, %0\n\t"
 		"bt/s	2f\n\t"
-		" cmp/eq #0,%3\n\t"
+		" cmp/eq #0, %3\n\t"
 		"bt/s	3f\n\t"
-		" cmp/eq %3,%2\n\t"
+		" cmp/eq %3, %2\n\t"
 		"bt/s	1b\n\t"
-		" mov.b	@%1+,%3\n\t"
-		"add	#-2,%1\n\t"
-		"mov.b	@%1,%3\n"
+		" mov.b	@%1+, %3\n\t"
+		"add	#-2, %1\n\t"
+		"mov.b	@%1, %3\n"
 		"2:\n\t"
-		"sub	%3,%2\n"
+		"sub	%3, %2\n"
 		"3:"
 		:"=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy)
 		: "0" (__cs), "1" (__ct), "r" (__cs+__n));
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/system.h linux/include/asm-sh/system.h
--- v2.3.99-pre3/linux/include/asm-sh/system.h	Tue Mar  7 14:32:26 2000
+++ linux/include/asm-sh/system.h	Mon Mar 27 10:26:15 2000
@@ -2,7 +2,7 @@
 #define __ASM_SH_SYSTEM_H
 
 /*
- * Copyright (C) 1999, 2000  Niibe Yutaka
+ * Copyright (C) 1999, 2000  Niibe Yutaka  &  Kaz Kojima
  */
 
 /*
@@ -93,13 +93,15 @@
 /* Interrupt Control */
 extern __inline__ void __sti(void)
 {
-	unsigned long __dummy;
+	unsigned long __dummy0, __dummy1;
 
 	__asm__ __volatile__("stc	$sr, %0\n\t"
 			     "and	%1, %0\n\t"
+			     "stc	$r5_bank, %1\n\t"
+			     "or	%1, %0\n\t"
 			     "ldc	%0, $sr"
-			     : "=&r" (__dummy)
-			     : "r" (0xefffffff)
+			     : "=&r" (__dummy0), "=r" (__dummy1)
+			     : "1" (~0xf0)
 			     : "memory");
 }
 
@@ -107,10 +109,10 @@
 {
 	unsigned long __dummy;
 	__asm__ __volatile__("stc	$sr, %0\n\t"
-			     "or	%1, %0\n\t"
+			     "or	#0xf0, %0\n\t"
 			     "ldc	%0, $sr"
-			     : "=&r" (__dummy)
-			     : "r" (0x10000000)
+			     : "=&z" (__dummy)
+			     : /* no inputs */
 			     : "memory");
 }
 
@@ -118,33 +120,70 @@
 x = (__extension__ ({	unsigned long __sr;	\
 	__asm__ __volatile__(			\
 		"stc	$sr, %0"		\
-		: "=r" (__sr)			\
+		: "=&r" (__sr)			\
 		: /* no inputs */		\
 		: "memory");			\
-	 (__sr & 0xffff7f0f);}))
+	 (__sr & 0x000000f0);}))
 
 #define __save_and_cli(x)    				\
 x = (__extension__ ({	unsigned long __dummy,__sr;	\
 	__asm__ __volatile__(                   	\
 		"stc	$sr, %1\n\t" 			\
-		"or	%0, %1\n\t" 			\
-		"stc	$sr, %0\n\t" 			\
-		"ldc	%1, $sr"     			\
-		: "=r" (__sr), "=&r" (__dummy) 		\
-		: "0" (0x10000000) 			\
-		: "memory"); (__sr & 0xffff7f0f); }))
+		"mov	%1, %0\n\t" 			\
+		"or	#0xf0, %0\n\t" 			\
+		"ldc	%0, $sr"     			\
+		: "=&z" (__dummy), "=&r" (__sr)		\
+		: /* no inputs */ 			\
+		: "memory"); (__sr & 0x000000f0); }))
 
 #define __restore_flags(x) do { 			\
-	unsigned long __dummy;				\
-	__asm__ __volatile__(				\
+	unsigned long __dummy0, __dummy1;		\
+	if (x != 0xf0)	/* not CLI-ed? */		\
+		__asm__ __volatile__(		       	\
 		"stc	$sr, %0\n\t"			\
 		"and	%1, %0\n\t"			\
-		"or	%2, %0\n\t"			\
+		"stc	$r5_bank, %1\n\t"		\
+		"or	%1, %0\n\t"			\
 		"ldc	%0, $sr"			\
-		: "=&r" (__dummy)			\
-		: "r" (0x000080f0), /* IMASK+FD */	\
-		  "r" (x)		 		\
+		: "=&r" (__dummy0), "=r" (__dummy1)	\
+		: "1" (0xffffff0f)	 		\
 		: "memory"); 				\
+} while (0)
+
+/*
+ * Jump to P2 area.
+ * When handling TLB or caches, we need to do it from P2 area.
+ */
+#define jump_to_P2()			\
+do {					\
+	unsigned long __dummy;		\
+	__asm__ __volatile__(		\
+		"mov.l	1f, %0\n\t"	\
+		"or	%1, %0\n\t"	\
+		"jmp	@%0\n\t"	\
+		" nop\n\t" 		\
+		".balign 4\n"		\
+		"1:	.long 2f\n"	\
+		"2:"			\
+		: "=&r" (__dummy)	\
+		: "r" (0x20000000));	\
+} while (0)
+
+/*
+ * Back to P1 area.
+ */
+#define back_to_P1()				\
+do {						\
+	unsigned long __dummy;			\
+	__asm__ __volatile__(			\
+		"nop;nop;nop;nop;nop;nop\n\t"	\
+		"mov.l	1f, %0\n\t"		\
+		"jmp	@%0\n\t"		\
+		" nop\n\t"			\
+		".balign 4\n"			\
+		"1:	.long 2f\n"		\
+		"2:"				\
+		: "=&r" (__dummy));		\
 } while (0)
 
 /* For spinlocks etc */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/uaccess.h linux/include/asm-sh/uaccess.h
--- v2.3.99-pre3/linux/include/asm-sh/uaccess.h	Sun Nov  7 16:37:34 1999
+++ linux/include/asm-sh/uaccess.h	Mon Mar 27 10:26:15 2000
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.6 1999/10/29 13:10:44 gniibe Exp $
+/* $Id: uaccess.h,v 1.10 2000/03/24 13:53:45 gniibe Exp $
  *
  * User space memory access functions
  *
@@ -47,7 +47,7 @@
  */
 #define __range_ok(addr,size) ({ \
 	unsigned long flag,sum; \
-	__asm__("clrt; addc %3,%1; movt %0; cmp/hi %4,%1; rotcl %0" \
+	__asm__("clrt; addc %3, %1; movt %0; cmp/hi %4, %1; rotcl %0" \
 		:"=&r" (flag), "=r" (sum) \
 		:"1" (addr), "r" ((int)(size)), "r" (current->addr_limit.seg)); \
 	flag; })
@@ -137,17 +137,17 @@
 ({ \
 __asm__ __volatile__( \
 	"1:\n\t" \
-	"mov." insn "	%2,%1\n\t" \
-	"mov	#0,%0\n" \
-	"2:\n\t" \
+	"mov." insn "	%2, %1\n\t" \
+	"mov	#0, %0\n" \
+	"2:\n" \
 	".section	.fixup,\"ax\"\n" \
 	"3:\n\t" \
-	"mov	#0,%1\n\t" \
-	"mov.l	4f,%0\n\t" \
+	"mov	#0, %1\n\t" \
+	"mov.l	4f, %0\n\t" \
 	"jmp	@%0\n\t" \
-	" mov	%3,%0\n" \
+	" mov	%3, %0\n" \
 	"4:	.long	2b\n\t" \
-	".previous\n\t" \
+	".previous\n" \
 	".section	__ex_table,\"a\"\n\t" \
 	".long	1b, 3b\n\t" \
 	".previous" \
@@ -189,17 +189,17 @@
 ({ \
 __asm__ __volatile__( \
 	"1:\n\t" \
-	"mov." insn "	%1,%2\n\t" \
-	"mov	#0,%0\n" \
-	"2:\n\t" \
+	"mov." insn "	%1, %2\n\t" \
+	"mov	#0, %0\n" \
+	"2:\n" \
 	".section	.fixup,\"ax\"\n" \
 	"3:\n\t" \
 	"nop\n\t" \
-	"mov.l	4f,%0\n\t" \
+	"mov.l	4f, %0\n\t" \
 	"jmp	@%0\n\t" \
-	"mov	%3,%0\n" \
+	"mov	%3, %0\n" \
 	"4:	.long	2b\n\t" \
-	".previous\n\t" \
+	".previous\n" \
 	".section	__ex_table,\"a\"\n\t" \
 	".long	1b, 3b\n\t" \
 	".previous" \
@@ -218,18 +218,18 @@
 
 	__asm__ __volatile__(
 		"9:\n\t"
-		"mov.b	@%2+,%1\n\t"
+		"mov.b	@%2+, %1\n\t"
 		"dt	%0\n"
 		"1:\n\t"
-		"mov.b	%1,@%3\n\t"
+		"mov.b	%1, @%3\n\t"
 		"bf/s	9b\n\t"
-		" add	#1,%3\n"
-		"2:"
+		" add	#1, %3\n"
+		"2:\n"
 		".section .fixup,\"ax\"\n"
 		"3:\n\t"
-		"mov.l	5f,%1\n\t"
+		"mov.l	5f, %1\n\t"
 		"jmp	@%1\n\t"
-		" mov	%7,%0\n\t"
+		" mov	%7, %0\n\t"
 		".balign 4\n"
 		"5:	.long 2b\n"
 		".previous\n"
@@ -238,7 +238,7 @@
 		"	.long 9b,3b\n"
 		"	.long 1b,2b\n"
 		".previous"
-		: "=&r" (res), "=&z" (__dummy), "=&r" (_f), "=&r" (_t)
+		: "=r" (res), "=&z" (__dummy), "=r" (_f), "=r" (_t)
 		: "2" (__from), "3" (__to), "0" (__n), "i" (-EFAULT)
 		: "memory");
 
@@ -297,23 +297,21 @@
 extern __inline__ __kernel_size_t
 __clear_user(void *addr, __kernel_size_t size)
 {
-	__kernel_size_t res;
-	unsigned long __a, __s;
+	unsigned long __a;
 
 	__asm__ __volatile__(
 		"9:\n\t"
-		"dt	%2\n"
+		"dt	%0\n"
 		"1:\n\t"
-		"mov.b	%5,@%1\n\t"
+		"mov.b	%4, @%1\n\t"
 		"bf/s	9b\n\t"
-		" add	#1,%1\n\t"
-		"sub	%2,%0\n"
+		" add	#1, %1\n"
 		"2:\n"
 		".section .fixup,\"ax\"\n"
 		"3:\n\t"
-		"mov.l	4f,%0\n\t"
-		"jmp	@%0\n\t"
-		" mov	%7,%0\n"
+		"mov.l	4f, %1\n\t"
+		"jmp	@%1\n\t"
+		" nop\n"
 		".balign 4\n"
 		"4:	.long 2b\n"
 		".previous\n"
@@ -321,10 +319,10 @@
 		"	.balign 4\n"
 		"	.long 1b,3b\n"
 		".previous"
-		: "=&r" (res), "=&r" (__a), "=&r" (__s)
-		: "1" (addr), "2" (size), "r" (0), "0" (size), "i" (-EFAULT));
+		: "=r" (size), "=r" (__a)
+		: "0" (size), "1" (addr), "r" (0));
 
-	return res;
+	return size;
 }
 
 #define clear_user(addr,n) ({ \
@@ -342,31 +340,31 @@
 
 	__asm__ __volatile__(
 		"9:\n"
-		"mov.b	@%2+,%1\n\t"
-		"cmp/eq	#0,%1\n\t"
+		"mov.b	@%2+, %1\n\t"
+		"cmp/eq	#0, %1\n\t"
 		"bt/s	2f\n"
 		"1:\n"
-		"mov.b	%1,@%3\n\t"
-		"dt	%0\n\t"
+		"mov.b	%1, @%3\n\t"
+		"dt	%7\n\t"
 		"bf/s	9b\n\t"
-		" add	#1,%3\n\t"
-		"sub	%6,%0\n"
-		"2:\n"
+		" add	#1, %3\n\t"
+		"2:\n\t"
+		"sub	%7, %0\n"
+		"3:\n"
 		".section .fixup,\"ax\"\n"
-		"3:\n\t"
-		"mov.l	4f,%1\n\t"
+		"4:\n\t"
+		"mov.l	5f, %1\n\t"
 		"jmp	@%1\n\t"
-		" mov	%8,%0\n\t"
+		" mov	%8, %0\n\t"
 		".balign 4\n"
-		"4:	.long 2b\n"
+		"5:	.long 3b\n"
 		".previous\n"
 		".section __ex_table,\"a\"\n"
 		"	.balign 4\n"
-		"	.long 9b,3b\n"
-		"	.long 1b,2b\n"
+		"	.long 9b,4b\n"
 		".previous"
-		: "=&r" (res), "=&z" (__dummy), "=&r" (_s), "=&r" (_d)
-		: "2" (__src), "3" (__dest), "r" (__count), "0" (__count),
+		: "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d)
+		: "0" (__count), "2" (__src), "3" (__dest), "r" (__count),
 		  "i" (-EFAULT)
 		: "memory");
 
@@ -393,19 +391,19 @@
 
 	__asm__ __volatile__(
 		"9:\n"
-		"cmp/eq	%4,%0\n\t"
+		"cmp/eq	%4, %0\n\t"
 		"bt	2f\n"
 		"1:\t"
-		"mov.b	@(%0,%3),%1\n\t"
-		"tst	%1,%1\n\t"
+		"mov.b	@(%0,%3), %1\n\t"
+		"tst	%1, %1\n\t"
 		"bf/s	9b\n\t"
-		" add	#1,%0\n"
+		" add	#1, %0\n"
 		"2:\n"
 		".section .fixup,\"ax\"\n"
 		"3:\n\t"
-		"mov.l	4f,%1\n\t"
+		"mov.l	4f, %1\n\t"
 		"jmp	@%1\n\t"
-		" mov	%5,%0\n"
+		" mov	%5, %0\n"
 		".balign 4\n"
 		"4:	.long 2b\n"
 		".previous\n"
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/unistd.h linux/include/asm-sh/unistd.h
--- v2.3.99-pre3/linux/include/asm-sh/unistd.h	Tue Mar  7 14:32:26 2000
+++ linux/include/asm-sh/unistd.h	Mon Mar 27 10:26:15 2000
@@ -227,6 +227,8 @@
 #define __NR_setfsuid32		215
 #define __NR_setfsgid32		216
 #define __NR_pivot_root		217
+#define __NR_mincore		218
+#define __NR_madvise		219
 
 /* user-visible error numbers are in the range -1 - -125: see <asm-sh/errno.h> */
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sh/user.h linux/include/asm-sh/user.h
--- v2.3.99-pre3/linux/include/asm-sh/user.h	Tue Mar  7 14:32:26 2000
+++ linux/include/asm-sh/user.h	Mon Mar 27 10:26:15 2000
@@ -30,16 +30,16 @@
  */
 
 struct user_fpu_struct {
-	unsigned long fp_regs[NUM_FPU_REGS];
-	unsigned long xf_regs[NUM_FPU_REGS];
+	unsigned long fp_regs[16];
+	unsigned long long xd_regs[8];
 	unsigned long fpscr;
 	unsigned long fpul;
 };
 
 struct user {
 	struct pt_regs	regs;			/* entire machine state */
-	struct user_fpu_struct fpu;	/* Math Co-processor registers. */
-	int u_fpvalid;		/* True if math co-processor being used. */
+	struct user_fpu_struct fpu;	/* Math Co-processor registers  */
+	int u_fpvalid;		/* True if math co-processor being used */
 	size_t		u_tsize;		/* text size (pages) */
 	size_t		u_dsize;		/* data size (pages) */
 	size_t		u_ssize;		/* stack size (pages) */
@@ -48,7 +48,7 @@
 	unsigned long	start_stack;		/* stack starting address */
 	long int	signal;			/* signal causing core dump */
 	struct regs *	u_ar0;			/* help gdb find registers */
-	struct user_fpu_struct* u_fpstate;	/* Math Co-processor pointer. */
+	struct user_fpu_struct* u_fpstate;	/* Math Co-processor pointer */
 	unsigned long	magic;			/* identifies a core file */
 	char		u_comm[32];		/* user command name */
 };
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc/io.h linux/include/asm-sparc/io.h
--- v2.3.99-pre3/linux/include/asm-sparc/io.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc/io.h	Thu Mar 30 16:54:53 2000
@@ -1,5 +1,5 @@
 /*
- * $Id: io.h,v 1.25 2000/01/22 07:35:46 zaitcev Exp $
+ * $Id: io.h,v 1.26 2000/03/30 01:43:26 davem Exp $
  */
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
@@ -47,6 +47,31 @@
 
 extern __inline__ void writel(unsigned int b, unsigned long addr) {
 	*(volatile unsigned long*)addr = flip_dword(b);
+}
+
+/* Now the 'raw' versions. */
+extern __inline__ unsigned long __raw_readb(unsigned long addr) {
+	return *(volatile unsigned char*)addr;
+}
+
+extern __inline__ unsigned long __raw_readw(unsigned long addr) {
+	return *(volatile unsigned short*)addr;
+}
+
+extern __inline__ unsigned long __raw_readl(unsigned long addr) {
+	return *(volatile unsigned long*)addr;
+}
+
+extern __inline__ void __raw_writeb(unsigned char b, unsigned long addr) {
+	*(volatile unsigned char*)addr = b;
+}
+
+extern __inline__ void __raw_writew(unsigned short b, unsigned long addr) {
+	*(volatile unsigned short*)addr = b;
+}
+
+extern __inline__ void __raw_writel(unsigned int b, unsigned long addr) {
+	*(volatile unsigned long*)addr = b;
 }
 
 /*
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc/namei.h linux/include/asm-sparc/namei.h
--- v2.3.99-pre3/linux/include/asm-sparc/namei.h	Thu Jun 17 01:08:50 1999
+++ linux/include/asm-sparc/namei.h	Sun Apr  2 15:49:07 2000
@@ -11,53 +11,16 @@
 #define SPARC_BSD_EMUL "usr/gnemul/sunos/"
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
 
-static inline struct dentry *
-__sparc_lookup_dentry(const char *name, int lookup_flags)
+static inline char * __emul_prefix(void)
 {
-	struct dentry *base;
-	char *emul;
-
 	switch (current->personality) {
 	case PER_BSD:
-		emul = SPARC_BSD_EMUL; break;
+		return SPARC_BSD_EMUL;
 	case PER_SVR4:
-		emul = SPARC_SOL_EMUL; break;
+		return SPARC_SOL_EMUL;
 	default:
 		return NULL;
 	}
-
-	base = lookup_dentry (emul, 
-			      dget (current->fs->root),
-			      (LOOKUP_FOLLOW | LOOKUP_DIRECTORY));
-			
-	if (IS_ERR (base)) return NULL;
-	
-	base = lookup_dentry (name, base, lookup_flags);
-	
-	if (IS_ERR (base)) return NULL;
-	
-	if (!base->d_inode) {
-		struct dentry *fromroot;
-		
-		fromroot = lookup_dentry (name, dget (current->fs->root), lookup_flags);
-		
-		if (IS_ERR (fromroot)) return base;
-		
-		if (fromroot->d_inode) {
-			dput(base);
-			return fromroot;
-		}
-		
-		dput(fromroot);
-	}
-	
-	return base;
 }
-
-#define __prefix_lookup_dentry(name, lookup_flags)				\
-	if (current->personality) {						\
-		dentry = __sparc_lookup_dentry (name, lookup_flags);		\
-		if (dentry) return dentry;					\
-	}
 
 #endif /* __SPARC_NAMEI_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- v2.3.99-pre3/linux/include/asm-sparc/page.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-sparc/page.h	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.51 2000/03/15 07:19:25 davem Exp $
+/* $Id: page.h,v 1.52 2000/03/28 06:07:25 anton Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
@@ -32,11 +32,20 @@
 
 #ifndef __ASSEMBLY__
 
-#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
-
-#define PAGE_BUG(page) do { \
-	BUG(); \
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+/* We need the mb()'s so we don't trigger a compiler bug - Anton */
+#define BUG() do { \
+	mb(); \
+	__builtin_trap(); \
+	mb(); \
+} while(0)
+#else
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; \
 } while (0)
+#endif
+
+#define PAGE_BUG(page)	BUG()
 
 #define clear_page(page)	 memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from) 	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v2.3.99-pre3/linux/include/asm-sparc/pgtable.h	Mon Mar 27 08:08:31 2000
+++ linux/include/asm-sparc/pgtable.h	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.93 2000/03/21 01:04:53 anton Exp $ */
+/* $Id: pgtable.h,v 1.94 2000/03/28 06:07:25 anton Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -96,12 +96,18 @@
 #define VMALLOC_START (0xfe300000)
 #define VMALLOC_END   ~0x0UL
 
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+#define pte_ERROR(e)   __builtin_trap()
+#define pmd_ERROR(e)   __builtin_trap()
+#define pgd_ERROR(e)   __builtin_trap()
+#else
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
 	printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
 #define pgd_ERROR(e) \
 	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+#endif
 
 BTFIXUPDEF_INT(page_none)
 BTFIXUPDEF_INT(page_shared)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h
--- v2.3.99-pre3/linux/include/asm-sparc64/asm_offsets.h	Sun Feb 20 21:12:39 2000
+++ linux/include/asm-sparc64/asm_offsets.h	Thu Mar 30 16:54:53 2000
@@ -266,33 +266,39 @@
 #define ASIZ_thread_w_saved	0x00000001
 #define AOFF_thread_fpdepth	0x0000000d
 #define ASIZ_thread_fpdepth	0x00000001
-#define AOFF_thread_fpsaved	0x0000000e
+#define AOFF_thread_fault_code	0x0000000e
+#define ASIZ_thread_fault_code	0x00000001
+#define AOFF_thread_use_blkcommit	0x0000000f
+#define ASIZ_thread_use_blkcommit	0x00000001
+#define AOFF_thread_fault_address	0x00000010
+#define ASIZ_thread_fault_address	0x00000008
+#define AOFF_thread_fpsaved	0x00000018
 #define ASIZ_thread_fpsaved	0x00000007
-#define AOFF_thread___pad1	0x00000015
-#define ASIZ_thread___pad1	0x00000003
-#define AOFF_thread_kregs	0x00000018
+#define AOFF_thread___pad2	0x0000001f
+#define ASIZ_thread___pad2	0x00000001
+#define AOFF_thread_kregs	0x00000020
 #define ASIZ_thread_kregs	0x00000008
-#define AOFF_thread_utraps	0x00000020
+#define AOFF_thread_utraps	0x00000028
 #define ASIZ_thread_utraps	0x00000008
-#define AOFF_thread_gsr	0x00000028
+#define AOFF_thread_gsr	0x00000030
 #define ASIZ_thread_gsr	0x00000007
-#define AOFF_thread___pad2	0x0000002f
-#define ASIZ_thread___pad2	0x00000001
-#define AOFF_thread_xfsr	0x00000030
+#define AOFF_thread___pad3	0x00000037
+#define ASIZ_thread___pad3	0x00000001
+#define AOFF_thread_xfsr	0x00000038
 #define ASIZ_thread_xfsr	0x00000038
-#define AOFF_thread_reg_window	0x00000068
+#define AOFF_thread_reg_window	0x00000070
 #define ASIZ_thread_reg_window	0x00000380
-#define AOFF_thread_rwbuf_stkptrs	0x000003e8
+#define AOFF_thread_rwbuf_stkptrs	0x000003f0
 #define ASIZ_thread_rwbuf_stkptrs	0x00000038
-#define AOFF_thread_user_cntd0	0x00000420
+#define AOFF_thread_user_cntd0	0x00000428
 #define ASIZ_thread_user_cntd0	0x00000008
-#define AOFF_thread_user_cntd1	0x00000428
+#define AOFF_thread_user_cntd1	0x00000430
 #define ASIZ_thread_user_cntd1	0x00000008
-#define AOFF_thread_kernel_cntd0	0x00000430
+#define AOFF_thread_kernel_cntd0	0x00000438
 #define ASIZ_thread_kernel_cntd0	0x00000008
-#define AOFF_thread_kernel_cntd1	0x00000438
+#define AOFF_thread_kernel_cntd1	0x00000440
 #define ASIZ_thread_kernel_cntd1	0x00000008
-#define AOFF_thread_pcr_reg	0x00000440
+#define AOFF_thread_pcr_reg	0x00000448
 #define ASIZ_thread_pcr_reg	0x00000008
 #define ASIZ_thread	0x00000450
 
@@ -554,33 +560,39 @@
 #define ASIZ_thread_w_saved	0x00000001
 #define AOFF_thread_fpdepth	0x0000000d
 #define ASIZ_thread_fpdepth	0x00000001
-#define AOFF_thread_fpsaved	0x0000000e
+#define AOFF_thread_fault_code	0x0000000e
+#define ASIZ_thread_fault_code	0x00000001
+#define AOFF_thread_use_blkcommit	0x0000000f
+#define ASIZ_thread_use_blkcommit	0x00000001
+#define AOFF_thread_fault_address	0x00000010
+#define ASIZ_thread_fault_address	0x00000008
+#define AOFF_thread_fpsaved	0x00000018
 #define ASIZ_thread_fpsaved	0x00000007
-#define AOFF_thread___pad1	0x00000015
-#define ASIZ_thread___pad1	0x00000003
-#define AOFF_thread_kregs	0x00000018
+#define AOFF_thread___pad2	0x0000001f
+#define ASIZ_thread___pad2	0x00000001
+#define AOFF_thread_kregs	0x00000020
 #define ASIZ_thread_kregs	0x00000008
-#define AOFF_thread_utraps	0x00000020
+#define AOFF_thread_utraps	0x00000028
 #define ASIZ_thread_utraps	0x00000008
-#define AOFF_thread_gsr	0x00000028
+#define AOFF_thread_gsr	0x00000030
 #define ASIZ_thread_gsr	0x00000007
-#define AOFF_thread___pad2	0x0000002f
-#define ASIZ_thread___pad2	0x00000001
-#define AOFF_thread_xfsr	0x00000030
+#define AOFF_thread___pad3	0x00000037
+#define ASIZ_thread___pad3	0x00000001
+#define AOFF_thread_xfsr	0x00000038
 #define ASIZ_thread_xfsr	0x00000038
-#define AOFF_thread_reg_window	0x00000068
+#define AOFF_thread_reg_window	0x00000070
 #define ASIZ_thread_reg_window	0x00000380
-#define AOFF_thread_rwbuf_stkptrs	0x000003e8
+#define AOFF_thread_rwbuf_stkptrs	0x000003f0
 #define ASIZ_thread_rwbuf_stkptrs	0x00000038
-#define AOFF_thread_user_cntd0	0x00000420
+#define AOFF_thread_user_cntd0	0x00000428
 #define ASIZ_thread_user_cntd0	0x00000008
-#define AOFF_thread_user_cntd1	0x00000428
+#define AOFF_thread_user_cntd1	0x00000430
 #define ASIZ_thread_user_cntd1	0x00000008
-#define AOFF_thread_kernel_cntd0	0x00000430
+#define AOFF_thread_kernel_cntd0	0x00000438
 #define ASIZ_thread_kernel_cntd0	0x00000008
-#define AOFF_thread_kernel_cntd1	0x00000438
+#define AOFF_thread_kernel_cntd1	0x00000440
 #define ASIZ_thread_kernel_cntd1	0x00000008
-#define AOFF_thread_pcr_reg	0x00000440
+#define AOFF_thread_pcr_reg	0x00000448
 #define ASIZ_thread_pcr_reg	0x00000008
 #define ASIZ_thread	0x00000450
 
@@ -840,33 +852,39 @@
 #define ASIZ_thread_w_saved	0x00000001
 #define AOFF_thread_fpdepth	0x0000000d
 #define ASIZ_thread_fpdepth	0x00000001
-#define AOFF_thread_fpsaved	0x0000000e
+#define AOFF_thread_fault_code	0x0000000e
+#define ASIZ_thread_fault_code	0x00000001
+#define AOFF_thread_use_blkcommit	0x0000000f
+#define ASIZ_thread_use_blkcommit	0x00000001
+#define AOFF_thread_fault_address	0x00000010
+#define ASIZ_thread_fault_address	0x00000008
+#define AOFF_thread_fpsaved	0x00000018
 #define ASIZ_thread_fpsaved	0x00000007
-#define AOFF_thread___pad1	0x00000015
-#define ASIZ_thread___pad1	0x00000003
-#define AOFF_thread_kregs	0x00000018
+#define AOFF_thread___pad2	0x0000001f
+#define ASIZ_thread___pad2	0x00000001
+#define AOFF_thread_kregs	0x00000020
 #define ASIZ_thread_kregs	0x00000008
-#define AOFF_thread_utraps	0x00000020
+#define AOFF_thread_utraps	0x00000028
 #define ASIZ_thread_utraps	0x00000008
-#define AOFF_thread_gsr	0x00000028
+#define AOFF_thread_gsr	0x00000030
 #define ASIZ_thread_gsr	0x00000007
-#define AOFF_thread___pad2	0x0000002f
-#define ASIZ_thread___pad2	0x00000001
-#define AOFF_thread_xfsr	0x00000030
+#define AOFF_thread___pad3	0x00000037
+#define ASIZ_thread___pad3	0x00000001
+#define AOFF_thread_xfsr	0x00000038
 #define ASIZ_thread_xfsr	0x00000038
-#define AOFF_thread_reg_window	0x00000068
+#define AOFF_thread_reg_window	0x00000070
 #define ASIZ_thread_reg_window	0x00000380
-#define AOFF_thread_rwbuf_stkptrs	0x000003e8
+#define AOFF_thread_rwbuf_stkptrs	0x000003f0
 #define ASIZ_thread_rwbuf_stkptrs	0x00000038
-#define AOFF_thread_user_cntd0	0x00000420
+#define AOFF_thread_user_cntd0	0x00000428
 #define ASIZ_thread_user_cntd0	0x00000008
-#define AOFF_thread_user_cntd1	0x00000428
+#define AOFF_thread_user_cntd1	0x00000430
 #define ASIZ_thread_user_cntd1	0x00000008
-#define AOFF_thread_kernel_cntd0	0x00000430
+#define AOFF_thread_kernel_cntd0	0x00000438
 #define ASIZ_thread_kernel_cntd0	0x00000008
-#define AOFF_thread_kernel_cntd1	0x00000438
+#define AOFF_thread_kernel_cntd1	0x00000440
 #define ASIZ_thread_kernel_cntd1	0x00000008
-#define AOFF_thread_pcr_reg	0x00000440
+#define AOFF_thread_pcr_reg	0x00000448
 #define ASIZ_thread_pcr_reg	0x00000008
 #define ASIZ_thread	0x00000450
 #endif /* SPIN_LOCK_DEBUG */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- v2.3.99-pre3/linux/include/asm-sparc64/bitops.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-sparc64/bitops.h	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.27 2000/02/09 03:28:33 davem Exp $
+/* $Id: bitops.h,v 1.28 2000/03/27 10:38:56 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -8,132 +8,17 @@
 #define _SPARC64_BITOPS_H
 
 #include <asm/byteorder.h>
-#include <asm/asi.h>         /* For the little endian spaces. */
 
-/* These can all be exported to userland, because the atomic
- * primitives used are not privileged.
- */
-
-/* Set bit 'nr' in 64-bit quantity at address 'addr' where bit '0'
- * is in the highest of the eight bytes and bit '63' is the high bit
- * within the first byte. Sparc is BIG-Endian. Unless noted otherwise
- * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
- */
-
-extern __inline__ int test_and_set_bit(unsigned long nr, void *addr)
-{
-	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
-	unsigned long oldbit;
-
-	__asm__ __volatile__("
-1:	ldx		[%2], %%g7
-	andcc		%%g7, %1, %0
-	bne,pn		%%xcc, 2f
-	 xor		%%g7, %1, %%g5
-	casx 		[%2], %%g7, %%g5
-	cmp		%%g7, %%g5
-	bne,pn		%%xcc, 1b
-	 nop
-2:
-"	: "=&r" (oldbit)
-	: "HIr" (1UL << (nr & 63)), "r" (m)
-	: "g5", "g7", "cc", "memory");
-	return oldbit != 0;
-}
-
-extern __inline__ void set_bit(unsigned long nr, void *addr)
-{
-	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
-
-	__asm__ __volatile__("
-1:	ldx		[%1], %%g7
-	andcc		%%g7, %0, %%g0
-	bne,pn		%%xcc, 2f
-	 xor		%%g7, %0, %%g5
-	casx 		[%1], %%g7, %%g5
-	cmp		%%g7, %%g5
-	bne,pn		%%xcc, 1b
-	 nop
-2:
-"	: /* no outputs */
-	: "HIr" (1UL << (nr & 63)), "r" (m)
-	: "g5", "g7", "cc", "memory");
-}
-
-extern __inline__ int test_and_clear_bit(unsigned long nr, void *addr)
-{
-	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
-	unsigned long oldbit;
-
-	__asm__ __volatile__("
-1:	ldx		[%2], %%g7
-	andcc		%%g7, %1, %0
-	be,pn		%%xcc, 2f
-	 xor		%%g7, %1, %%g5
-	casx 		[%2], %%g7, %%g5
-	cmp		%%g7, %%g5
-	bne,pn		%%xcc, 1b
-	 nop
-2:
-"	: "=&r" (oldbit)
-	: "HIr" (1UL << (nr & 63)), "r" (m)
-	: "g5", "g7", "cc", "memory");
-	return oldbit != 0;
-}
-
-extern __inline__ void clear_bit(unsigned long nr, void *addr)
-{
-	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
-
-	__asm__ __volatile__("
-1:	ldx		[%1], %%g7
-	andcc		%%g7, %0, %%g0
-	be,pn		%%xcc, 2f
-	 xor		%%g7, %0, %%g5
-	casx 		[%1], %%g7, %%g5
-	cmp		%%g7, %%g5
-	bne,pn		%%xcc, 1b
-	 nop
-2:
-"	: /* no outputs */
-	: "HIr" (1UL << (nr & 63)), "r" (m)
-	: "g5", "g7", "cc", "memory");
-}
-
-extern __inline__ int test_and_change_bit(unsigned long nr, void *addr)
-{
-	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
-	unsigned long oldbit;
-
-	__asm__ __volatile__("
-1:	ldx		[%2], %%g7
-	and		%%g7, %1, %0
-	xor		%%g7, %1, %%g5
-	casx 		[%2], %%g7, %%g5
-	cmp		%%g7, %%g5
-	bne,pn		%%xcc, 1b
-	 nop
-"	: "=&r" (oldbit)
-	: "HIr" (1UL << (nr & 63)), "r" (m)
-	: "g5", "g7", "cc", "memory");
-	return oldbit != 0;
-}
-
-extern __inline__ void change_bit(unsigned long nr, void *addr)
-{
-	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
-
-	__asm__ __volatile__("
-1:	ldx		[%1], %%g7
-	xor		%%g7, %0, %%g5
-	casx 		[%1], %%g7, %%g5
-	cmp		%%g7, %%g5
-	bne,pn		%%xcc, 1b
-	 nop
-"	: /* no outputs */
-	: "HIr" (1UL << (nr & 63)), "r" (m)
-	: "g5", "g7", "cc", "memory");
-}
+extern long __test_and_set_bit(unsigned long nr, void *addr);
+extern long __test_and_clear_bit(unsigned long nr, void *addr);
+extern long __test_and_change_bit(unsigned long nr, void *addr);
+
+#define test_and_set_bit(nr,addr)	(__test_and_set_bit(nr,addr)!=0)
+#define test_and_clear_bit(nr,addr)	(__test_and_clear_bit(nr,addr)!=0)
+#define test_and_change_bit(nr,addr)	(__test_and_change_bit(nr,addr)!=0)
+#define set_bit(nr,addr)		((void)__test_and_set_bit(nr,addr))
+#define clear_bit(nr,addr)		((void)__test_and_clear_bit(nr,addr))
+#define change_bit(nr,addr)		((void)__test_and_change_bit(nr,addr))
 
 extern __inline__ int test_bit(int nr, __const__ void *addr)
 {
@@ -280,50 +165,13 @@
 #define find_first_zero_bit(addr, size) \
         find_next_zero_bit((addr), (size), 0)
 
-/* Now for the ext2 filesystem bit operations and helper routines.
- * Note the usage of the little endian ASI's, werd, V9 is supreme.
- */
-extern __inline__ int set_le_bit(int nr,void * addr)
-{
-	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
-	unsigned long oldbit;
-
-	__asm__ __volatile__("
-1:	lduwa		[%2] %3, %%g7
-	andcc		%%g7, %1, %0
-	bne,pn		%%icc, 2f
-	 xor		%%g7, %1, %%g5
-	casa 		[%2] %3, %%g7, %%g5
-	cmp		%%g7, %%g5
-	bne,pn		%%icc, 1b
-	 nop
-2:
-"	: "=&r" (oldbit)
-	: "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
-	: "g5", "g7", "cc", "memory");
-	return oldbit != 0;
-}
-
-extern __inline__ int clear_le_bit(int nr, void * addr)
-{
-	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
-	unsigned long oldbit;
+extern long __test_and_set_le_bit(int nr, void *addr);
+extern long __test_and_clear_le_bit(int nr, void *addr);
 
-	__asm__ __volatile__("
-1:	lduwa		[%2] %3, %%g7
-	andcc		%%g7, %1, %0
-	be,pn		%%icc, 2f
-	 xor		%%g7, %1, %%g5
-	casa 		[%2] %3, %%g7, %%g5
-	cmp		%%g7, %%g5
-	bne,pn		%%icc, 1b
-	 nop
-2:
-"	: "=&r" (oldbit)
-	: "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
-	: "g5", "g7", "cc", "memory");
-	return oldbit != 0;
-}
+#define test_and_set_le_bit(nr,addr)	(__test_and_set_le_bit(nr,addr)!=0)
+#define test_and_clear_le_bit(nr,addr)	(__test_and_clear_le_bit(nr,addr)!=0)
+#define set_le_bit(nr,addr)		((void)__test_and_set_le_bit(nr,addr))
+#define clear_le_bit(nr,addr)		((void)__test_and_clear_le_bit(nr,addr))
 
 extern __inline__ int test_le_bit(int nr, __const__ void * addr)
 {
@@ -375,8 +223,8 @@
 
 #ifdef __KERNEL__
 
-#define ext2_set_bit			set_le_bit
-#define ext2_clear_bit			clear_le_bit
+#define ext2_set_bit			test_and_set_le_bit
+#define ext2_clear_bit			test_and_clear_le_bit
 #define ext2_test_bit  			test_le_bit
 #define ext2_find_first_zero_bit	find_first_zero_le_bit
 #define ext2_find_next_zero_bit		find_next_zero_le_bit
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h
--- v2.3.99-pre3/linux/include/asm-sparc64/io.h	Sat Feb 26 22:32:00 2000
+++ linux/include/asm-sparc64/io.h	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.33 2000/02/25 05:47:38 davem Exp $ */
+/* $Id: io.h,v 1.34 2000/03/30 01:40:54 davem Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
@@ -155,6 +155,68 @@
 #define writeb(__b, __addr)	(_writeb((__b), (unsigned long)(__addr)))
 #define writew(__w, __addr)	(_writew((__w), (unsigned long)(__addr)))
 #define writel(__l, __addr)	(_writel((__l), (unsigned long)(__addr)))
+
+/* Now versions without byte-swapping. */
+extern __inline__ unsigned int _raw_readb(unsigned long addr)
+{
+	unsigned int ret;
+
+	__asm__ __volatile__("lduba\t[%1] %2, %0\t/* pci_raw_readb */"
+			     : "=r" (ret)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+
+	return ret;
+}
+
+extern __inline__ unsigned int _raw_readw(unsigned long addr)
+{
+	unsigned int ret;
+
+	__asm__ __volatile__("lduha\t[%1] %2, %0\t/* pci_raw_readw */"
+			     : "=r" (ret)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+
+	return ret;
+}
+
+extern __inline__ unsigned int _raw_readl(unsigned long addr)
+{
+	unsigned int ret;
+
+	__asm__ __volatile__("lduwa\t[%1] %2, %0\t/* pci_raw_readl */"
+			     : "=r" (ret)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+
+	return ret;
+}
+
+extern __inline__ void _raw_writeb(unsigned char b, unsigned long addr)
+{
+	__asm__ __volatile__("stba\t%r0, [%1] %2\t/* pci_raw_writeb */"
+			     : /* no outputs */
+			     : "Jr" (b), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+extern __inline__ void _raw_writew(unsigned short w, unsigned long addr)
+{
+	__asm__ __volatile__("stha\t%r0, [%1] %2\t/* pci_raw_writew */"
+			     : /* no outputs */
+			     : "Jr" (w), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+extern __inline__ void _raw_writel(unsigned int l, unsigned long addr)
+{
+	__asm__ __volatile__("stwa\t%r0, [%1] %2\t/* pci_raw_writel */"
+			     : /* no outputs */
+			     : "Jr" (l), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+#define __raw_readb(__addr)		(_raw_readb((unsigned long)(__addr)))
+#define __raw_readw(__addr)		(_raw_readw((unsigned long)(__addr)))
+#define __raw_readl(__addr)		(_raw_readl((unsigned long)(__addr)))
+#define __raw_writeb(__b, __addr)	(_raw_writeb((__b), (unsigned long)(__addr)))
+#define __raw_writew(__w, __addr)	(_raw_writew((__w), (unsigned long)(__addr)))
+#define __raw_writel(__l, __addr)	(_raw_writel((__l), (unsigned long)(__addr)))
 
 /* Valid I/O Space regions are anywhere, because each PCI bus supported
  * can live in an arbitrary area of the physical address range.
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h
--- v2.3.99-pre3/linux/include/asm-sparc64/namei.h	Thu Jun 17 01:08:50 1999
+++ linux/include/asm-sparc64/namei.h	Sun Apr  2 15:49:07 2000
@@ -11,53 +11,16 @@
 #define SPARC_BSD_EMUL "usr/gnemul/sunos/"
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
 
-static inline struct dentry *
-__sparc64_lookup_dentry(const char *name, int lookup_flags)
+static inline char * __emul_prefix(void)
 {
-	struct dentry *base;
-	char *emul;
-
 	switch (current->personality) {
 	case PER_BSD:
-		emul = SPARC_BSD_EMUL; break;
+		return SPARC_BSD_EMUL;
 	case PER_SVR4:
-		emul = SPARC_SOL_EMUL; break;
+		return SPARC_SOL_EMUL;
 	default:
 		return NULL;
 	}
-
-	base = lookup_dentry (emul, 
-			      dget (current->fs->root), 
-			      (LOOKUP_FOLLOW | LOOKUP_DIRECTORY));
-			
-	if (IS_ERR (base)) return NULL;
-	
-	base = lookup_dentry (name, base, lookup_flags);
-	
-	if (IS_ERR (base)) return NULL;
-	
-	if (!base->d_inode) {
-		struct dentry *fromroot;
-		
-		fromroot = lookup_dentry (name, dget (current->fs->root), lookup_flags);
-		
-		if (IS_ERR (fromroot)) return base;
-		
-		if (fromroot->d_inode) {
-			dput(base);
-			return fromroot;
-		}
-		
-		dput(fromroot);
-	}
-	
-	return base;
 }
-
-#define __prefix_lookup_dentry(name, lookup_flags)				\
-	if (current->personality) {						\
-		dentry = __sparc64_lookup_dentry (name, lookup_flags);		\
-		if (dentry) return dentry;					\
-	}
 
 #endif /* __SPARC64_NAMEI_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc64/pbm.h linux/include/asm-sparc64/pbm.h
--- v2.3.99-pre3/linux/include/asm-sparc64/pbm.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-sparc64/pbm.h	Mon Mar 27 10:35:56 2000
@@ -1,4 +1,4 @@
-/* $Id: pbm.h,v 1.21 2000/03/10 02:42:17 davem Exp $
+/* $Id: pbm.h,v 1.22 2000/03/25 05:18:30 davem Exp $
  * pbm.h: UltraSparc PCI controller software state.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -142,6 +142,10 @@
 	/* PBM I/O and Memory space resources. */
 	struct resource			io_space;
 	struct resource			mem_space;
+
+	/* State of 66MHz capabilities on this PBM. */
+	int				is_66mhz_capable;
+	int				all_devs_66mhz;
 
 	/* This PBM's streaming buffer. */
 	struct pci_strbuf		stc;
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h
--- v2.3.99-pre3/linux/include/asm-sparc64/pgalloc.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-sparc64/pgalloc.h	Thu Mar 30 16:54:53 2000
@@ -70,27 +70,11 @@
 
 #define flush_cache_all()	smp_flush_cache_all()
 #define flush_tlb_all()		smp_flush_tlb_all()
-
-extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
-{
-	if (CTX_VALID(mm->context))
-		smp_flush_tlb_mm(mm);
-}
-
-extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
-				       unsigned long end)
-{
-	if (CTX_VALID(mm->context))
-		smp_flush_tlb_range(mm, start, end);
-}
-
-extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-	struct mm_struct *mm = vma->vm_mm;
-
-	if (CTX_VALID(mm->context))
-		smp_flush_tlb_page(mm, page);
-}
+#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_page(vma, page) \
+	smp_flush_tlb_page((vma)->vm_mm, page)
 
 #endif /* ! __SMP__ */
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.3.99-pre3/linux/include/asm-sparc64/pgtable.h	Tue Mar  7 14:32:26 2000
+++ linux/include/asm-sparc64/pgtable.h	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.121 2000/03/02 20:37:41 davem Exp $
+/* $Id: pgtable.h,v 1.124 2000/03/27 10:38:56 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -214,26 +214,9 @@
 #define pte_page(x) (mem_map+pte_pagenr(x))
 
 /* Be very careful when you change these three, they are delicate. */
-static __inline__ pte_t pte_mkyoung(pte_t _pte)
-{	if(pte_val(_pte) & _PAGE_READ)
-		return __pte(pte_val(_pte)|(_PAGE_ACCESSED|_PAGE_R));
-	else
-		return __pte(pte_val(_pte)|(_PAGE_ACCESSED));
-}
-
-static __inline__ pte_t pte_mkwrite(pte_t _pte)
-{	if(pte_val(_pte) & _PAGE_MODIFIED)
-		return __pte(pte_val(_pte)|(_PAGE_WRITE|_PAGE_W));
-	else
-		return __pte(pte_val(_pte)|(_PAGE_WRITE));
-}
-
-static __inline__ pte_t pte_mkdirty(pte_t _pte)
-{	if(pte_val(_pte) & _PAGE_WRITE)
-		return __pte(pte_val(_pte)|(_PAGE_MODIFIED|_PAGE_W));
-	else
-		return __pte(pte_val(_pte)|(_PAGE_MODIFIED));
-}
+#define pte_mkyoung(pte)	(__pte(pte_val(pte) | _PAGE_ACCESSED | _PAGE_R))
+#define pte_mkwrite(pte)	(__pte(pte_val(pte) | _PAGE_WRITE))
+#define pte_mkdirty(pte)	(__pte(pte_val(pte) | _PAGE_MODIFIED | _PAGE_W))
 
 /* to find an entry in a page-table-directory. */
 #define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD))
@@ -256,41 +239,7 @@
 #define mmu_lockarea(vaddr, len)		(vaddr)
 #define mmu_unlockarea(vaddr, len)		do { } while(0)
 
-/* There used to be some funny code here which tried to guess which
- * TLB wanted the mapping, that wasn't accurate enough to justify it's
- * existance.  The real way to do that is to have each TLB miss handler
- * pass in a distinct code to do_sparc64_fault() and do it more accurately
- * there.
- *
- * What we do need to handle here is prevent I-cache corruption.  The
- * deal is that the I-cache snoops stores from other CPUs and all DMA
- * activity, however stores from the local processor are not snooped.
- * The dynamic linker and our signal handler mechanism take care of
- * the cases where they write into instruction space, but when a page
- * is copied in the kernel and then executed in user-space is not handled
- * right.  This leads to corruptions if things are "just right", consider
- * the following scenerio:
- * 1) Process 1 frees up a page that was used for the PLT of libc in
- *    it's address space.
- * 2) Process 2 writes into a page in the PLT of libc for the first
- *    time.  do_wp_page() copies the page locally, the local I-cache of
- *    the processor does not notice the writes during the page copy.
- *    The new page used just so happens to be the one just freed in #1.
- * 3) After the PLT write, later the cpu calls into an unresolved PLT
- *    entry, the CPU executes old instructions from process 1's PLT
- *    table.
- * 4) Splat.
- */
-extern void __flush_icache_page(unsigned long phys_page);
-#define update_mmu_cache(__vma, __address, _pte) \
-do { \
-	unsigned short __flags = ((__vma)->vm_flags); \
-	if ((__flags & VM_EXEC) != 0 && \
-	    ((pte_val(_pte) & (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED)) == \
-	     (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED))) { \
-		__flush_icache_page(pte_pagenr(_pte) << PAGE_SHIFT); \
-	} \
-} while(0)
+extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte);
 
 #define flush_icache_page(vma, pg)	do { } while(0)
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- v2.3.99-pre3/linux/include/asm-sparc64/processor.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/processor.h	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.61 2000/01/21 11:39:22 jj Exp $
+/* $Id: processor.h,v 1.63 2000/03/27 10:38:57 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -51,15 +51,16 @@
 	unsigned long ksp __attribute__ ((aligned(16)));
 	unsigned char wstate, cwp, flags;
 	mm_segment_t current_ds;
-	unsigned char w_saved, fpdepth;
+	unsigned char w_saved, fpdepth, fault_code, use_blkcommit;
+	unsigned long fault_address;
 	unsigned char fpsaved[7];
-	unsigned char __pad1[3];
-	struct pt_regs *kregs;
+	unsigned char __pad2;
 	
 	/* D$ line 2, 3, 4 */
+	struct pt_regs *kregs;
 	unsigned long *utraps;
 	unsigned char gsr[7];
-	unsigned char __pad2;
+	unsigned char __pad3;
 	unsigned long xfsr[7];
 
 	struct reg_window reg_window[NSWINS];
@@ -73,11 +74,16 @@
 
 #endif /* !(__ASSEMBLY__) */
 
-#define SPARC_FLAG_UNALIGNED    0x01    /* is allowed to do unaligned accesses */
-#define SPARC_FLAG_NEWSIGNALS   0x02    /* task wants new-style signals */
-#define SPARC_FLAG_32BIT        0x04    /* task is older 32-bit binary */
-#define SPARC_FLAG_NEWCHILD     0x08    /* task is just-spawned child process */
-#define SPARC_FLAG_PERFCTR	0x10    /* task has performance counters active */
+#define SPARC_FLAG_UNALIGNED    0x01    /* is allowed to do unaligned accesses	*/
+#define SPARC_FLAG_NEWSIGNALS   0x02    /* task wants new-style signals		*/
+#define SPARC_FLAG_32BIT        0x04    /* task is older 32-bit binary		*/
+#define SPARC_FLAG_NEWCHILD     0x08    /* task is just-spawned child process	*/
+#define SPARC_FLAG_PERFCTR	0x10    /* task has performance counters active	*/
+
+#define FAULT_CODE_WRITE	0x01	/* Write access, implies D-TLB		*/
+#define FAULT_CODE_DTLB		0x02	/* Miss happened in D-TLB		*/
+#define FAULT_CODE_ITLB		0x04	/* Miss happened in I-TLB		*/
+#define FAULT_CODE_WINFIXUP	0x08	/* Miss happened during spill/fill	*/
 
 #define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \
 		    NULL, PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
@@ -85,10 +91,12 @@
 #define INIT_THREAD  {					\
 /* ksp, wstate, cwp, flags, current_ds, */ 		\
    0,   0,      0,   0,     KERNEL_DS,			\
-/* w_saved, fpdepth, fpsaved, pad1,  kregs, */		\
-   0,       0,       { 0 },   { 0 }, 0,			\
-/* utraps, gsr,   pad2, xfsr, */			\
-   0,	   { 0 }, 0,    { 0 },				\
+/* w_saved, fpdepth, fault_code, use_blkcommit, */	\
+   0,       0,       0,          0,			\
+/* fault_address, fpsaved, __pad2, kregs, */		\
+   0,             { 0 },   0,      0,			\
+/* utraps, gsr,   __pad3, xfsr, */			\
+   0,	   { 0 }, 0,      { 0 },			\
 /* reg_window */					\
    { { { 0, }, { 0, } }, }, 				\
 /* rwbuf_stkptrs */					\
diff -u --recursive --new-file v2.3.99-pre3/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.3.99-pre3/linux/include/asm-sparc64/system.h	Tue Mar  7 14:32:26 2000
+++ linux/include/asm-sparc64/system.h	Thu Mar 30 16:54:53 2000
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.56 2000/03/06 22:33:45 davem Exp $ */
+/* $Id: system.h,v 1.57 2000/03/27 10:38:57 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -131,16 +131,8 @@
 
 extern void synchronize_user_stack(void);
 
-extern __inline__ void flushw_user(void)
-{
-	__asm__ __volatile__("
-		rdpr		%%otherwin, %%g1
-		brz,pt		%%g1, 1f
-		 mov		%%o7, %%g3
-		call		__flushw_user
-		 clr		%%g2
-1:"	: : : "g1", "g2", "g3");
-}
+extern void __flushw_user(void);
+#define flushw_user() __flushw_user()
 
 #define flush_user_windows flushw_user
 #define flush_register_windows flushw_all
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.3.99-pre3/linux/include/linux/blk.h	Tue Mar 14 19:10:40 2000
+++ linux/include/linux/blk.h	Mon Apr 10 23:24:49 2000
@@ -54,6 +54,11 @@
 extern int bpcd_init(void);
 extern int ps2esdi_init(void);
 
+#if defined(CONFIG_ARCH_S390)
+extern int mdisk_init(void);
+extern int dasd_init(void);
+#endif /* CONFIG_ARCH_S390 */
+
 extern void set_device_ro(kdev_t dev,int flag);
 void add_blkdev_randomness(int major);
 
@@ -349,6 +354,23 @@
 #define DEVICE_NAME "nbd"
 #define DEVICE_REQUEST do_nbd_request
 #define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device) 
+#define DEVICE_OFF(device)
+
+
+#elif (MAJOR_NR == MDISK_MAJOR)
+
+#define DEVICE_NAME "mdisk"
+#define DEVICE_REQUEST mdisk_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device) 
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == DASD_MAJOR)
+
+#define DEVICE_NAME "dasd"
+#define DEVICE_REQUEST do_dasd_request
+#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
 #define DEVICE_ON(device) 
 #define DEVICE_OFF(device)
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/blkdev.h linux/include/linux/blkdev.h
--- v2.3.99-pre3/linux/include/linux/blkdev.h	Tue Mar 14 19:10:40 2000
+++ linux/include/linux/blkdev.h	Mon Apr 10 23:23:51 2000
@@ -32,6 +32,7 @@
 	int errors;
 	unsigned long sector;
 	unsigned long nr_sectors;
+	unsigned long hard_sector, hard_nr_sectors;
 	unsigned int nr_segments;
 	unsigned int nr_hw_segments;
 	unsigned long current_nr_sectors;
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/bootmem.h linux/include/linux/bootmem.h
--- v2.3.99-pre3/linux/include/linux/bootmem.h	Thu Feb 10 17:11:21 2000
+++ linux/include/linux/bootmem.h	Mon Apr 10 23:24:17 2000
@@ -14,6 +14,7 @@
  */
 
 extern unsigned long max_low_pfn;
+extern unsigned long min_low_pfn;
 
 /*
  * node_bootmem_map is a map pointer - the bits represent all physical 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/cycx_x25.h linux/include/linux/cycx_x25.h
--- v2.3.99-pre3/linux/include/linux/cycx_x25.h	Tue Jan 11 22:31:44 2000
+++ linux/include/linux/cycx_x25.h	Mon Apr  3 19:32:57 2000
@@ -12,6 +12,7 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* 2000/04/02	acme		dprintk and cycx_debug
 * 1999/01/03	acme		judicious use of data types
 * 1999/01/02	acme		#define X25_ACK_N3	0x4411
 * 1998/12/28	acme		cleanup: lot'o'things removed
@@ -29,6 +30,11 @@
 /* X.25 shared memory layout. */
 #define	X25_MBOX_OFFS	0x300	/* general mailbox block */
 #define	X25_RXMBOX_OFFS	0x340	/* receive mailbox */
+
+/* Debug */
+#define dprintk(level, format, a...) if (cycx_debug >= level) printk(format, ##a)
+
+extern unsigned int cycx_debug;
 
 /* Data Structures */
 /* X.25 Command Block. */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.3.99-pre3/linux/include/linux/dcache.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/dcache.h	Mon Apr 10 23:23:18 2000
@@ -1,6 +1,9 @@
 #ifndef __LINUX_DCACHE_H
 #define __LINUX_DCACHE_H
 
+#include <asm/atomic.h>
+#include <linux/mount.h>
+
 #ifdef __KERNEL__
 
 /*
@@ -105,7 +108,10 @@
 					 * s_nfsd_free_path semaphore will be down
 					 */
 
-/*
+/**
+ * d_drop - drop a dentry
+ * @dentry: dentry to drop
+ *
  * d_drop() unhashes the entry from the parent
  * dentry hashes, so that it won't be found through
  * a VFS lookup any more. Note that this is different
@@ -118,6 +124,7 @@
  * to invalidate a dentry for some reason (NFS
  * timeouts or autofs deletes).
  */
+
 static __inline__ void d_drop(struct dentry * dentry)
 {
 	list_del(&dentry->d_hash);
@@ -164,10 +171,16 @@
  * This adds the entry to the hash queues.
  */
 extern void d_rehash(struct dentry *);
-/*
+
+/**
+ * d_add - add dentry to hash queues
+ * @entry: dentry to add
+ * @inode: The inode to attach to this dentry
+ *
  * This adds the entry to the hash queues and initializes "d_inode".
  * The entry was actually filled in earlier during "d_alloc()"
  */
+ 
 static __inline__ void d_add(struct dentry * entry, struct inode * inode)
 {
 	d_rehash(entry);
@@ -183,10 +196,24 @@
 /* validate "insecure" dentry pointer */
 extern int d_validate(struct dentry *, struct dentry *, unsigned int, unsigned int);
 
+extern char * __d_path(struct dentry *, struct vfsmount *, struct dentry *,
+	struct vfsmount *, char *, int);
 /* write full pathname into buffer and return start of pathname */
-extern char * d_path(struct dentry *, char *, int);
-
+#define d_path(dentry, vfsmnt, buffer, buflen) \
+	__d_path(dentry, vfsmnt, current->fs->root, current->fs->rootmnt, \
+	buffer, buflen)
+  
 /* Allocation counts.. */
+
+/**
+ *	dget	-	get a reference to a dentry
+ *	@dentry: dentry to get a reference too
+ *
+ *	Given a dentry or NULL pointer increment the reference count
+ *	if appropriate and return the dentry. A dentry will not be 
+ *	destroyed when it has references.
+ */
+ 
 static __inline__ struct dentry * dget(struct dentry *dentry)
 {
 	if (dentry)
@@ -194,12 +221,26 @@
 	return dentry;
 }
 
+/**
+ *	d_unhashed -	is dentry hashed
+ *	@dentry: entry to check
+ *
+ *	Returns true if the dentry passed is not currently hashed
+ */
+ 
 static __inline__ int d_unhashed(struct dentry *dentry)
 {
 	return list_empty(&dentry->d_hash);
 }
 
 extern void dput(struct dentry *);
+
+/* MOUNT_REWRITE: replace with the check for d_vfsmnt */
+static __inline__ int d_mountpoint(struct dentry *dentry)
+{
+	return dentry != dentry->d_mounts;
+}
+
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/errno.h linux/include/linux/errno.h
--- v2.3.99-pre3/linux/include/linux/errno.h	Thu Jun 12 15:28:32 1997
+++ linux/include/linux/errno.h	Tue Mar 28 17:51:39 2000
@@ -11,6 +11,16 @@
 #define ERESTARTNOHAND	514	/* restart if no handler.. */
 #define ENOIOCTLCMD	515	/* No ioctl command */
 
+/* Defined for the NFSv3 protocol */
+#define EBADHANDLE	521	/* Illegal NFS file handle */
+#define ENOTSYNC	522	/* Update synchronization mismatch */
+#define EBADCOOKIE	523	/* Cookie is stale */
+#define ENOTSUPP	524	/* Operation is not supported */
+#define ETOOSMALL	525	/* Buffer or request is too small */
+#define ESERVERFAULT	526	/* An untranslatable error occurred */
+#define EBADTYPE	527	/* Type not supported by server */
+#define EJUKEBOX	528	/* Request initiated, but will not complete before timeout */
+
 #endif
 
 #endif
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.99-pre3/linux/include/linux/fs.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/fs.h	Mon Apr 10 23:23:20 2000
@@ -79,7 +79,6 @@
 #define FS_NO_PRELIM	4 /* prevent preloading of dentries, even if
 			   * FS_NO_DCACHE is not set.
 			   */
-#define FS_IBASKET	8 /* FS does callback to free_ibasket() if space gets low. */
 
 /*
  * These are the fs-independent mount-flags: up to 16 flags are supported
@@ -456,6 +455,7 @@
 struct file {
 	struct list_head	f_list;
 	struct dentry		*f_dentry;
+	struct vfsmount         *f_vfsmnt;
 	struct file_operations	*f_op;
 	atomic_t		f_count;
 	unsigned int 		f_flags;
@@ -507,16 +507,24 @@
 	struct file *fl_file;
 	unsigned char fl_flags;
 	unsigned char fl_type;
-	off_t fl_start;
-	off_t fl_end;
+	loff_t fl_start;
+	loff_t fl_end;
 
 	void (*fl_notify)(struct file_lock *);	/* unblock callback */
+	void (*fl_insert)(struct file_lock *);	/* lock insertion callback */
+	void (*fl_remove)(struct file_lock *);	/* lock removal callback */
 
 	union {
 		struct nfs_lock_info	nfs_fl;
 	} fl_u;
 };
 
+/* The following constant reflects the upper bound of the file/locking space */
+#ifndef OFFSET_MAX
+#define INT_LIMIT(x)	(~((x)1 << (sizeof(x)*8 - 1)))
+#define OFFSET_MAX	INT_LIMIT(loff_t)
+#endif
+
 extern struct file_lock			*file_lock_table;
 
 #include <linux/fcntl.h>
@@ -539,10 +547,36 @@
 	struct	file 		*fa_file;
 };
 
+struct nameidata {
+	struct dentry *dentry;
+	struct vfsmount *mnt;
+	struct qstr last;
+};
+
 #define FASYNC_MAGIC 0x4601
 
 extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
 
+#define DQUOT_USR_ENABLED	0x01		/* User diskquotas enabled */
+#define DQUOT_GRP_ENABLED	0x02		/* Group diskquotas enabled */
+
+struct quota_mount_options
+{
+	unsigned int flags;			/* Flags for diskquotas on this device */
+	struct semaphore dqio_sem;		/* lock device while I/O in progress */
+	struct semaphore dqoff_sem;		/* serialize quota_off() and quota_on() on device */
+	struct file *files[MAXQUOTAS];		/* fp's to quotafiles */
+	time_t inode_expire[MAXQUOTAS];		/* expiretime for inode-quota */
+	time_t block_expire[MAXQUOTAS];		/* expiretime for block-quota */
+	char rsquash[MAXQUOTAS];		/* for quotas threat root as any other user */
+};
+
+/*
+ *	Umount options
+ */
+
+#define MNT_FORCE	0x00000001	/* Attempt to forcibily umount */
+
 #include <linux/minix_fs_sb.h>
 #include <linux/ext2_fs_sb.h>
 #include <linux/hpfs_fs_sb.h>
@@ -582,9 +616,6 @@
 	struct dentry		*s_root;
 	wait_queue_head_t	s_wait;
 
-	struct inode		*s_ibasket;
-	short int		s_ibasket_count;
-	short int		s_ibasket_max;
 	struct list_head	s_dirty;	/* dirty inodes */
 	struct list_head	s_files;
 
@@ -688,7 +719,7 @@
 	int (*rename) (struct inode *, struct dentry *,
 			struct inode *, struct dentry *);
 	int (*readlink) (struct dentry *, char *,int);
-	struct dentry * (*follow_link) (struct dentry *, struct dentry *, unsigned int);
+	int (*follow_link) (struct dentry *, struct nameidata *);
 	void (*truncate) (struct inode *);
 	int (*permission) (struct inode *, int);
 	int (*revalidate) (struct dentry *);
@@ -812,10 +843,9 @@
 extern int get_unused_fd(void);
 extern void put_unused_fd(unsigned int);
 
-extern struct file *filp_open(const char *, int, int, struct dentry *);
-extern struct file *dentry_open(struct dentry *, int);
+extern struct file *filp_open(const char *, int, int);
+extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
 extern int filp_close(struct file *, fl_owner_t id);
-
 extern char * getname(const char *);
 #define __getname()	((char *) __get_free_page(GFP_KERNEL))
 #define putname(name)	free_page((unsigned long)(name))
@@ -930,13 +960,8 @@
 extern void put_write_access(struct inode *);
 extern struct dentry * do_mknod(const char *, int, dev_t);
 extern int do_pipe(int *);
-extern int do_unlink(const char * name, struct dentry *);
-extern struct dentry * __open_namei(const char *, int, int, struct dentry *);
 
-static inline struct dentry * open_namei(const char *pathname)
-{
-	return __open_namei(pathname, 0, 0, NULL);
-}
+extern int open_namei(const char *, int, int, struct nameidata *);
 
 extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
 extern struct file * open_exec(const char *);
@@ -968,6 +993,8 @@
 #define LOOKUP_DIRECTORY	(2)
 #define LOOKUP_SLASHOK		(4)
 #define LOOKUP_CONTINUE		(8)
+#define LOOKUP_POSITIVE		(16)
+#define LOOKUP_PARENT		(32)
 
 /*
  * "descriptor" for what we're up to with a read for sendfile().
@@ -987,12 +1014,13 @@
 
 typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);
 
-
-extern struct dentry * lookup_dentry(const char *, struct dentry *, unsigned int);
+extern struct dentry * lookup_dentry(const char *, unsigned int);
+extern int walk_init(const char *, unsigned, struct nameidata *);
+extern int walk_name(const char *, unsigned, struct nameidata *);
 extern struct dentry * lookup_one(const char *, struct dentry *);
 extern struct dentry * __namei(const char *, unsigned int);
 
-#define namei(pathname)		__namei(pathname, 1)
+#define namei(pathname)		__namei(pathname, LOOKUP_FOLLOW)
 #define lnamei(pathname)	__namei(pathname, 0)
 
 extern void iput(struct inode *);
@@ -1062,9 +1090,9 @@
 extern struct file_operations generic_ro_fops;
 
 extern int vfs_readlink(struct dentry *, char *, int, const char *);
-extern struct dentry *vfs_follow_link(struct dentry *, struct dentry *, unsigned, const char *);
+extern int vfs_follow_link(struct nameidata *, const char *);
 extern int page_readlink(struct dentry *, char *, int);
-extern struct dentry *page_follow_link(struct dentry *, struct dentry *, unsigned);
+extern int page_follow_link(struct dentry *, struct nameidata *);
 extern struct inode_operations page_symlink_inode_operations;
 
 extern int vfs_readdir(struct file *, filldir_t, void *);
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/ibmtr.h linux/include/linux/ibmtr.h
--- v2.3.99-pre3/linux/include/linux/ibmtr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/ibmtr.h	Sun Apr  2 15:38:54 2000
@@ -0,0 +1,454 @@
+/* Definitions for an IBM Token Ring card. */
+/* This file is distributed under the GNU GPL   */
+
+/* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */
+
+#define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */
+#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */
+#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */
+#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */
+#define TR_RETRIES 6            /* number of open retries */ 
+
+#define TR_ISA 1
+#define TR_MCA 2
+#define TR_ISAPNP 3
+#define NOTOK 0
+#define TOKDEBUG 1
+
+#define IBMTR_SHARED_RAM_SIZE 0x10000
+#define IBMTR_IO_EXTENT 4
+#define IBMTR_MAX_ADAPTERS 2
+
+#define CHANNEL_ID      0X1F30
+#define AIP             0X1F00
+#define AIPCHKSUM1      0X1F60
+#define AIPCHKSUM2      0X1FF0
+#define AIPADAPTYPE     0X1FA0
+#define AIPDATARATE     0X1FA2
+#define AIPEARLYTOKEN   0X1FA4
+#define AIPAVAILSHRAM   0X1FA6
+#define AIPSHRAMPAGE    0X1FA8
+#define AIP4MBDHB       0X1FAA
+#define AIP16MBDHB      0X1FAC
+#define AIPFID		0X1FBA
+
+/* Note, 0xA20 == 0x220 since motherboard decodes 10 bits.  I left everything
+   the way my documentation had it, ie: 0x0A20.     */
+#define ADAPTINTCNTRL   0x02f0  /* Adapter interrupt control */
+#define ADAPTRESET      0x1     /* Control Adapter reset (add to base) */
+#define ADAPTRESETREL   0x2     /* Release Adapter from reset ( """)  */
+#define ADAPTINTREL	0x3 	/* Adapter interrupt release */
+
+#define MMIOStartLocP   0x0a20  /* Primary adapter's starting MMIO area */
+#define MMIOStartLocA   0x0a24  /* Alternate adapter's starting MMIO area */
+
+#define GLOBAL_INT_ENABLE 0x02f0
+
+/* MMIO bits 0-4 select register */
+#define RRR_EVEN        0x00    /* Shared RAM relocation registers - even and odd */
+/* Used to set the starting address of shared RAM  */
+/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared RAM address.*/
+/* ie: 0x02 sets RAM address to ...ato!  issy su wazzoo !! GODZILLA!!! */
+#define RRR_ODD         0x01
+/* Bits 2 and 3 of this register can be read to determine shared RAM size */
+/* 00 for 8k, 01 for 16k, 10 for 32k, 11 for 64k  */
+#define WRBR_EVEN       0x02    /* Write region base registers - even and odd */
+#define WRBR_ODD        0x03
+#define WWOR_EVEN       0x04    /* Write window open registers - even and odd */
+#define WWOR_ODD        0x05
+#define WWCR_EVEN       0x06    /* Write window close registers - even and odd */
+#define WWCR_ODD        0x07
+
+/* Interrupt status registers - PC system  - even and odd */
+#define ISRP_EVEN       0x08
+
+#define TCR_INT 0x10    /* Bit 4 - Timer interrupt.  The TVR_EVEN timer has
+                                                                   expired. */
+#define ERR_INT 0x08    /* Bit 3 - Error interrupt.  The adapter has had an
+                                                                   internal error. */
+#define ACCESS_INT 0x04    /* Bit 2 - Access interrupt.  You have attempted to
+                                                           write to an invalid area of shared RAM or an invalid
+                                                                   register within the MMIO. */
+/*      In addition, the following bits within ISRP_EVEN can be turned on or off by you */
+/*      to control the interrupt processing:   */
+#define INT_IRQ 0x80    /* Bit 7 - If 0 the adapter will issue a CHCK, if 1 and
+                                                              IRQ.  This should normally be set (by you) to 1.  */
+#define INT_ENABLE 0x40 /* Bit 6 - Interrupt enable.  If 0, no interrupts will
+                                                                   occur.  If 1, interrupts will occur normally.
+                                                                   Normally set to 1.  */
+/* Bit 0 - Primary or alternate adapter.  Set to zero if this adapter is the primary adapter,*/
+/*         1 if this adapter is the alternate adapter. */
+
+
+#define ISRP_ODD        0x09
+
+#define ADAP_CHK_INT 0x40 /* Bit 6 - Adapter check.  the adapter has
+                             encountered a serious problem and has closed
+                             itself.  Whoa.  */
+#define SRB_RESP_INT 0x20 /* Bit 5 - SRB response.  The adapter has accepted
+                             an SRB request and set the return code within
+                             the SRB. */
+#define ASB_FREE_INT 0x10 /* Bit 4 - ASB free.  The adapter has read the ASB
+                                                                          and this area can be safely reused. This interrupt
+                                                                          is only used if your application has set the ASB
+                                                                          free request bit in ISRA_ODD or if an error was
+                                                                detected in your response. */
+#define ARB_CMD_INT  0x08 /* Bit 3 - ARB command.  The adapter has given you a
+                                                                          command for action.  The command is located in the
+                                                                          ARB area of shared memory. */
+#define SSB_RESP_INT 0x04 /* Bit 2 - SSB response.  The adapter has posted a
+                                                                          response to your SRB (the response is located in
+                                                                          the SSB area of shared memory). */
+/* Bit 1 - Bridge frame forward complete. */
+
+
+
+#define ISRA_EVEN       0x0A    /* Interrupt status registers - adapter  - even and odd */
+/* Bit 7 - Internal parity error (on adapter's internal bus) */
+/* Bit 6 - Timer interrupt pending */
+/* Bit 5 - Access interrupt (attempt by adapter to access illegal address) */
+/* Bit 4 - Adapter microcode problem (microcode dead-man timer expired) */
+/* Bit 3 - Adapter processor check status */
+/* Bit 2 - Reserved */
+/* Bit 1 - Adapter hardware interrupt mask (prevents internal interrupts) */
+/* Bit 0 - Adapter software interrupt mask (prevents internal software interrupts) */
+
+#define ISRA_ODD        0x0B
+#define CMD_IN_SRB 0x20 /* Bit 5  - Indicates that you have placed a new
+                           command in the SRB and are ready for the adapter to
+                           process the command. */
+#define RESP_IN_ASB 0x10 /* Bit 4 - Indicates that you have placed a response
+                                                                    (an ASB) in the shared RAM which is available for
+                                                                         the adapter's use. */
+/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but that a previous */
+/*         command is still pending.  The adapter will then interrupt you when the previous */
+/*         command is completed */
+/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but that a previous */
+/*         ASB is still pending.  The adapter will then interrupt you when the previous ASB */
+/*         is copied.  */
+#define ARB_FREE 0x2
+#define SSB_FREE 0x1
+
+#define TCR_EVEN        0x0C    /* Timer control registers - even and odd */
+#define TCR_ODD         0x0D
+#define TVR_EVEN        0x0E    /* Timer value registers - even and odd */
+#define TVR_ODD         0x0F
+#define SRPR_EVEN       0x18    /* Shared RAM paging registers - even and odd */
+#define SRPR_ENABLE_PAGING 0xc0
+#define SRPR_ODD        0x19 /* Not used. */
+#define TOKREAD         0x60
+#define TOKOR           0x40
+#define TOKAND          0x20
+#define TOKWRITE        0x00
+
+/* MMIO bits 5-6 select operation */
+/* 00 is used to write to a register */
+/* 01 is used to bitwise AND a byte with a register */
+/* 10 is used to bitwise OR a byte with a register  */
+/* 11 is used to read from a register */
+
+/* MMIO bits 7-8 select area of interest.. see below */
+/* 00 selects attachment control area. */
+/* 01 is reserved. */
+/* 10 selects adapter identification area A containing the adapter encoded address. */
+/* 11 selects the adapter identification area B containing test patterns. */
+
+#define PCCHANNELID 5049434F3631313039393020
+#define MCCHANNELID 4D4152533633583435313820
+
+#define ACA_OFFSET 0x1e00
+#define ACA_SET 0x40
+#define ACA_RESET 0x20
+#define ACA_RW 0x00
+
+#ifdef ENABLE_PAGING
+#define SET_PAGE(x) (isa_writeb((x), \
+  ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN))
+#else
+#define SET_PAGE(x)
+#endif
+
+typedef enum { IN_PROGRESS, SUCCESS, FAILURE, CLOSED } open_state;
+
+/* do_tok_int possible values */
+#define FIRST_INT 1
+#define NOT_FIRST 2
+
+struct tok_info {
+	unsigned char irq;
+	__u32 mmio;
+	unsigned char hw_address[32];
+	unsigned char adapter_type;
+	unsigned char data_rate;
+	unsigned char token_release;
+	unsigned char avail_shared_ram;
+	unsigned char shared_ram_paging;
+	unsigned short dhb_size4mb;
+	unsigned short rbuf_len4;
+	unsigned short rbuf_cnt4;
+	unsigned short maxmtu4;
+	unsigned short dhb_size16mb;
+	unsigned short rbuf_len16;
+	unsigned short rbuf_cnt16;
+	unsigned short maxmtu16;
+	/* Additions by David Morris       */
+	unsigned char do_tok_int;
+	wait_queue_head_t wait_for_tok_int;
+	wait_queue_head_t wait_for_reset;
+	unsigned char sram_base;
+	/* Additions by Peter De Schrijver */
+	unsigned char page_mask;          /* mask to select RAM page to Map*/
+	unsigned char mapped_ram_size;    /* size of RAM page */
+	__u32 sram;                       /* Shared memory base address */
+	__u32 init_srb;                   /* Initial System Request Block address */
+	__u32 srb;                        /* System Request Block address */
+	__u32 ssb;                        /* System Status Block address */
+	__u32 arb;                        /* Adapter Request Block address */
+	__u32 asb;                        /* Adapter Status Block address */
+        __u8  init_srb_page;
+        __u8  srb_page;
+        __u8  ssb_page;
+        __u8  arb_page;
+        __u8  asb_page;
+	unsigned short exsap_station_id;
+	unsigned short global_int_enable;
+	struct sk_buff *current_skb;
+	struct net_device_stats tr_stats;
+	unsigned char auto_ringspeedsave;
+	open_state open_status;
+	unsigned char readlog_pending;
+	unsigned short adapter_int_enable; /* Adapter-specific int enable */
+        struct timer_list tr_timer;
+	unsigned char ring_speed;
+	__u32 func_addr;
+	unsigned int retry_count;
+	spinlock_t lock;		/* SMP protection */
+};
+
+/* token ring adapter commands */
+#define DIR_INTERRUPT 		0x00 /* struct srb_interrupt */
+#define DIR_MOD_OPEN_PARAMS 	0x01
+#define DIR_OPEN_ADAPTER 	0x03 /* struct dir_open_adapter */
+#define DIR_CLOSE_ADAPTER   	0x04
+#define DIR_SET_GRP_ADDR    	0x06
+#define DIR_SET_FUNC_ADDR   	0x07 /* struct srb_set_funct_addr */
+#define DIR_READ_LOG 		0x08 /* struct srb_read_log */
+#define DLC_OPEN_SAP 		0x15 /* struct dlc_open_sap */
+#define DLC_CLOSE_SAP       	0x16
+#define DATA_LOST 		0x20 /* struct asb_rec */
+#define REC_DATA 		0x81 /* struct arb_rec_req */
+#define XMIT_DATA_REQ 		0x82 /* struct arb_xmit_req */
+#define DLC_STATUS 		0x83 /* struct arb_dlc_status */
+#define RING_STAT_CHANGE    	0x84 /* struct dlc_open_sap ??? */
+
+/* DIR_OPEN_ADAPTER options */
+#define OPEN_PASS_BCON_MAC 0x0100
+#define NUM_RCV_BUF 2
+#define RCV_BUF_LEN 1024
+#define DHB_LENGTH 2048
+#define NUM_DHB 2
+#define DLC_MAX_SAP 2
+#define DLC_MAX_STA 1
+
+/* DLC_OPEN_SAP options */
+#define MAX_I_FIELD 0x0088
+#define SAP_OPEN_IND_SAP 0x04
+#define SAP_OPEN_PRIORITY 0x20
+#define SAP_OPEN_STATION_CNT 0x1
+#define XMIT_DIR_FRAME 0x0A
+#define XMIT_UI_FRAME  0x0d
+#define XMIT_XID_CMD   0x0e
+#define XMIT_TEST_CMD  0x11
+
+/* srb close return code */
+#define SIGNAL_LOSS  0x8000
+#define HARD_ERROR   0x4000
+#define XMIT_BEACON  0x1000
+#define LOBE_FAULT   0x0800
+#define AUTO_REMOVAL 0x0400
+#define REMOVE_RECV  0x0100
+#define LOG_OVERFLOW 0x0080
+#define RING_RECOVER 0x0020
+
+struct srb_init_response {
+	unsigned char command;
+	unsigned char init_status;
+	unsigned char init_status_2;
+	unsigned char reserved[3];
+	__u16 bring_up_code;
+	__u16 encoded_address;
+	__u16 level_address;
+	__u16 adapter_address;
+	__u16 parms_address;
+	__u16 mac_address;
+};
+
+struct dir_open_adapter {
+	unsigned char command;
+	char reserved[7];
+	__u16 open_options;
+	unsigned char node_address[6];
+	unsigned char group_address[4];
+	unsigned char funct_address[4];
+	__u16 num_rcv_buf;
+	__u16 rcv_buf_len;
+	__u16 dhb_length;
+	unsigned char num_dhb;
+	char reserved2;
+	unsigned char dlc_max_sap;
+	unsigned char dlc_max_sta;
+	unsigned char dlc_max_gsap;
+	unsigned char dlc_max_gmem;
+	unsigned char dlc_t1_tick_1;
+	unsigned char dlc_t2_tick_1;
+	unsigned char dlc_ti_tick_1;
+	unsigned char dlc_t1_tick_2;
+	unsigned char dlc_t2_tick_2;
+	unsigned char dlc_ti_tick_2;
+	unsigned char product_id[18];
+};
+
+struct srb_open_response {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+	unsigned char reserved2[3];
+	__u16 error_code;
+	__u16 asb_addr;
+	__u16 srb_addr;
+	__u16 arb_addr;
+	__u16 ssb_addr;
+};
+
+struct dlc_open_sap {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+	unsigned char reserved2;
+	__u16 station_id;
+	unsigned char timer_t1;
+	unsigned char timer_t2;
+	unsigned char timer_ti;
+	unsigned char maxout;
+	unsigned char maxin;
+	unsigned char maxout_incr;
+	unsigned char max_retry_count;
+	unsigned char gsap_max_mem;
+	__u16 max_i_field;
+	unsigned char sap_value;
+	unsigned char sap_options;
+	unsigned char station_count;
+	unsigned char sap_gsap_mem;
+	unsigned char gsap[0];
+};
+
+struct srb_xmit {
+	unsigned char command;
+	unsigned char cmd_corr;
+	unsigned char ret_code;
+	unsigned char reserved1;
+	__u16 station_id;
+};
+
+struct srb_interrupt {
+	unsigned char command;
+	unsigned char cmd_corr;
+	unsigned char ret_code;
+};
+
+struct srb_read_log {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+	unsigned char reserved2;
+	unsigned char line_errors;
+	unsigned char internal_errors;
+	unsigned char burst_errors;
+	unsigned char A_C_errors;
+	unsigned char abort_delimiters;
+	unsigned char reserved3;
+	unsigned char lost_frames;
+	unsigned char recv_congest_count;
+	unsigned char frame_copied_errors;
+	unsigned char frequency_errors;
+	unsigned char token_errors;
+};
+
+struct asb_xmit_resp {
+	unsigned char command;
+	unsigned char cmd_corr;
+	unsigned char ret_code;
+	unsigned char reserved;
+	__u16 station_id;
+	__u16 frame_length;
+	unsigned char hdr_length;
+	unsigned char rsap_value;
+};
+
+struct arb_xmit_req {
+	unsigned char command;
+	unsigned char cmd_corr;
+	unsigned char reserved1[2];
+	__u16 station_id;
+	__u16 dhb_address;
+};
+
+struct arb_rec_req {
+	unsigned char command;
+	unsigned char reserved1[3];
+	__u16 station_id;
+	__u16 rec_buf_addr;
+	unsigned char lan_hdr_len;
+	unsigned char dlc_hdr_len;
+	__u16 frame_len;
+	unsigned char msg_type;
+};
+
+struct asb_rec {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+	unsigned char reserved2;
+	__u16 station_id;
+	__u16 rec_buf_addr;
+};
+
+struct rec_buf {
+  /*	unsigned char reserved1[2]; */
+	__u16 buf_ptr;
+	unsigned char reserved2;
+	__u16 buf_len;
+	unsigned char data[0];
+};
+
+struct arb_dlc_status {
+	unsigned char command;
+	unsigned char reserved1[3];
+	__u16 station_id;
+	__u16 status;
+	unsigned char frmr_data[5];
+	unsigned char access_prio;
+	unsigned char rem_addr[TR_ALEN];
+	unsigned char rsap_value;
+};
+
+struct arb_ring_stat_change {
+	unsigned char command;
+	unsigned char reserved1[5];
+	__u16 ring_status;
+};
+
+struct srb_close_adapter {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+};
+
+struct srb_set_funct_addr {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+	unsigned char reserved2[3];
+	unsigned char funct_address[4];
+};
+
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/if_ppp.h linux/include/linux/if_ppp.h
--- v2.3.99-pre3/linux/include/linux/if_ppp.h	Tue Mar 14 19:10:40 2000
+++ linux/include/linux/if_ppp.h	Mon Mar 27 10:28:55 2000
@@ -21,7 +21,7 @@
  */
 
 /*
- *  ==FILEVERSION 20000115==
+ *  ==FILEVERSION 20000324==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the above date.
@@ -140,6 +140,7 @@
 #define PPPIOCCONNECT	_IOW('t', 58, int)	/* connect channel to unit */
 #define PPPIOCDISCONN	_IO('t', 57)		/* disconnect channel */
 #define PPPIOCATTCHAN	_IOW('t', 56, int)	/* attach to ppp channel */
+#define PPPIOCGCHAN	_IOR('t', 55, int)	/* get ppp channel number */
 
 #define SIOCGPPPSTATS   (SIOCDEVPRIVATE + 0)
 #define SIOCGPPPVER     (SIOCDEVPRIVATE + 1)	/* NEVER change this!! */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/input.h linux/include/linux/input.h
--- v2.3.99-pre3/linux/include/linux/input.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/input.h	Mon Apr 10 22:53:15 2000
@@ -47,6 +47,35 @@
 };
 
 /*
+ * The device ID structure;
+ */
+
+struct input_id {
+	__u16 bus;
+	__u16 vendor;
+	__u16 product;
+};
+
+/*
+ * Protocol version.
+ */
+
+#define EV_VERSION		0x010000
+
+/*
+ * IOCTLs (0x00 - 0x7f)
+ */
+
+#define EVIOCGVERSION		_IOR('E', 0x01, __u32)                  /* get driver version */
+#define EVIOCGID		_IOR('E', 0x02, struct input_id)	/* get device ID */
+#define EVIOCGREP		_IOR('E', 0x03, int[2])			/* get repeat settings */
+#define EVIOCSREP		_IOW('E', 0x03, int[2])			/* get repeat settings */
+#define EVIOCGNAME(len)		_IOC(_IOC_READ, 'E', 0x03, len)		/* get device name */
+#define EVIOCGBIT(ev,len)	_IOC(_IOC_READ, 'E', 0x20 + ev, len)	/* get event bits */
+#define EVIOCGABSLIM(num)	_IOR('E', 0x40 + num, int[4])		/* get abs event limits */ 
+#define EVIOCGABS(num)		_IOR('E', 0x80 + num, int)		/* get abs value */
+
+/*
  * Event types
  */
 
@@ -273,11 +302,12 @@
 #define BTN_THUMB2		0x122
 #define BTN_TOP			0x123
 #define BTN_TOP2		0x124
-#define BTN_BASE		0x125
-#define BTN_BASE2		0x126
-#define BTN_BASE3		0x127
-#define BTN_BASE4		0x128
-#define BTN_BASE5		0x129
+#define BTN_PINKIE		0x125
+#define BTN_BASE		0x126
+#define BTN_BASE2		0x127
+#define BTN_BASE3		0x128
+#define BTN_BASE4		0x129
+#define BTN_BASE5		0x12a
 
 #define BTN_GAMEPAD		0x130
 #define BTN_A			0x130
@@ -383,6 +413,7 @@
  */
 
 #include <linux/sched.h>
+#include <linux/devfs_fs_kernel.h>
 
 #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
 #define BIT(x)	(1<<((x)%BITS_PER_LONG))
@@ -393,6 +424,8 @@
 	void *private;
 
 	int number;
+	char *name;
+	struct input_id id;
 
 	unsigned long evbit[NBITS(EV_MAX)];
 	unsigned long keybit[NBITS(KEY_MAX)];
@@ -430,17 +463,21 @@
 	void *private;
 
 	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
-	int (*connect)(struct input_handler *handler, struct input_dev *dev);
+	struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev);
 	void (*disconnect)(struct input_handle *handle);
 
-	struct input_handle *handle;
+	struct file_operations *fops;
+	int minor;
 
+	struct input_handle *handle;
 	struct input_handler *next;
 };
 
 struct input_handle {
 
 	void *private;
+
+	int open;
 	
 	struct input_dev *dev;
 	struct input_handler *handler;
@@ -455,8 +492,11 @@
 void input_register_handler(struct input_handler *);
 void input_unregister_handler(struct input_handler *);
 
-void input_open_device(struct input_handle *);
+int input_open_device(struct input_handle *);
 void input_close_device(struct input_handle *);
+
+devfs_handle_t input_register_minor(char *name, int minor, int minor_base);
+void input_unregister_minor(devfs_handle_t handle);
 
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/lockd/lockd.h linux/include/linux/lockd/lockd.h
--- v2.3.99-pre3/linux/include/linux/lockd/lockd.h	Fri Mar 10 16:40:49 2000
+++ linux/include/linux/lockd/lockd.h	Mon Apr 10 23:24:20 2000
@@ -146,12 +146,14 @@
 					struct sockaddr_in *, int, int);
 struct rpc_clnt * nlm_bind_host(struct nlm_host *);
 void		  nlm_rebind_host(struct nlm_host *);
+struct nlm_host * nlm_get_host(struct nlm_host *);
 void		  nlm_release_host(struct nlm_host *);
 void		  nlm_shutdown_hosts(void);
 
 /*
  * Server-side lock handling
  */
+int		  nlmsvc_async_call(struct nlm_rqst *, u32, rpc_action);
 u32		  nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
 					struct nlm_lock *, int, struct nlm_cookie *);
 u32		  nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/lockd/nlm.h linux/include/linux/lockd/nlm.h
--- v2.3.99-pre3/linux/include/linux/lockd/nlm.h	Sun Feb 20 21:12:40 2000
+++ linux/include/linux/lockd/nlm.h	Sun Apr  2 15:31:32 2000
@@ -12,11 +12,8 @@
 #include <linux/config.h>
 
 /* Maximum file offset in file_lock.fl_end */
-#ifdef OFFSET_MAX
-# define NLM_OFFSET_MAX		OFFSET_MAX
-#else
-# define NLM_OFFSET_MAX		((off_t) 0x7fffffff)
-#endif
+# define NLM_OFFSET_MAX		((s32) 0x7fffffff)
+# define NLM4_OFFSET_MAX	((s64) ((~(u64)0) >> 1))
 
 /* Return states for NLM */
 enum {
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.99-pre3/linux/include/linux/mm.h	Tue Mar 14 19:10:40 2000
+++ linux/include/linux/mm.h	Mon Apr 10 23:23:20 2000
@@ -163,7 +163,7 @@
 #define PG_error		 1
 #define PG_referenced		 2
 #define PG_uptodate		 3
-#define PG__unused_00		 4
+#define PG_dirty		 4
 #define PG_decr_after		 5
 #define PG_unused_01		 6
 #define PG__unused_02		 7
@@ -180,6 +180,8 @@
 #define Page_Uptodate(page)	test_bit(PG_uptodate, &(page)->flags)
 #define SetPageUptodate(page)	set_bit(PG_uptodate, &(page)->flags)
 #define ClearPageUptodate(page)	clear_bit(PG_uptodate, &(page)->flags)
+#define PageDirty(page)		test_bit(PG_dirty, &(page)->flags)
+#define SetPageDirty(page)	set_bit(PG_dirty, &(page)->flags)
 #define PageLocked(page)	test_bit(PG_locked, &(page)->flags)
 #define LockPage(page)		set_bit(PG_locked, &(page)->flags)
 #define TryLockPage(page)	test_and_set_bit(PG_locked, &(page)->flags)
@@ -188,7 +190,7 @@
 					wake_up(&page->wait); \
 				} while (0)
 #define PageError(page)		test_bit(PG_error, &(page)->flags)
-#define SetPageError(page)	test_and_set_bit(PG_error, &(page)->flags)
+#define SetPageError(page)	set_bit(PG_error, &(page)->flags)
 #define ClearPageError(page)	clear_bit(PG_error, &(page)->flags)
 #define PageReferenced(page)	test_bit(PG_referenced, &(page)->flags)
 #define PageDecrAfter(page)	test_bit(PG_decr_after, &(page)->flags)
@@ -205,6 +207,9 @@
 #define PageClearSwapCache(page)	clear_bit(PG_swap_cache, &(page)->flags)
 
 #define PageTestandClearSwapCache(page)	test_and_clear_bit(PG_swap_cache, &(page)->flags)
+#define PageSwapEntry(page)		test_bit(PG_swap_entry, &(page)->flags)
+#define SetPageSwapEntry(page)		set_bit(PG_swap_entry, &(page)->flags)
+#define ClearPageSwapEntry(page)	clear_bit(PG_swap_entry, &(page)->flags)
 
 #ifdef CONFIG_HIGHMEM
 #define PageHighMem(page)		test_bit(PG_highmem, &(page)->flags)
@@ -406,7 +411,8 @@
 
 extern void free_area_init(unsigned long * zones_size);
 extern void free_area_init_node(int nid, pg_data_t *pgdat, 
-		unsigned long * zones_size, unsigned long zone_start_paddr);
+	unsigned long * zones_size, unsigned long zone_start_paddr, 
+	unsigned long *zholes_size);
 extern void mem_init(void);
 extern void show_mem(void);
 extern void si_meminfo(struct sysinfo * val);
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/mmzone.h linux/include/linux/mmzone.h
--- v2.3.99-pre3/linux/include/linux/mmzone.h	Tue Mar 14 19:10:40 2000
+++ linux/include/linux/mmzone.h	Mon Apr 10 23:23:19 2000
@@ -102,7 +102,7 @@
  */
 extern void show_free_areas_core(int);
 extern void free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
-		unsigned long *zones_size, unsigned long paddr);
+  unsigned long *zones_size, unsigned long paddr, unsigned long *zholes_size);
 
 #ifndef CONFIG_DISCONTIGMEM
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/mount.h linux/include/linux/mount.h
--- v2.3.99-pre3/linux/include/linux/mount.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/mount.h	Sun Apr  2 15:49:08 2000
@@ -11,20 +11,6 @@
 #ifndef _LINUX_MOUNT_H
 #define _LINUX_MOUNT_H
 
-#define DQUOT_USR_ENABLED	0x01		/* User diskquotas enabled */
-#define DQUOT_GRP_ENABLED	0x02		/* Group diskquotas enabled */
-
-struct quota_mount_options
-{
-	unsigned int flags;			/* Flags for diskquotas on this device */
-	struct semaphore dqio_sem;		/* lock device while I/O in progress */
-	struct semaphore dqoff_sem;		/* serialize quota_off() and quota_on() on device */
-	struct file *files[MAXQUOTAS];		/* fp's to quotafiles */
-	time_t inode_expire[MAXQUOTAS];		/* expiretime for inode-quota */
-	time_t block_expire[MAXQUOTAS];		/* expiretime for block-quota */
-	char rsquash[MAXQUOTAS];		/* for quotas threat root as any other user */
-};
-
 struct vfsmount
 {
   kdev_t mnt_dev;			/* Device this applies to */
@@ -34,10 +20,14 @@
   struct vfsmount *mnt_next;		/* pointer to next in linkedlist */
 };
 
-/*
- *	Umount options
- */
- 
-#define MNT_FORCE	0x00000001	/* Attempt to forcibily umount */
+/* MOUNT_REWRITE: fill these */
+static inline struct vfsmount *mntget(struct vfsmount *mnt)
+{
+	return mnt;
+}
+
+static inline void mntput(struct vfsmount *mnt)
+{
+}
 
 #endif /* _LINUX_MOUNT_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/nbd.h linux/include/linux/nbd.h
--- v2.3.99-pre3/linux/include/linux/nbd.h	Fri Mar 10 16:40:49 2000
+++ linux/include/linux/nbd.h	Tue Apr 11 06:59:14 2000
@@ -15,6 +15,7 @@
 #define NBD_CLEAR_QUE	_IO( 0xab, 5 )
 #define NBD_PRINT_DEBUG	_IO( 0xab, 6 )
 #define NBD_SET_SIZE_BLOCKS	_IO( 0xab, 7 )
+#define NBD_DISCONNECT  _IO( 0xab, 8 )
 
 #ifdef MAJOR_NR
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/net.h linux/include/linux/net.h
--- v2.3.99-pre3/linux/include/linux/net.h	Mon Oct 11 15:38:15 1999
+++ linux/include/linux/net.h	Mon Apr 10 23:23:19 2000
@@ -53,11 +53,13 @@
   SS_DISCONNECTING			/* in process of disconnecting	*/
 } socket_state;
 
-#define SO_ACCEPTCON	(1<<16)		/* performed a listen		*/
-#define SO_WAITDATA	(1<<17)		/* wait data to read		*/
-#define SO_NOSPACE	(1<<18)		/* no space to write		*/
+#define __SO_ACCEPTCON	(1<<16)		/* performed a listen		*/
 
 #ifdef __KERNEL__
+
+#define SOCK_ASYNC_NOSPACE	0
+#define SOCK_ASYNC_WAITDATA	1
+#define SOCK_NOSPACE		2
 
 struct socket
 {
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/netfilter_ipv4/ip_conntrack.h linux/include/linux/netfilter_ipv4/ip_conntrack.h
--- v2.3.99-pre3/linux/include/linux/netfilter_ipv4/ip_conntrack.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/netfilter_ipv4/ip_conntrack.h	Mon Apr 10 23:26:45 2000
@@ -67,13 +67,13 @@
 	struct ip_conntrack *expectant;
 };
 
-#if defined(CONFIG_IP_NF_NAT) || defined(CONFIG_IP_NF_NAT_MODULE)
+#ifdef CONFIG_IP_NF_NAT_NEEDED
 #include <linux/netfilter_ipv4/ip_nat.h>
 #endif
 
 #if defined(CONFIG_IP_NF_FTP) || defined(CONFIG_IP_NF_FTP_MODULE)
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#if defined(CONFIG_IP_NF_NAT) || defined(CONFIG_IP_NF_NAT_MODULE)
+#ifdef CONFIG_IP_NF_NAT_NEEDED
 #include <linux/netfilter_ipv4/ip_nat_ftp.h>
 #endif
 #endif
@@ -119,7 +119,7 @@
 #endif
 	} help;
 
-#if defined(CONFIG_IP_NF_NAT) || defined(CONFIG_IP_NF_NAT_MODULE)
+#ifdef CONFIG_IP_NF_NAT_NEEDED
 	struct {
 		struct ip_nat_info info;
 		union {
@@ -132,7 +132,7 @@
 		int masq_index;
 #endif
 	} nat;
-#endif /* CONFIG_IP_NF_NAT || CONFIG_IP_NF_NAT_MODULE */
+#endif /* CONFIG_IP_NF_NAT_NEEDED */
 
 };
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/netfilter_ipv4/ip_conntrack_ftp.h linux/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
--- v2.3.99-pre3/linux/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Mon Apr 10 23:26:44 2000
@@ -19,7 +19,6 @@
 	IP_CT_FTP_PASV = IP_CT_DIR_REPLY
 };
 
-/* Protected by ip_conntrack_lock */
 /* We record seq number and length of ftp ip/port text here: all in
    host order. */
 struct ip_ct_ftp
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/netfilter_ipv4/ip_queue.h linux/include/linux/netfilter_ipv4/ip_queue.h
--- v2.3.99-pre3/linux/include/linux/netfilter_ipv4/ip_queue.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/netfilter_ipv4/ip_queue.h	Thu Mar 30 16:54:53 2000
@@ -2,7 +2,7 @@
  * This is a module which is used for queueing IPv4 packets and
  * communicating with userspace via netlink.
  *
- * (C) 2000 James Morris
+ * (C) 2000 James Morris, this code is GPL.
  */
 #ifndef _IP_QUEUE_H
 #define _IP_QUEUE_H
@@ -27,7 +27,7 @@
 	char indev_name[IFNAMSIZ];	/* Name of incoming interface */
 	char outdev_name[IFNAMSIZ];	/* Name of outgoing interface */
 	size_t data_len;		/* Length of packet data */
-	/* Optional packet data follows */
+	unsigned char payload[0];	/* Optional packet data */
 } ipq_packet_msg_t;
 
 /* Messages sent from userspace */
@@ -40,7 +40,7 @@
 	unsigned int value;		/* Verdict to hand to netfilter */
 	unsigned long id;		/* Packet ID for this verdict */
 	size_t data_len;		/* Length of replacement data */
-	/* Optional replacement data follows */
+	unsigned char payload[0];	/* Optional replacement packet */
 } ipq_verdict_msg_t;
 
 typedef struct ipq_peer_msg {
@@ -50,37 +50,19 @@
 	} msg;
 } ipq_peer_msg_t;
 
-/* Each queued packet has one of these states */
+/* Packet delivery modes */
 enum {
-	IPQ_PS_NEW,		/* Newly arrived packet */
-	IPQ_PS_WAITING,		/* User has been notified of packet, 
-	                           we're waiting for a verdict */
-	IPQ_PS_VERDICT		/* Packet has been assigned verdict,
-	                           waiting to be reinjected */
-};
-#define IPQ_PS_MAX IPQ_PS_VERDICT
-
-/* The queue operates in one of these states */
-enum {
-	IPQ_QS_HOLD,		/* Hold all packets in queue */
-	IPQ_QS_COPY,		/* Copy metadata and/or packets to user */
-	IPQ_QS_FLUSH		/* Flush and drop all queue entries */
-};
-#define IPQ_QS_MAX IPQ_QS_FLUSH
-
-/* Modes requested by peer */
-enum {
-	IPQ_COPY_NONE,		/* Copy nothing */
+	IPQ_COPY_NONE,		/* Initial mode, packets are dropped */
 	IPQ_COPY_META,		/* Copy metadata */
 	IPQ_COPY_PACKET		/* Copy metadata + packet (range) */
-};	
+};
 #define IPQ_COPY_MAX IPQ_COPY_PACKET
 
 /* Types of messages */
 #define IPQM_BASE	0x10	/* standard netlink messages below this */
-#define IPQM_MODE	(IPQM_BASE + 1)	/* Mode request from peer */
-#define IPQM_VERDICT	(IPQM_BASE + 2)	/* Verdict from peer */ 
-#define IPQM_PACKET	(IPQM_BASE + 3)	/* Packet from kernel */
+#define IPQM_MODE	(IPQM_BASE + 1)		/* Mode request from peer */
+#define IPQM_VERDICT	(IPQM_BASE + 2)		/* Verdict from peer */ 
+#define IPQM_PACKET	(IPQM_BASE + 3)		/* Packet from kernel */
 #define IPQM_MAX	(IPQM_BASE + 4)
 
 #endif /*_IP_QUEUE_H*/
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/netfilter_ipv4/ipt_REJECT.h linux/include/linux/netfilter_ipv4/ipt_REJECT.h
--- v2.3.99-pre3/linux/include/linux/netfilter_ipv4/ipt_REJECT.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/netfilter_ipv4/ipt_REJECT.h	Mon Mar 27 10:35:56 2000
@@ -6,8 +6,7 @@
 	IPT_ICMP_HOST_UNREACHABLE,
 	IPT_ICMP_PROT_UNREACHABLE,
 	IPT_ICMP_PORT_UNREACHABLE,
-	IPT_ICMP_ECHOREPLY,
-	IPT_TCP_RESET,
+	IPT_ICMP_ECHOREPLY
 };
 
 struct ipt_reject_info {
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/nfs.h linux/include/linux/nfs.h
--- v2.3.99-pre3/linux/include/linux/nfs.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/nfs.h	Sat Apr  1 08:04:27 2000
@@ -9,6 +9,7 @@
 
 #include <linux/sunrpc/msg_prot.h>
 
+#define NFS_PROGRAM	100003
 #define NFS_PORT	2049
 #define NFS_MAXDATA	8192
 #define NFS_MAXPATHLEN	1024
@@ -26,7 +27,9 @@
 #define NFSMODE_SOCK	0140000
 #define NFSMODE_FIFO	0010000
 
-	
+#define NFS_MNT_PROGRAM	100005
+#define NFS_MNT_PORT	627
+
 /*
  * NFS stats. The good thing with these values is that NFSv3 errors are
  * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
@@ -84,187 +87,27 @@
 	NFFIFO = 8
 };
 
+#if defined(__KERNEL__)
+/*
+ * This is the kernel NFS client file handle representation
+ */
+#define NFS_MAXFHSIZE		64
 struct nfs_fh {
-	char			data[NFS_FHSIZE];
+	unsigned short		size;
+	unsigned char		data[NFS_MAXFHSIZE];
 };
 
-#define NFS_PROGRAM		100003
-#define NFS_VERSION		2
-#define NFSPROC_NULL		0
-#define NFSPROC_GETATTR		1
-#define NFSPROC_SETATTR		2
-#define NFSPROC_ROOT		3
-#define NFSPROC_LOOKUP		4
-#define NFSPROC_READLINK	5
-#define NFSPROC_READ		6
-#define NFSPROC_WRITECACHE	7
-#define NFSPROC_WRITE		8
-#define NFSPROC_CREATE		9
-#define NFSPROC_REMOVE		10
-#define NFSPROC_RENAME		11
-#define NFSPROC_LINK		12
-#define NFSPROC_SYMLINK		13
-#define NFSPROC_MKDIR		14
-#define NFSPROC_RMDIR		15
-#define NFSPROC_READDIR		16
-#define NFSPROC_STATFS		17
-
-/* Mount support for NFSroot */
-#ifdef __KERNEL__
-#define NFS_MNT_PROGRAM		100005
-#define NFS_MNT_VERSION		1
-#define NFS_MNT_PORT		627
-#define NFS_MNTPROC_MNT		1
-#define NFS_MNTPROC_UMNT	3
-
 /*
  * This is really a general kernel constant, but since nothing like
  * this is defined in the kernel headers, I have to do it here.
  */
 #define NFS_OFFSET_MAX		((__s64)((~(__u64)0) >> 1))
 
-#endif /* __KERNEL__ */
-
-#if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
-
-extern struct rpc_program	nfs_program;
-extern struct rpc_stat		nfs_rpcstat;
-
-struct nfs_time {
-	__u32			seconds;
-	__u32			useconds;
-};
-
-struct nfs_fattr {
-	enum nfs_ftype		type;
-	__u32			mode;
-	__u32			nlink;
-	__u32			uid;
-	__u32			gid;
-	__u32			size;
-	__u32			blocksize;
-	__u32			rdev;
-	__u32			blocks;
-	__u32			fsid;
-	__u32			fileid;
-	struct nfs_time		atime;
-	struct nfs_time		mtime;
-	struct nfs_time		ctime;
-};
-
-struct nfs_fsinfo {
-	__u32			tsize;
-	__u32			bsize;
-	__u32			blocks;
-	__u32			bfree;
-	__u32			bavail;
-};
-
-/* Arguments to the write call.
- * Note that NFS_WRITE_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h
- */
-#define NFS_WRITE_MAXIOV        8
 
 enum nfs3_stable_how {
 	NFS_UNSTABLE = 0,
 	NFS_DATA_SYNC = 1,
 	NFS_FILE_SYNC = 2
 };
-
-struct nfs_writeargs {
-	struct nfs_fh *		fh;
-	__u32			offset;
-	__u32			count;
-	enum nfs3_stable_how	stable;
-	unsigned int		nriov;
-	struct iovec		iov[NFS_WRITE_MAXIOV];
-};
-
-struct nfs_writeverf {
-	enum nfs3_stable_how	committed;
-	__u32			verifier[2];
-};
-
-struct nfs_writeres {
-	struct nfs_fattr *	fattr;
-	struct nfs_writeverf *	verf;
-	__u32			count;
-};
-
-#ifdef NFS_NEED_XDR_TYPES
-
-struct nfs_sattrargs {
-	struct nfs_fh *		fh;
-	struct iattr *		sattr;
-};
-
-struct nfs_diropargs {
-	struct nfs_fh *		fh;
-	const char *		name;
-};
-
-struct nfs_readlinkargs {
-	struct nfs_fh *		fh;
-	const void *		buffer;
-};
-
-struct nfs_readargs {
-	struct nfs_fh *		fh;
-	__u32			offset;
-	__u32			count;
-	void *			buffer;
-};
-
-struct nfs_createargs {
-	struct nfs_fh *		fh;
-	const char *		name;
-	struct iattr *		sattr;
-};
-
-struct nfs_renameargs {
-	struct nfs_fh *		fromfh;
-	const char *		fromname;
-	struct nfs_fh *		tofh;
-	const char *		toname;
-};
-
-struct nfs_linkargs {
-	struct nfs_fh *		fromfh;
-	struct nfs_fh *		tofh;
-	const char *		toname;
-};
-
-struct nfs_symlinkargs {
-	struct nfs_fh *		fromfh;
-	const char *		fromname;
-	const char *		topath;
-	struct iattr *		sattr;
-};
-
-struct nfs_readdirargs {
-	struct nfs_fh *		fh;
-	__u32			cookie;
-	void *			buffer;
-	int			bufsiz;
-};
-
-struct nfs_diropok {
-	struct nfs_fh *		fh;
-	struct nfs_fattr *	fattr;
-};
-
-struct nfs_readres {
-	struct nfs_fattr *	fattr;
-	unsigned int		count;
-};
-
-struct nfs_readdirres {
-	void *			buffer;
-	int			bufsiz;
-	u32			cookie;
-};
-
-#endif /* NFS_NEED_XDR_TYPES */
 #endif /* __KERNEL__ */
-
-#endif
+#endif /* _LINUX_NFS_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/nfs2.h linux/include/linux/nfs2.h
--- v2.3.99-pre3/linux/include/linux/nfs2.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/nfs2.h	Sat Apr  1 08:04:27 2000
@@ -0,0 +1,74 @@
+/*
+ * NFS protocol definitions
+ *
+ * This file contains constants for Version 2 of the protocol.
+ */
+#ifndef _LINUX_NFS2_H
+#define _LINUX_NFS2_H
+
+#define NFS2_PORT	2049
+#define NFS2_MAXDATA	8192
+#define NFS2_MAXPATHLEN	1024
+#define NFS2_MAXNAMLEN	255
+#define NFS2_MAXGROUPS	16
+#define NFS2_FHSIZE	32
+#define NFS2_COOKIESIZE	4
+#define NFS2_FIFO_DEV	(-1)
+#define NFS2MODE_FMT	0170000
+#define NFS2MODE_DIR	0040000
+#define NFS2MODE_CHR	0020000
+#define NFS2MODE_BLK	0060000
+#define NFS2MODE_REG	0100000
+#define NFS2MODE_LNK	0120000
+#define NFS2MODE_SOCK	0140000
+#define NFS2MODE_FIFO	0010000
+
+
+/* NFSv2 file types - beware, these are not the same in NFSv3 */
+enum nfs2_ftype {
+	NF2NON = 0,
+	NF2REG = 1,
+	NF2DIR = 2,
+	NF2BLK = 3,
+	NF2CHR = 4,
+	NF2LNK = 5,
+	NF2SOCK = 6,
+	NF2BAD = 7,
+	NF2FIFO = 8
+};
+
+struct nfs2_fh {
+	char			data[NFS2_FHSIZE];
+};
+
+/*
+ * Procedure numbers for NFSv2
+ */
+#define NFS2_VERSION		2
+#define NFSPROC_NULL		0
+#define NFSPROC_GETATTR		1
+#define NFSPROC_SETATTR		2
+#define NFSPROC_ROOT		3
+#define NFSPROC_LOOKUP		4
+#define NFSPROC_READLINK	5
+#define NFSPROC_READ		6
+#define NFSPROC_WRITECACHE	7
+#define NFSPROC_WRITE		8
+#define NFSPROC_CREATE		9
+#define NFSPROC_REMOVE		10
+#define NFSPROC_RENAME		11
+#define NFSPROC_LINK		12
+#define NFSPROC_SYMLINK		13
+#define NFSPROC_MKDIR		14
+#define NFSPROC_RMDIR		15
+#define NFSPROC_READDIR		16
+#define NFSPROC_STATFS		17
+
+#define NFS_MNT_PROGRAM		100005
+#define NFS_MNT_VERSION		1
+#define MNTPROC_NULL		0
+#define MNTPROC_MNT		1
+#define MNTPROC_UMNT		3
+#define MNTPROC_UMNTALL		4
+
+#endif /* _LINUX_NFS2_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/nfs3.h linux/include/linux/nfs3.h
--- v2.3.99-pre3/linux/include/linux/nfs3.h	Wed Dec  8 14:11:28 1999
+++ linux/include/linux/nfs3.h	Sat Apr  1 08:04:27 2000
@@ -4,14 +4,12 @@
 #ifndef _LINUX_NFS3_H
 #define _LINUX_NFS3_H
 
-#include <linux/sunrpc/msg_prot.h>
-#include <linux/nfs.h>
-
 #define NFS3_PORT		2049
-#define NFS3_MAXDATA		8192
+#define NFS3_MAXDATA		32768
 #define NFS3_MAXPATHLEN		PATH_MAX
 #define NFS3_MAXNAMLEN		NAME_MAX
 #define NFS3_MAXGROUPS		16
+#define NFS3_FHSIZE		64
 #define NFS3_COOKIESIZE		4
 #define NFS3_FIFO_DEV		(-1)
 #define NFS3MODE_FMT		0170000
@@ -23,7 +21,6 @@
 #define NFS3MODE_SOCK		0140000
 #define NFS3MODE_FIFO		0010000
 
-	
 /* Flags for access() call */
 #define NFS3_ACCESS_READ	0x0001
 #define NFS3_ACCESS_LOOKUP	0x0002
@@ -33,9 +30,11 @@
 #define NFS3_ACCESS_EXECUTE	0x0020
 
 /* Flags for create mode */
-#define NFS3_CREATE_UNCHECKED	0
-#define NFS3_CREATE_GUARDED	1
-#define NFS3_CREATE_EXCLUSIVE	2
+enum nfs3_createmode {
+	NFS3_CREATE_UNCHECKED = 0,
+	NFS3_CREATE_GUARDED = 1,
+	NFS3_CREATE_EXCLUSIVE = 2
+};
 
 /* NFSv3 file system properties */
 #define NFS3_FSF_LINK		0x0001
@@ -60,180 +59,41 @@
 };
 
 #define NFS3_VERSION		3
-#define NFSPROC_NULL		0
-#define NFSPROC_GETATTR		1
-#define NFSPROC_SETATTR		2
-#define NFSPROC_ROOT		3
-#define NFSPROC_LOOKUP		4
-#define NFSPROC_READLINK	5
-#define NFSPROC_READ		6
-#define NFSPROC_WRITECACHE	7
-#define NFSPROC_WRITE		8
-#define NFSPROC_CREATE		9
-#define NFSPROC_REMOVE		10
-#define NFSPROC_RENAME		11
-#define NFSPROC_LINK		12
-#define NFSPROC_SYMLINK		13
-#define NFSPROC_MKDIR		14
-#define NFSPROC_RMDIR		15
-#define NFSPROC_READDIR		16
-#define NFSPROC_STATFS		17
+#define NFS3PROC_NULL		0
+#define NFS3PROC_GETATTR	1
+#define NFS3PROC_SETATTR	2
+#define NFS3PROC_LOOKUP		3
+#define NFS3PROC_ACCESS		4
+#define NFS3PROC_READLINK	5
+#define NFS3PROC_READ		6
+#define NFS3PROC_WRITE		7
+#define NFS3PROC_CREATE		8
+#define NFS3PROC_MKDIR		9
+#define NFS3PROC_SYMLINK	10
+#define NFS3PROC_MKNOD		11
+#define NFS3PROC_REMOVE		12
+#define NFS3PROC_RMDIR		13
+#define NFS3PROC_RENAME		14
+#define NFS3PROC_LINK		15
+#define NFS3PROC_READDIR	16
+#define NFS3PROC_READDIRPLUS	17
+#define NFS3PROC_FSSTAT		18
+#define NFS3PROC_FSINFO		19
+#define NFS3PROC_PATHCONF	20
+#define NFS3PROC_COMMIT		21
+
+#define NFS_MNT3_PROGRAM	100005
+#define NFS_MNT3_VERSION	3
+#define MOUNTPROC3_NULL		0
+#define MOUNTPROC3_MNT		1
+#define MOUNTPROC3_UMNT		3
+#define MOUNTPROC3_UMNTALL	4
+ 
 
 #if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
 
 /* Number of 32bit words in post_op_attr */
 #define NFS3_POST_OP_ATTR_WORDS		22
 
-struct nfs3_fattr {
-	enum nfs3_ftype		type;
-	__u32			mode;
-	__u32			nlink;
-	__u32			uid;
-	__u32			gid;
-	__u64			size;
-	__u64			used;
-	__u32			rdev_maj;
-	__u32			rdev_min;
-	__u32			fsid;
-	__u32			fileid;
-	struct nfs_time		atime;
-	struct nfs_time		mtime;
-	struct nfs_time		ctime;
-};
-
-struct nfs3_wcc_attr {
-	__u64			size;
-	struct nfs_time		mtime;
-	struct nfs_time		ctime;
-};
-
-struct nfs3_wcc_data {
-	struct nfs3_wcc_attr	before;
-	struct nfs3_wcc_attr	after;
-};
-
-struct nfs3_sattr {
-	__u32			valid;
-	__u32			mode;
-	__u32			uid;
-	__u32			gid;
-	__u64			size;
-	struct nfs_time		atime;
-	struct nfs_time		mtime;
-};
-
-struct nfs3_entry {
-	__u32			fileid;
-	char *			name;
-	unsigned int		length;
-	__u32			cookie;
-	__u32			eof;
-};
-
-struct nfs3_fsinfo {
-	__u32			tsize;
-	__u32			bsize;
-	__u32			blocks;
-	__u32			bfree;
-	__u32			bavail;
-};
-
-#ifdef NFS_NEED_XDR_TYPES
-
-struct nfs3_sattrargs {
-	struct nfs_fh *		fh;
-	struct nfs_sattr *	sattr;
-};
-
-struct nfs3_diropargs {
-	struct nfs_fh *		fh;
-	const char *		name;
-};
-
-struct nfs3_readargs {
-	struct nfs_fh *		fh;
-	__u32			offset;
-	__u32			count;
-	void *			buffer;
-};
-
-struct nfs3_writeargs {
-	struct nfs_fh *		fh;
-	__u32			offset;
-	__u32			count;
-	const void *		buffer;
-};
-
-struct nfs3_createargs {
-	struct nfs_fh *		fh;
-	const char *		name;
-	struct nfs_sattr *	sattr;
-};
-
-struct nfs3_renameargs {
-	struct nfs_fh *		fromfh;
-	const char *		fromname;
-	struct nfs_fh *		tofh;
-	const char *		toname;
-};
-
-struct nfs3_linkargs {
-	struct nfs_fh *		fromfh;
-	struct nfs_fh *		tofh;
-	const char *		toname;
-};
-
-struct nfs3_symlinkargs {
-	struct nfs_fh *		fromfh;
-	const char *		fromname;
-	const char *		topath;
-	struct nfs_sattr *	sattr;
-};
-
-struct nfs3_readdirargs {
-	struct nfs_fh *		fh;
-	__u32			cookie;
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-struct nfs3_diropok {
-	struct nfs_fh *		fh;
-	struct nfs_fattr *	fattr;
-};
-
-struct nfs3_readres {
-	struct nfs_fattr *	fattr;
-	unsigned int		count;
-};
-
-struct nfs3_readlinkres {
-	char **			string;
-	unsigned int *		lenp;
-	unsigned int		maxlen;
-	void *			buffer;
-};
-
-struct nfs3_readdirres {
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-/*
- * The following are for NFSv3
- */
-struct nfs3_fh {
-	__u32			size;
-	__u8			data[NFS3_FHSIZE]
-};
-
-struct nfs3_wcc_attr {
-	__u64			size;
-	struct nfs_time		mtime;
-	struct nfs_time		ctime;
-};
-
-#endif /* NFS_NEED_XDR_TYPES */
 #endif /* __KERNEL__ */
-
-#endif
+#endif /* _LINUX_NFS3_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.3.99-pre3/linux/include/linux/nfs_fs.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/nfs_fs.h	Mon Apr 10 23:24:09 2000
@@ -10,14 +10,16 @@
 #define _LINUX_NFS_FS_H
 
 #include <linux/config.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/pagemap.h>
 #include <linux/in.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#include <linux/sunrpc/debug.h>
 
-#include <linux/sunrpc/sched.h>
 #include <linux/nfs.h>
-#include <linux/nfs_mount.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_xdr.h>
 
 /*
  * Enable debugging support for nfs client.
@@ -63,17 +65,20 @@
 #define NFS_DSERVER(dentry)		(&(dentry)->d_sb->u.nfs_sb.s_server)
 #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_OLDMTIME(inode)		((inode)->u.nfs_i.read_cache_mtime)
+#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_ATIME(inode)		((inode)->u.nfs_i.read_cache_atime)
+#define NFS_CACHE_ISIZE(inode)		((inode)->u.nfs_i.read_cache_isize)
 #define NFS_NEXTSCAN(inode)		((inode)->u.nfs_i.nextscan)
 #define NFS_CACHEINV(inode) \
 do { \
-	NFS_READTIME(inode) = jiffies - 1000000; \
-	NFS_OLDMTIME(inode) = 0; \
+	NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
 } while (0)
 #define NFS_ATTRTIMEO(inode)		((inode)->u.nfs_i.attrtimeo)
 #define NFS_MINATTRTIMEO(inode) \
@@ -82,15 +87,18 @@
 #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_FLAGS(inode)		((inode)->u.nfs_i.flags)
 #define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
-#define NFS_COOKIES(inode)		((inode)->u.nfs_i.cookies)
-#define NFS_DIREOF(inode)		((inode)->u.nfs_i.direof)
 
 #define NFS_FILEID(inode)		((inode)->u.nfs_i.fileid)
 #define NFS_FSID(inode)			((inode)->u.nfs_i.fsid)
 
+/* Inode Flags */
+#define NFS_USE_READDIRPLUS(inode)	((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0)
+#define NFS_MONOTONE_COOKIES(inode)	((NFS_SERVER(inode)->flags & NFS_NONMONOTONE_COOKIES) ? 0 : 1)
+
 /*
  * These are the default flags for swap requests
  */
@@ -124,45 +132,6 @@
 }
 
 #ifdef __KERNEL__
-
-/*
- * linux/fs/nfs/proc.c
- */
-extern int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fattr *fattr);
-extern int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fattr *fattr, struct iattr *sattr);
-extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct nfs_fh *fhandle,
-			struct nfs_fattr *fattr);
-extern int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
-			int swap, unsigned long offset, unsigned int count,
-			void *buffer, struct nfs_fattr *fattr);
-extern int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
-			int swap, unsigned long offset, unsigned int count,
-			const void *buffer, struct nfs_fattr *fattr);
-extern int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct iattr *sattr,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr);
-extern int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name);
-extern int nfs_proc_rename(struct nfs_server *server,
-			struct nfs_fh *old_dir, const char *old_name,
-			struct nfs_fh *new_dir, const char *new_name);
-extern int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fh *dir, const char *name);
-extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, const char *path,
-			struct iattr *sattr);
-extern int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct iattr *sattr,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr);
-extern int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name);
-extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fsinfo *res);
-
-
 /*
  * linux/fs/nfs/inode.c
  */
@@ -191,8 +160,6 @@
 extern struct inode_operations nfs_dir_inode_operations;
 extern struct file_operations nfs_dir_operations;
 extern struct dentry_operations nfs_dentry_operations;
-extern void nfs_flush_dircache(struct inode *);
-extern void nfs_free_dircache(struct inode *);
 
 /*
  * linux/fs/nfs/symlink.c
@@ -244,7 +211,7 @@
 static inline int
 nfs_wb_page(struct inode *inode, struct page* page)
 {
-	int error = nfs_sync_file(inode, 0, page_offset(page), PAGE_CACHE_SIZE, FLUSH_WAIT | FLUSH_STABLE);
+	int error = nfs_sync_file(inode, 0, page_index(page), 1, FLUSH_WAIT | FLUSH_STABLE);
 	return (error < 0) ? error : 0;
 }
 
@@ -268,6 +235,7 @@
  * (Used only by nfsroot module)
  */
 extern int  nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *);
+extern int  nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *);
 
 /*
  * inline functions
@@ -279,6 +247,30 @@
 	if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
 		return 0;
 	return __nfs_revalidate_inode(server, dentry);
+}
+
+static inline loff_t
+nfs_size_to_loff_t(__u64 size)
+{
+	loff_t maxsz = (((loff_t) ULONG_MAX) << PAGE_CACHE_SHIFT) + PAGE_CACHE_SIZE - 1;
+	if (size > maxsz)
+		return maxsz;
+	return (loff_t) size;
+}
+
+static inline ino_t
+nfs_fileid_to_ino_t(u64 fileid)
+{
+	ino_t ino = (ino_t) fileid;
+	if (sizeof(ino_t) < sizeof(u64))
+		ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8;
+	return ino;
+}
+
+static inline time_t
+nfs_time_to_secs(__u64 time)
+{
+	return (time_t)(time >> 32);
 }
 
 /* NFS root */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h
--- v2.3.99-pre3/linux/include/linux/nfs_fs_i.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/nfs_fs_i.h	Sun Apr  2 15:31:32 2000
@@ -1,8 +1,8 @@
 #ifndef _NFS_FS_I
 #define _NFS_FS_I
 
-#include <linux/nfs.h>
-#include <linux/pipe_fs_i.h>
+#include <asm/types.h>
+#include <linux/list.h>
 
 /*
  * nfs fs inode data in memory
@@ -11,8 +11,8 @@
 	/*
 	 * The 64bit 'inode number'
 	 */
-	__u32 fsid;
-	__u32 fileid;
+	__u64 fsid;
+	__u64 fileid;
 
 	/*
 	 * Various flags
@@ -37,8 +37,18 @@
 	 *	mtime != read_cache_mtime
 	 */
 	unsigned long		read_cache_jiffies;
-	unsigned long		read_cache_mtime;
+	__u64			read_cache_ctime;
+	__u64			read_cache_mtime;
+	__u64			read_cache_atime;
+	__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.
@@ -55,15 +65,12 @@
 	struct inode		*hash_next,
 				*hash_prev;
 	unsigned long		nextscan;
-
-	/* Readdir caching information. */
-	void *cookies;
-	u32 direof;
 };
 
 /*
  * Legal inode flag values
  */
+#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 */
@@ -74,6 +81,7 @@
 struct nfs_lock_info {
 	u32		state;
 	u32		flags;
+	struct nlm_host	*host;
 };
 
 /*
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/nfs_fs_sb.h linux/include/linux/nfs_fs_sb.h
--- v2.3.99-pre3/linux/include/linux/nfs_fs_sb.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/nfs_fs_sb.h	Sat Apr  1 08:04:27 2000
@@ -1,22 +1,22 @@
 #ifndef _NFS_FS_SB
 #define _NFS_FS_SB
 
-#include <linux/nfs.h>
-#include <linux/in.h>
-
 /*
  * NFS client parameters stored in the superblock.
  */
 struct nfs_server {
 	struct rpc_clnt *	client;		/* RPC client handle */
+	struct nfs_rpc_ops *	rpc_ops;	/* NFS protocol vector */
 	int			flags;		/* various flags */
-	int			rsize;		/* read size */
-	int			wsize;		/* write size */
+	unsigned int		rsize;		/* read size */
+	unsigned int		wsize;		/* write size */
+	unsigned int		dtsize;		/* readdir size */
 	unsigned int		bsize;		/* server block size */
 	unsigned int		acregmin;	/* attr cache timeouts */
 	unsigned int		acregmax;
 	unsigned int		acdirmin;
 	unsigned int		acdirmax;
+	unsigned int		namelen;
 	char *			hostname;	/* remote hostname */
 	struct nfs_reqlist *	rw_requests;	/* async read/write requests */
 };
@@ -26,7 +26,6 @@
  */
 struct nfs_sb_info {
 	struct nfs_server	s_server;
-	struct nfs_fh		s_root;
 };
 
 #endif
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/nfs_mount.h linux/include/linux/nfs_mount.h
--- v2.3.99-pre3/linux/include/linux/nfs_mount.h	Mon Apr  7 11:35:31 1997
+++ linux/include/linux/nfs_mount.h	Mon Apr 10 23:24:04 2000
@@ -8,6 +8,8 @@
  *
  *  structure passed from user-space to kernel-space during an nfs mount
  */
+#include <linux/in.h>
+#include <linux/nfs.h>
 
 /*
  * WARNING!  Do not delete or change the order of these fields.  If
@@ -16,12 +18,12 @@
  * mount-to-kernel version compatibility.  Some of these aren't used yet
  * but here they are anyway.
  */
-#define NFS_MOUNT_VERSION	3
+#define NFS_MOUNT_VERSION	4
 
 struct nfs_mount_data {
 	int		version;		/* 1 */
 	int		fd;			/* 1 */
-	struct nfs_fh	root;			/* 1 */
+	struct nfs2_fh	old_root;		/* 1 */
 	int		flags;			/* 1 */
 	int		rsize;			/* 1 */
 	int		wsize;			/* 1 */
@@ -35,6 +37,7 @@
 	char		hostname[256];		/* 1 */
 	int		namlen;			/* 2 */
 	unsigned int	bsize;			/* 3 */
+	struct nfs_fh	root;			/* 4 */
 };
 
 /* bits in the flags field */
@@ -49,5 +52,13 @@
 #define NFS_MOUNT_VER3		0x0080	/* 3 */
 #define NFS_MOUNT_KERBEROS	0x0100	/* 3 */
 #define NFS_MOUNT_NONLM		0x0200	/* 3 */
+#define NFS_MOUNT_FLAGMASK	0xFFFF
+
+/*
+ * Private flags - not to be set by mount program
+ */
+#ifdef __KERNEL__
+#define NFS_NONMONOTONE_COOKIES	0x00010000
+#endif /* __KERNEL__ */
  
 #endif
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/nfs_xdr.h linux/include/linux/nfs_xdr.h
--- v2.3.99-pre3/linux/include/linux/nfs_xdr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/nfs_xdr.h	Sat Apr  1 08:04:27 2000
@@ -0,0 +1,374 @@
+#ifndef _LINUX_NFS_XDR_H
+#define _LINUX_NFS_XDR_H
+
+extern struct rpc_program	nfs_program;
+extern struct rpc_stat		nfs_rpcstat;
+
+struct nfs_fattr {
+	unsigned short		valid;		/* which fields are valid */
+	__u64			pre_size;	/* pre_op_attr.size	  */
+	__u64			pre_mtime;	/* pre_op_attr.mtime	  */
+	__u64			pre_ctime;	/* pre_op_attr.ctime	  */
+	enum nfs_ftype		type;		/* always use NFSv2 types */
+	__u32			mode;
+	__u32			nlink;
+	__u32			uid;
+	__u32			gid;
+	__u64			size;
+	union {
+		struct {
+			__u32	blocksize;
+			__u32	blocks;
+		} nfs2;
+		struct {
+			__u64	used;
+		} nfs3;
+	} du;
+	__u32			rdev;
+	__u64			fsid;
+	__u64			fileid;
+	__u64			atime;
+	__u64			mtime;
+	__u64			ctime;
+};
+
+#define NFS_ATTR_WCC		0x0001		/* pre-op WCC data    */
+#define NFS_ATTR_FATTR		0x0002		/* post-op attributes */
+#define NFS_ATTR_FATTR_V3	0x0004		/* NFSv3 attributes */
+
+/*
+ * Info on the file system
+ */
+struct nfs_fsinfo {
+	__u32			rtmax;	/* max.  read transfer size */
+	__u32			rtpref;	/* pref. read transfer size */
+	__u32			rtmult;	/* reads should be multiple of this */
+	__u32			wtmax;	/* max.  write transfer size */
+	__u32			wtpref;	/* pref. write transfer size */
+	__u32			wtmult;	/* writes should be multiple of this */
+	__u32			dtpref;	/* pref. readdir transfer size */
+	__u64			maxfilesize;
+	__u64			bsize;	/* block size */
+	__u64			tbytes;	/* total size in bytes */
+	__u64			fbytes;	/* # of free bytes */
+	__u64			abytes;	/* # of bytes available to user */
+	__u64			tfiles;	/* # of files */
+	__u64			ffiles;	/* # of free files */
+	__u64			afiles;	/* # of files available to user */
+	__u32			linkmax;/* max # of hard links */
+	__u32			namelen;/* max name length */
+};
+
+/* Arguments to the read call.
+ * Note that NFS_READ_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h
+ */
+#define NFS_READ_MAXIOV 8
+
+struct nfs_readargs {
+	struct nfs_fh *		fh;
+	__u64			offset;
+	__u32			count;
+	unsigned int            nriov;
+	struct iovec            iov[NFS_READ_MAXIOV];
+};
+
+struct nfs_readres {
+	struct nfs_fattr *	fattr;
+	unsigned int		count;
+	int                     eof;
+};
+
+/* Arguments to the write call.
+ * Note that NFS_WRITE_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h
+ */
+#define NFS_WRITE_MAXIOV        8
+struct nfs_writeargs {
+	struct nfs_fh *		fh;
+	__u32			offset;
+	__u32			count;
+	enum nfs3_stable_how	stable;
+	unsigned int		nriov;
+	struct iovec		iov[NFS_WRITE_MAXIOV];
+};
+
+struct nfs_writeverf {
+	enum nfs3_stable_how	committed;
+	__u32			verifier[2];
+};
+
+struct nfs_writeres {
+	struct nfs_fattr *	fattr;
+	struct nfs_writeverf *	verf;
+	__u32			count;
+};
+
+/*
+ * Argument struct for decode_entry function
+ */
+struct nfs_entry {
+	struct page *		page;
+	__u64			ino;
+	__u64			cookie,
+				prev_cookie;
+	const char *		name;
+	unsigned int		len;
+	int			eof;
+	struct nfs_fh		fh;
+	struct nfs_fattr	fattr;
+	unsigned long		offset,
+				prev;
+};
+
+/*
+ * The following types are for NFSv2 only.
+ */
+struct nfs_sattrargs {
+	struct nfs_fh *		fh;
+	struct iattr *		sattr;
+};
+
+struct nfs_diropargs {
+	struct nfs_fh *		fh;
+	const char *		name;
+	unsigned int		len;
+};
+
+struct nfs_createargs {
+	struct nfs_fh *		fh;
+	const char *		name;
+	unsigned int		len;
+	struct iattr *		sattr;
+};
+
+struct nfs_renameargs {
+	struct nfs_fh *		fromfh;
+	const char *		fromname;
+	unsigned int		fromlen;
+	struct nfs_fh *		tofh;
+	const char *		toname;
+	unsigned int		tolen;
+};
+
+struct nfs_linkargs {
+	struct nfs_fh *		fromfh;
+	struct nfs_fh *		tofh;
+	const char *		toname;
+	unsigned int		tolen;
+};
+
+struct nfs_symlinkargs {
+	struct nfs_fh *		fromfh;
+	const char *		fromname;
+	unsigned int		fromlen;
+	const char *		topath;
+	unsigned int		tolen;
+	struct iattr *		sattr;
+};
+
+struct nfs_readdirargs {
+	struct nfs_fh *		fh;
+	__u32			cookie;
+	void *			buffer;
+	unsigned int		bufsiz;
+};
+
+struct nfs_diropok {
+	struct nfs_fh *		fh;
+	struct nfs_fattr *	fattr;
+};
+
+struct nfs_readlinkargs {
+	struct nfs_fh *		fh;
+	void *			buffer;
+	unsigned int		bufsiz;
+};
+
+struct nfs_readlinkres {
+	void *			buffer;
+	unsigned int		bufsiz;
+};
+
+struct nfs_readdirres {
+	void *			buffer;
+	unsigned int		bufsiz;
+};
+
+struct nfs3_sattrargs {
+	struct nfs_fh *		fh;
+	struct iattr *		sattr;
+	unsigned int		guard;
+	__u64			guardtime;
+};
+
+struct nfs3_diropargs {
+	struct nfs_fh *		fh;
+	const char *		name;
+	unsigned int		len;
+};
+
+struct nfs3_accessargs {
+	struct nfs_fh *		fh;
+	__u32			access;
+};
+
+struct nfs3_createargs {
+	struct nfs_fh *		fh;
+	const char *		name;
+	unsigned int		len;
+	struct iattr *		sattr;
+	enum nfs3_createmode	createmode;
+	__u32			verifier[2];
+};
+
+struct nfs3_mkdirargs {
+	struct nfs_fh *		fh;
+	const char *		name;
+	unsigned int		len;
+	struct iattr *		sattr;
+};
+
+struct nfs3_symlinkargs {
+	struct nfs_fh *		fromfh;
+	const char *		fromname;
+	unsigned int		fromlen;
+	const char *		topath;
+	unsigned int		tolen;
+	struct iattr *		sattr;
+};
+
+struct nfs3_mknodargs {
+	struct nfs_fh *		fh;
+	const char *		name;
+	unsigned int		len;
+	enum nfs3_ftype		type;
+	struct iattr *		sattr;
+	dev_t			rdev;
+};
+
+struct nfs3_renameargs {
+	struct nfs_fh *		fromfh;
+	const char *		fromname;
+	unsigned int		fromlen;
+	struct nfs_fh *		tofh;
+	const char *		toname;
+	unsigned int		tolen;
+};
+
+struct nfs3_linkargs {
+	struct nfs_fh *		fromfh;
+	struct nfs_fh *		tofh;
+	const char *		toname;
+	unsigned int		tolen;
+};
+
+struct nfs3_readdirargs {
+	struct nfs_fh *		fh;
+	__u64			cookie;
+	__u32			verf[2];
+	void *			buffer;
+	unsigned int		bufsiz;
+	int			plus;
+};
+
+struct nfs3_diropres {
+	struct nfs_fattr *	dir_attr;
+	struct nfs_fh *		fh;
+	struct nfs_fattr *	fattr;
+};
+
+struct nfs3_accessres {
+	struct nfs_fattr *	fattr;
+	__u32			access;
+};
+
+struct nfs3_readlinkargs {
+	struct nfs_fh *		fh;
+	void *			buffer;
+	unsigned int		bufsiz;
+};
+
+struct nfs3_readlinkres {
+	struct nfs_fattr *	fattr;
+	void *			buffer;
+	unsigned int		bufsiz;
+};
+
+struct nfs3_renameres {
+	struct nfs_fattr *	fromattr;
+	struct nfs_fattr *	toattr;
+};
+
+struct nfs3_linkres {
+	struct nfs_fattr *	dir_attr;
+	struct nfs_fattr *	fattr;
+};
+
+struct nfs3_readdirres {
+	struct nfs_fattr *	dir_attr;
+	__u32 *			verf;
+	void *			buffer;
+	unsigned int		bufsiz;
+	int			plus;
+};
+
+/*
+ * RPC procedure vector for NFSv2/NFSv3 demuxing
+ */
+struct nfs_rpc_ops {
+	int	version;		/* Protocol version */
+
+	int	(*getroot) (struct nfs_server *, struct nfs_fh *,
+			    struct nfs_fattr *);
+	int	(*getattr) (struct dentry *, struct nfs_fattr *);
+	int	(*setattr) (struct dentry *, struct nfs_fattr *,
+			    struct iattr *);
+	int	(*lookup)  (struct dentry *, struct qstr *,
+			    struct nfs_fh *, struct nfs_fattr *);
+	int	(*access)  (struct dentry *, int , int);
+	int	(*readlink)(struct dentry *, void *, unsigned int);
+	int	(*read)    (struct dentry *, struct nfs_fattr *,
+			    int, loff_t, unsigned int,
+			    void *buffer, int *eofp);
+	int	(*write)   (struct dentry *, struct nfs_fattr *,
+			    int, loff_t, unsigned int,
+			    void *buffer, struct nfs_writeverf *verfp);
+	int	(*commit)  (struct dentry *, struct nfs_fattr *,
+			    unsigned long, unsigned int);
+	int	(*create)  (struct dentry *, struct qstr *, struct iattr *,
+			    int, struct nfs_fh *, struct nfs_fattr *);
+	int	(*remove)  (struct dentry *, struct qstr *);
+	int	(*rename)  (struct dentry *, struct qstr *,
+			    struct dentry *, struct qstr *);
+	int	(*link)    (struct dentry *, struct dentry *, struct qstr *);
+	int	(*symlink) (struct dentry *, struct qstr *, struct qstr *,
+			    struct iattr *, struct nfs_fh *,
+			    struct nfs_fattr *);
+	int	(*mkdir)   (struct dentry *, struct qstr *, struct iattr *,
+			    struct nfs_fh *, struct nfs_fattr *);
+	int	(*rmdir)   (struct dentry *, struct qstr *);
+	int	(*readdir) (struct dentry *, u64 cookie, void *, unsigned int,
+			    int);
+	int	(*mknod)   (struct dentry *, struct qstr *, struct iattr *,
+			    dev_t, struct nfs_fh *, struct nfs_fattr *);
+	int	(*statfs)  (struct nfs_server *, struct nfs_fh *,
+			    struct nfs_fsinfo *);
+	u32 *	(*decode_dirent)(u32 *, struct nfs_entry *, int plus);
+};
+
+/*
+ * 	NFS_CALL(getattr, inode, (fattr));
+ * into
+ *	NFS_PROTO(inode)->getattr(fattr);
+ */
+#define NFS_CALL(op, inode, args)	NFS_PROTO(inode)->op args
+
+/*
+ * Function vectors etc. for the NFS client
+ */
+extern struct nfs_rpc_ops	nfs_v2_clientops;
+extern struct nfs_rpc_ops	nfs_v3_clientops;
+extern struct rpc_version	nfs_version2;
+extern struct rpc_version	nfs_version3;
+extern struct rpc_program	nfs_program;
+
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/nfsd/const.h linux/include/linux/nfsd/const.h
--- v2.3.99-pre3/linux/include/linux/nfsd/const.h	Wed Dec  8 14:11:28 1999
+++ linux/include/linux/nfsd/const.h	Sat Apr  1 08:04:27 2000
@@ -10,6 +10,8 @@
 #define _LINUX_NFSD_CONST_H
 
 #include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
 
 /*
  * Maximum protocol version supported by knfsd
@@ -20,18 +22,6 @@
  * Maximum blocksize supported by daemon currently at 8K
  */
 #define NFSSVC_MAXBLKSIZE	8192
-
-#define NFS2_MAXPATHLEN		1024
-#define NFS2_MAXNAMLEN		255
-#define NFS2_FHSIZE		NFS_FHSIZE
-#define NFS2_COOKIESIZE		4
-
-#define NFS3_MAXPATHLEN		PATH_MAX
-#define NFS3_MAXNAMLEN		NAME_MAX
-#define NFS3_FHSIZE		64
-#define NFS3_COOKIEVERFSIZE	8
-#define NFS3_CREATEVERFSIZE	8
-#define NFS3_WRITEVERFSIZE	8
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.99-pre3/linux/include/linux/pci.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/pci.h	Mon Apr 10 23:23:21 2000
@@ -340,7 +340,7 @@
 	struct resource dma_resource[DEVICE_COUNT_DMA];
 	struct resource irq_resource[DEVICE_COUNT_IRQ];
 
-	char		name[48];	/* device name */
+	char		name[80];	/* device name */
 	char		slot_name[8];	/* slot name */
 	int		active;		/* ISAPnP: device is active */
 	int		ro;		/* ISAPnP: read only */
@@ -510,6 +510,7 @@
 
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
+void pdev_assign_unassigned_resources(struct pci_dev *dev);
 void pci_set_bus_ranges(void);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
 		    int (*)(struct pci_dev *, u8, u8));
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/ppp_channel.h linux/include/linux/ppp_channel.h
--- v2.3.99-pre3/linux/include/linux/ppp_channel.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/ppp_channel.h	Mon Apr 10 23:05:35 2000
@@ -16,11 +16,12 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  *
- * ==FILEVERSION 20000225==
+ * ==FILEVERSION 20000322==
  */
 
 #include <linux/list.h>
 #include <linux/skbuff.h>
+#include <linux/poll.h>
 
 struct ppp_channel;
 
@@ -61,7 +62,10 @@
 /* Detach a channel from its PPP unit (e.g. on hangup). */
 extern void ppp_unregister_channel(struct ppp_channel *);
 
-/* Get the unit number associated with a channel */
+/* Get the channel number for a channel */
+extern int ppp_channel_index(struct ppp_channel *);
+
+/* Get the unit number associated with a channel, or -1 if none */
 extern int ppp_unit_number(struct ppp_channel *);
 
 /*
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/proc_fs_i.h linux/include/linux/proc_fs_i.h
--- v2.3.99-pre3/linux/include/linux/proc_fs_i.h	Thu Nov 11 20:11:53 1999
+++ linux/include/linux/proc_fs_i.h	Fri Apr  7 13:38:00 2000
@@ -2,7 +2,7 @@
 	struct task_struct *task;
 	int type;
 	union {
-		struct dentry *(*proc_get_link)(struct inode *);
+		int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **);
 		int (*proc_read)(struct task_struct *task, char *page);
 	} op;
 	struct file *file;
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/raid/md_u.h linux/include/linux/raid/md_u.h
--- v2.3.99-pre3/linux/include/linux/raid/md_u.h	Thu Feb 10 17:11:22 2000
+++ linux/include/linux/raid/md_u.h	Mon Apr 10 23:04:49 2000
@@ -17,6 +17,12 @@
 
 /* ioctls */
 
+/* compat */
+#define REGISTER_DEV 		_IO (MD_MAJOR, 1)
+#define START_MD     		_IO (MD_MAJOR, 2)
+#define STOP_MD      		_IO (MD_MAJOR, 3)
+
+
 /* status */
 #define RAID_VERSION		_IOR (MD_MAJOR, 0x10, mdu_version_t)
 #define GET_ARRAY_INFO		_IOR (MD_MAJOR, 0x11, mdu_array_info_t)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.99-pre3/linux/include/linux/sched.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/sched.h	Mon Apr 10 23:23:20 2000
@@ -185,12 +185,13 @@
 	atomic_t count;
 	int umask;
 	struct dentry * root, * pwd;
+	struct vfsmount * rootmnt, * pwdmnt;
 };
 
 #define INIT_FS { \
 	ATOMIC_INIT(1), \
 	0022, \
-	NULL, NULL \
+	NULL, NULL, NULL, NULL \
 }
 
 /* Maximum number of active map areas.. This is a random (large) number */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.3.99-pre3/linux/include/linux/skbuff.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/skbuff.h	Mon Apr 10 23:23:51 2000
@@ -207,20 +207,45 @@
 	return (atomic_t *)(skb->end);
 }
 
+/**
+ *	skb_queue_empty - check if a queue is empty
+ *	@list: queue head
+ *
+ *	Returns true if the queue is empty, false otherwise
+ */
+ 
 extern __inline__ int skb_queue_empty(struct sk_buff_head *list)
 {
 	return (list->next == (struct sk_buff *) list);
 }
 
+/**
+ *	skb_get - reference buffer
+ *	@skb: buffer to reference
+ *
+ *	Makes another reference to a socket buffer and returns a pointer
+ *	to the buffer.
+ */
+ 
 extern __inline__ struct sk_buff *skb_get(struct sk_buff *skb)
 {
 	atomic_inc(&skb->users);
 	return skb;
 }
 
-/* If users==1, we are the only owner and are can avoid redundant
+/*
+ * If users==1, we are the only owner and are can avoid redundant
  * atomic change.
  */
+ 
+/**
+ *	kfree_skb - free an sk_buff
+ *	@skb: The buffer to free
+ *
+ *	Drop a reference to the buffer and free it if the usage count has
+ *	hit zero.
+ */
+ 
 extern __inline__ void kfree_skb(struct sk_buff *skb)
 {
 	if (atomic_read(&skb->users) == 1 || atomic_dec_and_test(&skb->users))
@@ -234,16 +259,47 @@
 		kfree_skbmem(skb);	
 }
 
+/**
+ *	skb_cloned - is the buffer a clone
+ *	@skb: Buffer to check
+ *
+ *	Returns true if the buffer was generated with skb_clone and is
+ *	one of multiple shared copies of the buffer. Cloned buffers are
+ *	shared data so must not be written to under normal circumstances.
+ */
+
 extern __inline__ int skb_cloned(struct sk_buff *skb)
 {
 	return skb->cloned && atomic_read(skb_datarefp(skb)) != 1;
 }
 
+/**
+ *	skb_shared - is the buffer shared
+ *	@skb: buffer to check
+ *
+ *	Returns true if more than one person has a reference to this
+ *	buffer.
+ */
+ 
 extern __inline__ int skb_shared(struct sk_buff *skb)
 {
 	return (atomic_read(&skb->users) != 1);
 }
 
+/** 
+ *	skb_share_check - check if buffer is shared and if so clone it
+ *	@skb: buffer to check
+ *	@pri: priority for memory allocation
+ *	
+ *	If the buffer is shared the buffer is cloned and the old copy
+ *	drops a reference. A new clone with a single reference is returned.
+ *	If the buffer is not shared the original buffer is returned. When
+ *	being called from interrupt status or with spinlocks held pri must
+ *	be GFP_ATOMIC.
+ *
+ *	NULL is returned on a memory allocation failure.
+ */
+ 
 extern __inline__ struct sk_buff *skb_share_check(struct sk_buff *skb, int pri)
 {
 	if (skb_shared(skb)) {
@@ -263,6 +319,20 @@
  *	a packet thats being forwarded.
  */
  
+/**
+ *	skb_unshare - make a copy of a shared buffer
+ *	@skb: buffer to check
+ *	@pri: priority for memory allocation
+ *
+ *	If the socket buffer is a clone then this function creates a new
+ *	copy of the data, drops a reference count on the old copy and returns
+ *	the new copy with the reference count at 1. If the buffer is not a clone
+ *	the original buffer is returned. When called with a spinlock held or
+ *	from interrupt state pri must be GFP_ATOMIC
+ *
+ *	NULL is returned on a memory allocation failure.
+ */
+ 
 extern __inline__ struct sk_buff *skb_unshare(struct sk_buff *skb, int pri)
 {
 	struct sk_buff *nskb;
@@ -273,11 +343,18 @@
 	return nskb;
 }
 
-/*
+/**
+ *	skb_peek
+ *	@list_: list to peek at
+ *
  *	Peek an sk_buff. Unlike most other operations you _MUST_
  *	be careful with this one. A peek leaves the buffer on the
- *	list and someone else may run off with it. For an interrupt
- *	type system cli() peek the buffer copy the data and sti();
+ *	list and someone else may run off with it. You must hold
+ *	the appropriate locks or have a private queue to do this.
+ *
+ *	Returns NULL for an empty list or a pointer to the head element.
+ *	The reference count is not incremented and the reference is therefore
+ *	volatile. Use with caution.
  */
  
 extern __inline__ struct sk_buff *skb_peek(struct sk_buff_head *list_)
@@ -288,6 +365,20 @@
 	return list;
 }
 
+/**
+ *	skb_peek_tail
+ *	@list_: list to peek at
+ *
+ *	Peek an sk_buff. Unlike most other operations you _MUST_
+ *	be careful with this one. A peek leaves the buffer on the
+ *	list and someone else may run off with it. You must hold
+ *	the appropriate locks or have a private queue to do this.
+ *
+ *	Returns NULL for an empty list or a pointer to the tail element.
+ *	The reference count is not incremented and the reference is therefore
+ *	volatile. Use with caution.
+ */
+
 extern __inline__ struct sk_buff *skb_peek_tail(struct sk_buff_head *list_)
 {
 	struct sk_buff *list = ((struct sk_buff *)list_)->prev;
@@ -296,8 +387,11 @@
 	return list;
 }
 
-/*
- *	Return the length of an sk_buff queue
+/**
+ *	skb_queue_len	- get queue length
+ *	@list_: list to measure
+ *
+ *	Return the length of an sk_buff queue. 
  */
  
 extern __inline__ __u32 skb_queue_len(struct sk_buff_head *list_)
@@ -320,6 +414,17 @@
  *	can only be called with interrupts disabled.
  */
 
+/**
+ *	__skb_queue_head - queue a buffer at the list head
+ *	@list: list to use
+ *	@newsk: buffer to queue
+ *
+ *	Queue a buffer at the start of a list. This function takes no locks
+ *	and you must therefore hold required locks before calling it.
+ *
+ *	A buffer cannot be placed on two lists at the same time.
+ */	
+ 
 extern __inline__ void __skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
 {
 	struct sk_buff *prev, *next;
@@ -334,6 +439,19 @@
 	prev->next = newsk;
 }
 
+
+/**
+ *	skb_queue_head - queue a buffer at the list head
+ *	@list: list to use
+ *	@newsk: buffer to queue
+ *
+ *	Queue a buffer at the start of the list. This function takes the
+ *	list lock and can be used safely with other locking sk_buff functions
+ *	safely.
+ *
+ *	A buffer cannot be placed on two lists at the same time.
+ */	
+
 extern __inline__ void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
 {
 	unsigned long flags;
@@ -343,9 +461,17 @@
 	spin_unlock_irqrestore(&list->lock, flags);
 }
 
-/*
- *	Insert an sk_buff at the end of a list.
- */
+/**
+ *	__skb_queue_tail - queue a buffer at the list tail
+ *	@list: list to use
+ *	@newsk: buffer to queue
+ *
+ *	Queue a buffer at the end of a list. This function takes no locks
+ *	and you must therefore hold required locks before calling it.
+ *
+ *	A buffer cannot be placed on two lists at the same time.
+ */	
+ 
 
 extern __inline__ void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
 {
@@ -361,6 +487,18 @@
 	prev->next = newsk;
 }
 
+/**
+ *	skb_queue_tail - queue a buffer at the list tail
+ *	@list: list to use
+ *	@newsk: buffer to queue
+ *
+ *	Queue a buffer at the tail of the list. This function takes the
+ *	list lock and can be used safely with other locking sk_buff functions
+ *	safely.
+ *
+ *	A buffer cannot be placed on two lists at the same time.
+ */	
+
 extern __inline__ void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
 {
 	unsigned long flags;
@@ -370,8 +508,13 @@
 	spin_unlock_irqrestore(&list->lock, flags);
 }
 
-/*
- *	Remove an sk_buff from a list.
+/**
+ *	__skb_dequeue - remove from the head of the queue
+ *	@list: list to dequeue from
+ *
+ *	Remove the head of the list. This function does not take any locks
+ *	so must be used with appropriate locks held only. The head item is
+ *	returned or NULL if the list is empty.
  */
 
 extern __inline__ struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
@@ -394,6 +537,15 @@
 	return result;
 }
 
+/**
+ *	skb_dequeue - remove from the head of the queue
+ *	@list: list to dequeue from
+ *
+ *	Remove the head of the list. The list lock is taken so the function
+ *	may be used safely with other locking list functions. The head item is
+ *	returned or NULL if the list is empty.
+ */
+
 extern __inline__ struct sk_buff *skb_dequeue(struct sk_buff_head *list)
 {
 	long flags;
@@ -421,9 +573,16 @@
 	list->qlen++;
 }
 
-/*
- *	Place a packet before a given packet in a list
+/**
+ *	skb_insert	-	insert a buffer
+ *	@old: buffer to insert before
+ *	@newsk: buffer to insert
+ *
+ *	Place a packet before a given packet in a list. The list locks are taken
+ *	and this function is atomic with respect to other list locked calls
+ *	A buffer cannot be placed on two lists at the same time.
  */
+
 extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
 {
 	unsigned long flags;
@@ -442,6 +601,17 @@
 	__skb_insert(newsk, old, old->next, old->list);
 }
 
+/**
+ *	skb_append	-	append a buffer
+ *	@old: buffer to insert after
+ *	@newsk: buffer to insert
+ *
+ *	Place a packet after a given packet in a list. The list locks are taken
+ *	and this function is atomic with respect to other list locked calls.
+ *	A buffer cannot be placed on two lists at the same time.
+ */
+
+
 extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
 {
 	unsigned long flags;
@@ -455,6 +625,7 @@
  * remove sk_buff from list. _Must_ be called atomically, and with
  * the list known..
  */
+ 
 extern __inline__ void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
 {
 	struct sk_buff * next, * prev;
@@ -469,11 +640,17 @@
 	prev->next = next;
 }
 
-/*
- *	Remove an sk_buff from its list. Works even without knowing the list it
- *	is sitting on, which can be handy at times. It also means that THE LIST
- *	MUST EXIST when you unlink. Thus a list must have its contents unlinked
- *	_FIRST_.
+/**
+ *	skb_unlink	-	remove a buffer from a list
+ *	@skb: buffer to remove
+ *
+ *	Place a packet after a given packet in a list. The list locks are taken
+ *	and this function is atomic with respect to other list locked calls
+ *	
+ *	Works even without knowing the list it is sitting on, which can be 
+ *	handy at times. It also means that THE LIST MUST EXIST when you 
+ *	unlink. Thus a list must have its contents unlinked before it is
+ *	destroyed.
  */
 
 extern __inline__ void skb_unlink(struct sk_buff *skb)
@@ -491,6 +668,16 @@
 }
 
 /* XXX: more streamlined implementation */
+
+/**
+ *	__skb_dequeue_tail - remove from the tail of the queue
+ *	@list: list to dequeue from
+ *
+ *	Remove the tail of the list. This function does not take any locks
+ *	so must be used with appropriate locks held only. The tail item is
+ *	returned or NULL if the list is empty.
+ */
+
 extern __inline__ struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
 {
 	struct sk_buff *skb = skb_peek_tail(list); 
@@ -499,6 +686,15 @@
 	return skb;
 }
 
+/**
+ *	skb_dequeue - remove from the head of the queue
+ *	@list: list to dequeue from
+ *
+ *	Remove the head of the list. The list lock is taken so the function
+ *	may be used safely with other locking list functions. The tail item is
+ *	returned or NULL if the list is empty.
+ */
+
 extern __inline__ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
 {
 	long flags;
@@ -522,6 +718,16 @@
 	return tmp;
 }
 
+/**
+ *	skb_put - add data to a buffer
+ *	@skb: buffer to use 
+ *	@len: amount of data to add
+ *
+ *	This function extends the used data area of the buffer. If this would
+ *	exceed the total buffer size the kernel will panic. A pointer to the
+ *	first byte of the extra data is returned
+ */
+ 
 extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
 {
 	unsigned char *tmp=skb->tail;
@@ -540,6 +746,16 @@
 	return skb->data;
 }
 
+/**
+ *	skb_push - add data to the start of a buffer
+ *	@skb: buffer to use 
+ *	@len: amount of data to add
+ *
+ *	This function extends the used data area of the buffer at the buffer
+ *	start. If this would  exceed the total buffer headroom the kernel will
+ *	 panic. A pointer to the first byte of the extra data is returned
+ */
+
 extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
 {
 	skb->data-=len;
@@ -556,6 +772,17 @@
 	return 	skb->data+=len;
 }
 
+/**
+ *	skb_pull - remove data from the start of a buffer
+ *	@skb: buffer to use 
+ *	@len: amount of data to remove
+ *
+ *	This function  removes data from the start of a buffer, returning
+ *	the memory to the headroom. A pointer to the next data in the buffer
+ *	is returned. Once the data has been pulled future pushes will overwrite
+ *	the old data
+ */
+
 extern __inline__ unsigned char * skb_pull(struct sk_buff *skb, unsigned int len)
 {	
 	if (len > skb->len)
@@ -563,28 +790,61 @@
 	return __skb_pull(skb,len);
 }
 
+/**
+ *	skb_headroom - bytes at buffer head
+ *	@skb: buffer to check
+ *
+ *	Return the number of bytes of free space at the head of an sk_buff
+ */
+ 
 extern __inline__ int skb_headroom(const struct sk_buff *skb)
 {
 	return skb->data-skb->head;
 }
 
+/**
+ *	skb_tailroom - bytes at buffer end
+ *	@skb: buffer to check
+ *
+ *	Return the number of bytes of free space at the tail of an sk_buff
+ */
+
 extern __inline__ int skb_tailroom(const struct sk_buff *skb)
 {
 	return skb->end-skb->tail;
 }
 
+/**
+ *	skb_reserve - adjust headroom
+ *	@skb: buffer to alter
+ *	@len: bytes to move
+ *
+ *	Increase the headroom of an empty sk_buff by reducing the tail
+ *	room. This is only allowed for an empty buffer.
+ */
+
 extern __inline__ void skb_reserve(struct sk_buff *skb, unsigned int len)
 {
 	skb->data+=len;
 	skb->tail+=len;
 }
 
+
 extern __inline__ void __skb_trim(struct sk_buff *skb, unsigned int len)
 {
 	skb->len = len;
 	skb->tail = skb->data+len;
 }
 
+/**
+ *	skb_trim - remove end from a buffer
+ *	@skb: buffer to alter
+ *	@len: new length
+ *
+ *	Cut the length of a buffer down by removing data from the tail. If
+ *	the buffer is already under the length specified it is not modified.
+ */
+
 extern __inline__ void skb_trim(struct sk_buff *skb, unsigned int len)
 {
 	if (skb->len > len) {
@@ -592,6 +852,16 @@
 	}
 }
 
+/**
+ *	skb_orphan - orphan a buffer
+ *	@skb: buffer to orphan
+ *
+ *	If a buffer currently has an owner then we call the owners
+ *	destructor function and make the skb unowned. The buffer continues
+ *	to exist but is no longer charged to its former owner.
+ */
+
+
 extern __inline__ void skb_orphan(struct sk_buff *skb)
 {
 	if (skb->destructor)
@@ -600,6 +870,16 @@
 	skb->sk = NULL;
 }
 
+/**
+ *	skb_purge - empty a list
+ *	@list: list to empty
+ *
+ *	Delete all buffers on an sk_buff list. Each buffer is removed from
+ *	the list and one reference dropped. This function takes the list
+ *	lock and is atomic with respect to other list locking functions.
+ */
+
+
 extern __inline__ void skb_queue_purge(struct sk_buff_head *list)
 {
 	struct sk_buff *skb;
@@ -607,6 +887,16 @@
 		kfree_skb(skb);
 }
 
+/**
+ *	__skb_purge - empty a list
+ *	@list: list to empty
+ *
+ *	Delete all buffers on an sk_buff list. Each buffer is removed from
+ *	the list and one reference dropped. This function does not take the
+ *	list lock and the caller must hold the relevant locks to use it.
+ */
+
+
 extern __inline__ void __skb_queue_purge(struct sk_buff_head *list)
 {
 	struct sk_buff *skb;
@@ -614,6 +904,19 @@
 		kfree_skb(skb);
 }
 
+/**
+ *	dev_alloc_skb - allocate an skbuff for sending
+ *	@length: length to allocate
+ *
+ *	Allocate a new sk_buff and assign it a usage count of one. The
+ *	buffer has unspecified headroom built in. Users should allocate
+ *	the headroom they think they need without accounting for the
+ *	built in space. The built in space is used for optimisations.
+ *
+ *	NULL is returned in there is no free memory. Although this function
+ *	allocates memory it can be called from an interrupt.
+ */
+ 
 extern __inline__ struct sk_buff *dev_alloc_skb(unsigned int length)
 {
 	struct sk_buff *skb;
@@ -623,6 +926,22 @@
 		skb_reserve(skb,16);
 	return skb;
 }
+
+/**
+ *	skb_cow - copy a buffer if need be
+ *	@skb: buffer to copy
+ *	@headroom: needed headroom
+ *
+ *	If the buffer passed lacks sufficient headroom or is a clone then
+ *	it is copied and the additional headroom made available. If there
+ *	is no free memory NULL is returned. The new buffer is returned if
+ *	a copy was made (and the old one dropped a reference). The existing
+ *	buffer is returned otherwise.
+ *
+ *	This function primarily exists to avoid making two copies when making
+ *	a writable copy of a buffer and then growing the headroom.
+ */
+ 
 
 extern __inline__ struct sk_buff *
 skb_cow(struct sk_buff *skb, unsigned int headroom)
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/sunrpc/sched.h linux/include/linux/sunrpc/sched.h
--- v2.3.99-pre3/linux/include/linux/sunrpc/sched.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/sunrpc/sched.h	Mon Apr 10 23:24:04 2000
@@ -63,6 +63,7 @@
 	void			(*tk_callback)(struct rpc_task *);
 	void			(*tk_action)(struct rpc_task *);
 	void			(*tk_exit)(struct rpc_task *);
+	void			(*tk_release)(struct rpc_task *);
 	void *			tk_calldata;
 
 	/*
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/sunrpc/svc.h linux/include/linux/sunrpc/svc.h
--- v2.3.99-pre3/linux/include/linux/sunrpc/svc.h	Thu Feb 10 17:11:22 2000
+++ linux/include/linux/sunrpc/svc.h	Mon Apr 10 23:24:09 2000
@@ -10,6 +10,7 @@
 #ifndef SUNRPC_SVC_H
 #define SUNRPC_SVC_H
 
+#include <linux/in.h>
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/svcauth.h>
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/sunrpc/xdr.h linux/include/linux/sunrpc/xdr.h
--- v2.3.99-pre3/linux/include/linux/sunrpc/xdr.h	Sun Feb 20 21:12:40 2000
+++ linux/include/linux/sunrpc/xdr.h	Mon Apr 10 23:24:04 2000
@@ -59,6 +59,7 @@
 /*
  * Miscellaneous XDR helper functions
  */
+u32 *	xdr_encode_array(u32 *p, const char *s, unsigned int len);
 u32 *	xdr_encode_string(u32 *p, const char *s);
 u32 *	xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen);
 u32 *	xdr_encode_netobj(u32 *p, const struct xdr_netobj *);
@@ -92,6 +93,9 @@
 {
 	return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base);
 }
+
+void xdr_shift_iovec(struct iovec *, int, size_t);
+void xdr_zero_iovec(struct iovec *, int, size_t);
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.3.99-pre3/linux/include/linux/swap.h	Tue Mar 14 19:10:40 2000
+++ linux/include/linux/swap.h	Mon Apr 10 23:23:19 2000
@@ -154,7 +154,7 @@
 		return 1;
 	count = page_count(page);
 	if (PageSwapCache(page))
-		count += swap_count(page) - 2;
+		count += swap_count(page) - 2 - !!page->buffers;
 	return  count > 1;
 }
 
@@ -173,6 +173,8 @@
 
 #define	lru_cache_del(page)			\
 do {						\
+	if (!PageLocked(page))			\
+		BUG();				\
 	spin_lock(&pagemap_lru_lock);		\
 	list_del(&(page)->lru);			\
 	nr_lru_pages--;				\
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.3.99-pre3/linux/include/linux/tty.h	Tue Mar 14 19:10:40 2000
+++ linux/include/linux/tty.h	Mon Apr 10 23:23:20 2000
@@ -374,6 +374,9 @@
 extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
 extern int tty_register_driver(struct tty_driver *driver);
 extern int tty_unregister_driver(struct tty_driver *driver);
+extern void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
+				unsigned minor);
+extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
 extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
 			     int buflen);
 extern void tty_write_message(struct tty_struct *tty, char *msg);
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/udf_fs.h linux/include/linux/udf_fs.h
--- v2.3.99-pre3/linux/include/linux/udf_fs.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/udf_fs.h	Mon Apr 10 22:50:40 2000
@@ -56,12 +56,4 @@
 #define udf_info(f, a...) \
 		printk (KERN_INFO "UDF-fs INFO " ## f, ## a);
 
-#ifdef __KERNEL__
-/*
- * Function prototypes (all other prototypes included in udfdecl.h)
- */
-extern int init_udf_fs(void);
-
-#endif /* __KERNEL__ */
-
 #endif /* !defined(_LINUX_UDF_FS_H) */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/usb.h linux/include/linux/usb.h
--- v2.3.99-pre3/linux/include/linux/usb.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/usb.h	Tue Apr 11 09:57:43 2000
@@ -1,13 +1,6 @@
 #ifndef __LINUX_USB_H
 #define __LINUX_USB_H
 
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <linux/version.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>	/* for in_interrupt() */
-
 /* USB constants */
 
 /*
@@ -130,6 +123,12 @@
 
 #ifdef __KERNEL__
 
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>	/* for in_interrupt() */
 #include <linux/config.h>
 #include <linux/list.h>
 
@@ -364,10 +363,9 @@
  */
 typedef int (*usb_device_irq)(int, void *, int, void *);
 
-/* -------------------------------------------------------------------------------------* 
- * New USB Structures                                                                   *
- * -------------------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------* 
+ * New USB Structures                                                         *
+ *----------------------------------------------------------------------------*/
 
 #define USB_DISABLE_SPD         0x0001
 #define USB_ISO_ASAP            0x0002
@@ -499,7 +497,7 @@
 	usb_device_irq handler;
 };
 
-/* ------------------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
 struct usb_operations {
 	int (*allocate)(struct usb_device *);
@@ -712,6 +710,7 @@
  * Send and receive control messages..
  */
 int usb_new_device(struct usb_device *dev);
+int usb_reset_device(struct usb_device *dev);
 int usb_set_address(struct usb_device *dev);
 int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
 	unsigned char descindex, void *buf, int size);
diff -u --recursive --new-file v2.3.99-pre3/linux/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h
--- v2.3.99-pre3/linux/include/linux/usbdevice_fs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/usbdevice_fs.h	Mon Apr 10 22:55:08 2000
@@ -0,0 +1,170 @@
+/*****************************************************************************/
+
+/*
+ *	usbdevice_fs.h  --  USB device file system.
+ *
+ *	Copyright (C) 2000
+ *          Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  History:
+ *   0.1  04.01.2000  Created
+ *
+ *  $Id: usbdevice_fs.h,v 1.1 2000/01/06 18:40:41 tom Exp $
+ */
+
+/*****************************************************************************/
+
+#ifndef _LINUX_USBDEVICE_FS_H
+#define _LINUX_USBDEVICE_FS_H
+
+/* --------------------------------------------------------------------- */
+
+#define USBDEVICE_SUPER_MAGIC 0x9fa2
+
+/* usbdevfs ioctl codes */
+
+struct usbdevfs_ctrltransfer {
+	__u8 requesttype;
+	__u8 request;
+	__u16 value;
+	__u16 index;
+	__u16 length;
+	__u32 timeout;  /* in milliseconds */
+ 	void *data;
+};
+
+struct usbdevfs_bulktransfer {
+	unsigned int ep;
+	unsigned int len;
+	unsigned int timeout; /* in milliseconds */
+	void *data;
+};
+
+struct usbdevfs_setinterface {
+	unsigned int interface;
+	unsigned int altsetting;
+};
+
+struct usbdevfs_disconnectsignal {
+	unsigned int signr;
+	void *context;
+};
+
+#define USBDEVFS_URB_DISABLE_SPD           1
+#define USBDEVFS_URB_ISO_ASAP              2
+
+#define USBDEVFS_URB_TYPE_ISO		   0
+#define USBDEVFS_URB_TYPE_INTERRUPT	   1
+#define USBDEVFS_URB_TYPE_CONTROL	   2
+#define USBDEVFS_URB_TYPE_BULK		   3
+
+struct usbdevfs_iso_packet_desc {
+	unsigned int length;
+	unsigned int actual_length;
+	unsigned int status;
+};
+
+struct usbdevfs_urb {
+	unsigned char type;
+	unsigned char endpoint;
+	int status;
+	unsigned int flags;
+	void *buffer;
+	int buffer_length;
+	int actual_length;
+	int start_frame;
+	int number_of_packets;
+	int error_count;
+	unsigned int signr;  /* signal to be sent on error, -1 if none should be sent */
+	void *usercontext;
+	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+
+#define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
+#define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
+#define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
+#define USBDEVFS_SETINTERFACE      _IOR('U', 4, struct usbdevfs_setinterface)
+#define USBDEVFS_SETCONFIGURATION  _IOR('U', 5, unsigned int)
+#define USBDEVFS_SUBMITURB         _IOR('U', 10, struct usbdevfs_urb)
+#define USBDEVFS_DISCARDURB        _IO('U', 11)
+#define USBDEVFS_REAPURB           _IOW('U', 12, void *)
+#define USBDEVFS_REAPURBNDELAY     _IOW('U', 13, void *)
+#define USBDEVFS_DISCSIGNAL        _IOR('U', 14, struct usbdevfs_disconnectsignal)
+#define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
+#define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
+
+/* --------------------------------------------------------------------- */
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+#include <asm/semaphore.h>
+
+/*
+ * inode number macros
+ */
+#define ITYPE(x)   ((x)&(0xf<<28))
+#define ISPECIAL   (0<<28)
+#define IBUS       (1<<28)
+#define IDEVICE    (2<<28)
+#define IBUSNR(x)  (((x)>>8)&0xff)
+#define IDEVNR(x)  ((x)&0xff)
+
+#define IROOT      1
+
+/*
+ * sigh. rwsemaphores do not (yet) work from modules
+ */
+
+#define rw_semaphore semaphore
+#define init_rwsem init_MUTEX
+#define down_read down
+#define down_write down
+#define up_read up
+#define up_write up
+
+
+struct dev_state {
+	struct list_head list;      /* state list */
+	struct rw_semaphore devsem; /* protects modifications to dev (dev == NULL indicating disconnect) */ 
+	struct usb_device *dev;
+	struct file *file;
+	spinlock_t lock;            /* protects the async urb lists */
+	struct list_head async_pending;
+	struct list_head async_completed;
+	wait_queue_head_t wait;     /* wake up if a request completed */
+	unsigned int discsignr;
+	struct task_struct *disctask;
+	void *disccontext;
+	unsigned long ifclaimed;
+};
+
+/* internal methods & data */
+extern struct usb_driver usbdevfs_driver;
+extern struct file_operations usbdevfs_drivers_fops;
+extern struct file_operations usbdevfs_devices_fops;
+extern struct file_operations usbdevfs_device_file_operations;
+extern struct inode_operations usbdevfs_device_inode_operations;
+extern struct inode_operations usbdevfs_bus_inode_operations;
+extern struct file_operations usbdevfs_bus_file_operations;
+extern void usbdevfs_conn_disc_event(void);
+
+
+#endif /* __KERNEL__ */
+
+/* --------------------------------------------------------------------- */
+#endif /* _LINUX_USBDEVICE_FS_H */
diff -u --recursive --new-file v2.3.99-pre3/linux/include/net/sock.h linux/include/net/sock.h
--- v2.3.99-pre3/linux/include/net/sock.h	Thu Mar  2 14:36:23 2000
+++ linux/include/net/sock.h	Mon Apr 10 23:24:24 2000
@@ -263,10 +263,11 @@
 	__u16	mss_cache;	/* Cached effective mss, not including SACKS */
 	__u16	mss_clamp;	/* Maximal mss, negotiated at connection setup */
 	__u16	ext_header_len;	/* Network protocol overhead (IP/IPv6 options) */
-	__u8	dup_acks;	/* Consequetive duplicate acks seen from other end */
+	__u8	dup_acks;	/* Consecutive duplicate acks seen from other end */
 	__u8	retransmits;
 
-	__u16	__empty1;
+	__u8	__empty1;
+	__u8	sorry;
 	__u8	defer_accept;
 
 /* RTT measurement */
@@ -726,7 +727,7 @@
 	if ((__sk)->backlog.tail != NULL) \
 		__release_sock(__sk); \
 	(__sk)->lock.users = 0; \
-	wake_up(&((__sk)->lock.wq)); \
+        if (waitqueue_active(&((__sk)->lock.wq))) wake_up(&((__sk)->lock.wq)); \
 	spin_unlock_bh(&((__sk)->lock.slock)); \
 } while(0)
 
@@ -837,11 +838,19 @@
 extern void sklist_destroy_socket(struct sock **list, struct sock *sk);
 
 #ifdef CONFIG_FILTER
-/*
+
+/**
+ *	sk_filter - run a packet through a socket filter
+ *	@skb: buffer to filter
+ *	@filter: filter to apply
+ *
  * Run the filter code and then cut skb->data to correct size returned by
  * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller
- * than pkt_len we keep whole skb->data.
+ * than pkt_len we keep whole skb->data. This is the socket level
+ * wrapper to sk_run_filter. It returns 0 if the packet should
+ * be accepted or 1 if the packet should be tossed.
  */
+ 
 extern __inline__ int sk_filter(struct sk_buff *skb, struct sk_filter *filter)
 {
 	int pkt_len;
@@ -855,6 +864,14 @@
 	return 0;
 }
 
+/**
+ *	sk_filter_release: Release a socket filter
+ *	@sk: socket
+ *	@fp: filter to remove
+ *
+ *	Remove a filter from a socket and release its resources.
+ */
+ 
 extern __inline__ void sk_filter_release(struct sock *sk, struct sk_filter *fp)
 {
 	unsigned int size = sk_filter_len(fp);
@@ -1135,6 +1152,12 @@
 	return amt;
 }
 
+extern __inline__ void sk_wake_async(struct sock *sk, int how, int band)
+{
+	if (sk->socket && sk->socket->fasync_list)
+		sock_wake_async(sk->socket, how, band);
+}
+
 #define SOCK_MIN_SNDBUF 2048
 #define SOCK_MIN_RCVBUF 128
 /* Must be less or equal SOCK_MIN_SNDBUF */
@@ -1167,6 +1190,14 @@
 extern __inline__ int sock_rcvlowat(struct sock *sk, int waitall, int len)
 {
 	return waitall ? len : min(sk->rcvlowat, len);
+}
+
+/* Alas, with timeout socket operations are not restartable.
+ * Compare this to poll().
+ */
+extern __inline__ int sock_intr_errno(long timeo)
+{
+	return timeo == MAX_SCHEDULE_TIMEOUT ? -ERESTARTSYS : -EINTR;
 }
 
 /* 
diff -u --recursive --new-file v2.3.99-pre3/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.3.99-pre3/linux/include/net/tcp.h	Sun Mar 19 18:35:31 2000
+++ linux/include/net/tcp.h	Mon Apr 10 23:24:59 2000
@@ -669,8 +669,6 @@
 						  struct tcphdr *th, int len, 
 						  struct sk_buff *skb);
 
-extern void			tcp_v4_send_reset(struct sk_buff *skb);
-
 extern int			tcp_v4_conn_request(struct sock *sk,
 						    struct sk_buff *skb);
 
@@ -908,6 +906,13 @@
 
 #define TCP_SKB_CB(__skb)	((struct tcp_skb_cb *)&((__skb)->cb[0]))
 
+/*
+ *	Compute minimal free write space needed to queue new packets. 
+ */
+#define tcp_min_write_space(__sk) \
+	(atomic_read(&(__sk)->wmem_alloc) / 2)
+
+
 /* This determines how many packets are "in the network" to the best
  * of our knowledge.  In many cases it is conservative, but where
  * detailed information is available from the receiver (via SACK
@@ -1342,6 +1347,15 @@
 
 	if (sk->rcvbuf < 3*rcvbuf)
 		sk->rcvbuf = min (3*rcvbuf, sysctl_rmem_max);
+
+	/* Reserve slack space to reduce jitter of advertised window. */
+	if (tp->window_clamp >= tcp_full_space(sk)) {
+		int nwin = tcp_full_space(sk) - tp->mss_clamp;
+
+		if (nwin >= MAX_TCP_WINDOW && nwin >= 2*tp->advmss)
+			tp->window_clamp = nwin;
+	}
+
 	if (sk->sndbuf < 3*sndbuf)
 		sk->sndbuf = min (3*sndbuf, sysctl_wmem_max);
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.3.99-pre3/linux/include/scsi/sg.h	Tue Mar  7 14:32:26 2000
+++ linux/include/scsi/sg.h	Mon Mar 27 10:48:23 2000
@@ -11,9 +11,13 @@
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2000 Douglas Gilbert
 
-    Version: 3.1.12 (20000222)
+    Version: 3.1.13 (20000323)
     This version is for 2.3/2.4 series kernels.
 
+    Changes since 3.1.12 (20000222)
+    	- make sg_header interface use SCSI_DATA_UNKNOWN
+    	- add SG_DXFER_UNKNOWN define to sg interface
+    	- stop allocating data buffers to non data transfer commands
     Changes since 3.1.10 (20000123)
     	- make device allocation dynamic (get rid of SG_EXTRA_DEVS)
 	- move to sg0,sg1,sg2 rather than sga,sgb,sgc
@@ -147,6 +151,7 @@
 				   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 */
 
 /* following flag values can be "or"-ed together */
 #define SG_FLAG_DIRECT_IO 1     /* default is indirect IO */
diff -u --recursive --new-file v2.3.99-pre3/linux/init/main.c linux/init/main.c
--- v2.3.99-pre3/linux/init/main.c	Fri Mar 10 16:40:50 2000
+++ linux/init/main.c	Sun Apr  9 08:12:56 2000
@@ -510,16 +510,14 @@
 	kmem_cache_init();
 	sti();
 	calibrate_delay();
-#if 0000
 #ifdef CONFIG_BLK_DEV_INITRD
-	// FIXME, use the bootmem.h interface.
-	if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) {
+	if (initrd_start && !initrd_below_start_ok &&
+			initrd_start < min_low_pfn << PAGE_SHIFT) {
 		printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
-		    "disabling it.\n",initrd_start,memory_start);
+		    "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
 		initrd_start = 0;
 	}
 #endif
-#endif /* 0000 */
 	mem_init();
 	kmem_cache_sizes_init();
 #ifdef CONFIG_PROC_FS
@@ -571,14 +569,6 @@
 	(void) dup(0);
 	return execve(shell, argv, envp_init);
 }
-
-static int __init no_initrd(char *s)
-{
-	mount_initrd = 0;
-	return 1;
-}
-
-__setup("noinitrd", no_initrd);
 
 #endif
 
diff -u --recursive --new-file v2.3.99-pre3/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.99-pre3/linux/ipc/shm.c	Mon Mar 27 08:08:32 2000
+++ linux/ipc/shm.c	Sun Apr  9 08:14:23 2000
@@ -18,8 +18,9 @@
  * 1) It only can handle one directory.
  * 2) Because the directory is represented by the SYSV shm array it
  *    can only be mounted one time.
- * 3) Read and write are not implemented (should they?)
- * 4) No special nodes are supported
+ * 3) Private writeable mappings are not supported
+ * 4) Read and write are not implemented (should they?)
+ * 5) No special nodes are supported
  *
  * There are the following mount options:
  * - nr_blocks (^= shmall) is the number of blocks of size PAGE_SIZE
@@ -67,6 +68,13 @@
 #define SHM_FMT ".IPC_%08x"
 #define SHM_FMT_LEN 13
 
+/* shm_mode upper byte flags */
+/* SHM_DEST and SHM_LOCKED are used in ipcs(8) */
+#define PRV_DEST	0010000	/* segment will be destroyed on last detach */
+#define PRV_LOCKED	0020000	/* segment will not be swapped */
+#define SHM_UNLK	0040000	/* filename is unlinked */
+#define SHM_SYSV	0100000	/* It is a SYSV shm segment */
+
 struct shmid_kernel /* private to the kernel */
 {	
 	struct kern_ipc_perm	shm_perm;
@@ -82,7 +90,6 @@
 			time_t			ctime;
 			pid_t			cpid;
 			pid_t			lpid;
-			int			unlinked;
 			int			nlen;
 			char			nm[0];
 		} shmem;
@@ -100,7 +107,7 @@
 #define shm_lprid	permap.shmem.lpid
 #define shm_namelen	permap.shmem.nlen
 #define shm_name	permap.shmem.nm
-#define shm_unlinked	permap.shmem.unlinked
+#define shm_flags	shm_perm.mode
 #define zsem		permap.zero.sema
 #define zero_list	permap.zero.list
 
@@ -111,13 +118,11 @@
 #define shm_lockall()	ipc_lockall(&shm_ids)
 #define shm_unlockall()	ipc_unlockall(&shm_ids)
 #define shm_get(id)	((struct shmid_kernel*)ipc_get(&shm_ids,id))
-#define shm_checkid(s, id)	\
-	ipc_checkid(&shm_ids,&s->shm_perm,id)
 #define shm_buildid(id, seq) \
 	ipc_buildid(&shm_ids, id, seq)
 
 static int newseg (key_t key, const char *name, int namelen, int shmflg, size_t size);
-static void killseg_core(struct shmid_kernel *shp, int doacc);
+static void seg_free(struct shmid_kernel *shp, int doacc);
 static void shm_open (struct vm_area_struct *shmd);
 static void shm_close (struct vm_area_struct *shmd);
 static int shm_remove_name(int id);
@@ -316,6 +321,15 @@
 	return 0;
 }
 
+static inline int shm_checkid(struct shmid_kernel *s, int id)
+{
+	if (!(s->shm_flags & SHM_SYSV))
+		return -EINVAL;
+	if (ipc_checkid(&shm_ids,&s->shm_perm,id))
+		return -EIDRM;
+	return 0;
+}
+
 static inline struct shmid_kernel *shm_rmid(int id)
 {
 	return (struct shmid_kernel *)ipc_rmid(&shm_ids,id);
@@ -348,7 +362,7 @@
 			printk(KERN_DEBUG "shm_nattch = %ld\n", shp->shm_nattch);
 		shp = shm_rmid(i);
 		shm_unlock(i);
-		killseg_core(shp, 1);
+		seg_free(shp, 1);
 	}
 	dput (sb->s_root);
 	up(&shm_ids.sem);
@@ -383,7 +397,7 @@
 	if (id < SEQ_MULTIPLIER) {
 		if (!(shp = shm_lock (id)))
 			return;
-		inode->i_mode = shp->shm_perm.mode | S_IFREG;
+		inode->i_mode = (shp->shm_flags & S_IALLUGO) | S_IFREG;
 		inode->i_uid  = shp->shm_perm.uid;
 		inode->i_gid  = shp->shm_perm.gid;
 		inode->i_size = shp->shm_segsz;
@@ -455,7 +469,7 @@
 				continue;
 			if (!(shp = shm_get (nr-2))) 
 				continue;
-			if (shp->shm_unlinked)
+			if (shp->shm_flags & SHM_UNLK)
 				continue;
 			if (filldir(dirent, shp->shm_name, shp->shm_namelen, nr, nr) < 0 )
 				break;;
@@ -484,7 +498,7 @@
 			continue;
 		if (!(shp = shm_lock(i)))
 			continue;
-		if (!(shp->shm_unlinked) &&
+		if (!(shp->shm_flags & SHM_UNLK) &&
 		    dent->d_name.len == shp->shm_namelen &&
 		    strncmp(dent->d_name.name, shp->shm_name, shp->shm_namelen) == 0)
 			goto found;
@@ -522,8 +536,7 @@
 	down (&shm_ids.sem);
 	if (!(shp = shm_lock (inode->i_ino)))
 		BUG();
-	shp->shm_unlinked = 1;
-	shp->shm_perm.mode |= SHM_DEST;
+	shp->shm_flags |= SHM_UNLK | PRV_DEST;
 	shp->shm_perm.key = IPC_PRIVATE; /* Do not find it any more */
 	shm_unlock (inode->i_ino);
 	up (&shm_ids.sem);
@@ -542,7 +555,7 @@
 
 #define SHM_ENTRY(shp, index) (shp)->shm_dir[(index)/PTRS_PER_PTE][(index)%PTRS_PER_PTE]
 
-static pte_t **shm_alloc(unsigned long pages)
+static pte_t **shm_alloc(unsigned long pages, int doacc)
 {
 	unsigned short dir  = pages / PTRS_PER_PTE;
 	unsigned short last = pages % PTRS_PER_PTE;
@@ -572,6 +585,12 @@
 		for (pte = *ptr; pte < *ptr + last; pte++)
 			pte_clear (pte);
 	}
+	if (doacc) {
+		shm_lockall();
+		shm_tot += pages;
+		used_segs++;
+		shm_unlockall();
+	}
 	return ret;
 
 free:
@@ -584,13 +603,28 @@
 	return ERR_PTR(-ENOMEM);
 }
 
-static void shm_free(pte_t** dir, unsigned long pages)
+static void shm_free(pte_t** dir, unsigned long pages, int doacc)
 {
+	int i, rss, swp;
 	pte_t **ptr = dir+pages/PTRS_PER_PTE;
 
 	if (!dir)
 		return;
 
+	for (i = 0, rss = 0, swp = 0; i < pages ; i++) {
+		pte_t pte;
+		pte = dir[i/PTRS_PER_PTE][i%PTRS_PER_PTE];
+		if (pte_none(pte))
+			continue;
+		if (pte_present(pte)) {
+			__free_page (pte_page(pte));
+			rss++;
+		} else {
+			swap_free(pte_to_swp_entry(pte));
+			swp++;
+		}
+	}
+
 	/* first the last page */
 	if (pages%PTRS_PER_PTE)
 		kfree (*ptr);
@@ -601,6 +635,15 @@
 
 	/* Now the indirect block */
 	kfree (dir);
+
+	if (doacc) {
+		shm_lockall();
+		shm_rss -= rss;
+		shm_swp -= swp;
+		shm_tot -= pages;
+		used_segs--;
+		shm_unlockall();
+	}
 }
 
 static 	int shm_setattr (struct dentry *dentry, struct iattr *attr)
@@ -611,7 +654,8 @@
 	unsigned long new_pages, old_pages;
 	pte_t **new_dir, **old_dir;
 
-	if ((error = inode_change_ok(inode, attr)))
+	error = inode_change_ok(inode, attr);
+	if (error)
 		return error;
 	if (!(attr->ia_valid & ATTR_SIZE))
 		goto set_attr;
@@ -620,15 +664,19 @@
 
 	/* We set old_pages and old_dir for easier cleanup */
 	old_pages = new_pages = (attr->ia_size  + PAGE_SIZE - 1) >> PAGE_SHIFT;
-	if (shm_tot + new_pages >= shm_ctlall)
-		return -ENOSPC;
-	if (IS_ERR(old_dir = new_dir = shm_alloc(new_pages)))
+	old_dir = new_dir = shm_alloc(new_pages, 1);
+	if (IS_ERR(new_dir))
 		return PTR_ERR(new_dir);
 
 	if (!(shp = shm_lock(inode->i_ino)))
 		BUG();
+	error = -ENOSPC;
+	if (shm_tot - shp->shm_npages >= shm_ctlall)
+		goto out;
+	error = 0;
 	if (shp->shm_segsz == attr->ia_size)
 		goto out;
+	/* Now we set them to the real values */
 	old_dir = shp->shm_dir;
 	old_pages = shp->shm_npages;
 	if (old_dir){
@@ -650,16 +698,13 @@
 	shp->shm_segsz = attr->ia_size;
 out:
 	shm_unlock(inode->i_ino);
-	shm_lockall();
-	shm_tot += new_pages - old_pages;
-	shm_unlockall();
-	shm_free (old_dir, old_pages);
+	shm_free (old_dir, old_pages, 1);
 set_attr:
 	inode_setattr(inode, attr);
-	return 0;
+	return error;
 }
 
-static inline struct shmid_kernel *newseg_alloc(int numpages, size_t namelen)
+static struct shmid_kernel *seg_alloc(int numpages, size_t namelen)
 {
 	struct shmid_kernel *shp;
 	pte_t		   **dir;
@@ -668,7 +713,7 @@
 	if (!shp)
 		return ERR_PTR(-ENOMEM);
 
-	dir = shm_alloc (numpages);
+	dir = shm_alloc (numpages, namelen);
 	if (IS_ERR(dir)) {
 		kfree(shp);
 		return ERR_PTR(PTR_ERR(dir));
@@ -680,6 +725,12 @@
 	return(shp);
 }
 
+static void seg_free(struct shmid_kernel *shp, int doacc)
+{
+	shm_free (shp->shm_dir, shp->shm_npages, doacc);
+	kfree(shp);
+}
+
 static int newseg (key_t key, const char *name, int namelen,
 		   int shmflg, size_t size)
 {
@@ -696,32 +747,28 @@
 	if (shm_tot + numpages >= shm_ctlall)
 		return -ENOSPC;
 
-	if (!(shp = newseg_alloc(numpages, namelen ? namelen : SHM_FMT_LEN + 1)))
+	if (!(shp = seg_alloc(numpages, namelen ? namelen : SHM_FMT_LEN + 1)))
 		return -ENOMEM;
 	id = shm_addid(shp);
 	if(id == -1) {
-		shm_free(shp->shm_dir,numpages);
-		kfree(shp);
+		seg_free(shp, 1);
 		return -ENOSPC;
 	}
 	shp->shm_perm.key = key;
-	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
+	shp->shm_flags = (shmflg & S_IRWXUGO);
 	shp->shm_segsz = size;
 	shp->shm_cprid = current->pid;
 	shp->shm_lprid = 0;
 	shp->shm_atim = shp->shm_dtim = 0;
 	shp->shm_ctim = CURRENT_TIME;
 	shp->id = shm_buildid(id,shp->shm_perm.seq);
-	shp->shm_unlinked = 0;
 	if (namelen != 0) {
 		shp->shm_namelen = namelen;
 		memcpy (shp->shm_name, name, namelen);		  
 	} else {
+		shp->shm_flags |= SHM_SYSV;
 		shp->shm_namelen = sprintf (shp->shm_name, SHM_FMT, shp->id);
 	}
-
-	shm_tot += numpages;
-	used_segs++;
 	shm_unlock(id);
 	
 	return shp->id;
@@ -768,36 +815,6 @@
 	return err;
 }
 
-static void killseg_core(struct shmid_kernel *shp, int doacc)
-{
-	int i, numpages, rss, swp;
-
-	numpages = shp->shm_npages;
-	for (i = 0, rss = 0, swp = 0; i < numpages ; i++) {
-		pte_t pte;
-		pte = SHM_ENTRY (shp,i);
-		if (pte_none(pte))
-			continue;
-		if (pte_present(pte)) {
-			__free_page (pte_page(pte));
-			rss++;
-		} else {
-			swap_free(pte_to_swp_entry(pte));
-			swp++;
-		}
-	}
-	shm_free (shp->shm_dir, numpages);
-	kfree(shp);
-	if (doacc) {
-		shm_lockall();
-		shm_rss -= rss;
-		shm_swp -= swp;
-		shm_tot -= numpages;
-		used_segs--;
-		shm_unlockall();
-	}
-}
-
 static void shm_delete (struct inode *ino)
 {
 	int shmid = ino->i_ino;
@@ -811,7 +828,7 @@
 	shp = shm_rmid(shmid);
 	shm_unlock(shmid);
 	up(&shm_ids.sem);
-	killseg_core(shp, 1);
+	seg_free(shp, 1);
 	clear_inode(ino);
 }
 
@@ -858,7 +875,7 @@
 
 		out->uid	= tbuf.shm_perm.uid;
 		out->gid	= tbuf.shm_perm.gid;
-		out->mode	= tbuf.shm_perm.mode;
+		out->mode	= tbuf.shm_flags;
 
 		return 0;
 	    }
@@ -871,7 +888,7 @@
 
 		out->uid	= tbuf_old.shm_perm.uid;
 		out->gid	= tbuf_old.shm_perm.gid;
-		out->mode	= tbuf_old.shm_perm.mode;
+		out->mode	= tbuf_old.shm_flags;
 
 		return 0;
 	    }
@@ -975,12 +992,13 @@
 			return -EINVAL;
 		if(cmd==SHM_STAT) {
 			err = -EINVAL;
-			if (shmid > shm_ids.max_id)
+			if (!(shp->shm_flags & SHM_SYSV) ||
+			    shmid > shm_ids.max_id)
 				goto out_unlock;
 			result = shm_buildid(shmid, shp->shm_perm.seq);
 		} else {
-			err = -EIDRM;
-			if(shm_checkid(shp,shmid))
+			err = shm_checkid(shp,shmid);
+			if(err)
 				goto out_unlock;
 			result = 0;
 		}
@@ -988,6 +1006,13 @@
 		if (ipcperms (&shp->shm_perm, S_IRUGO))
 			goto out_unlock;
 		kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
+		/* ugly hack to keep binary compatibility for ipcs */
+		tbuf.shm_flags &= PRV_DEST | PRV_LOCKED | S_IRWXUGO;
+		if (tbuf.shm_flags & PRV_DEST)
+			tbuf.shm_flags |= SHM_DEST;
+		if (tbuf.shm_flags & PRV_LOCKED)
+			tbuf.shm_flags |= SHM_LOCKED;
+		tbuf.shm_flags &= SHM_DEST | SHM_LOCKED | S_IRWXUGO;
 		tbuf.shm_segsz	= shp->shm_segsz;
 		tbuf.shm_atime	= shp->shm_atim;
 		tbuf.shm_dtime	= shp->shm_dtim;
@@ -1006,7 +1031,6 @@
 /* Allow superuser to lock segment in memory */
 /* Should the pages be faulted in here or leave it to user? */
 /* need to determine interaction with current->swappable */
-		struct kern_ipc_perm *ipcp;
 		if ((shmid % SEQ_MULTIPLIER)== zero_id)
 			return -EINVAL;
 		if (!capable(CAP_IPC_LOCK))
@@ -1015,21 +1039,13 @@
 		shp = shm_lock(shmid);
 		if(shp==NULL)
 			return -EINVAL;
-		err=-EIDRM;
-		if(shm_checkid(shp,shmid))
+		err = shm_checkid(shp,shmid);
+		if(err)
 			goto out_unlock;
-		ipcp = &shp->shm_perm;
-		if(cmd==SHM_LOCK) {
-			if (!(ipcp->mode & SHM_LOCKED)) {
-				ipcp->mode |= SHM_LOCKED;
-				err = 0;
-			}
-		} else {
-			if (ipcp->mode & SHM_LOCKED) {
-				ipcp->mode &= ~SHM_LOCKED;
-				err = 0;
-			}
-		}
+		if(cmd==SHM_LOCK)
+			shp->shm_flags |= PRV_LOCKED;
+		else
+			shp->shm_flags &= ~PRV_LOCKED;
 		shm_unlock(shmid);
 		return err;
 	}
@@ -1053,9 +1069,10 @@
 			up(&shm_ids.sem);
 			return -EINVAL;
 		}
-		err = -EIDRM;
-		if (shm_checkid(shp, shmid) == 0) {
-			if (shp->shm_nattch == 0) {
+		err = shm_checkid(shp, shmid);
+		if (err == 0) {
+			if (shp->shm_nattch == 0 && 
+			    !(shp->shm_flags & SHM_UNLK)) {
 				int id=shp->id;
 				shm_unlock(shmid);
 				up(&shm_ids.sem);
@@ -1066,10 +1083,9 @@
 				 */
 				return shm_remove_name(id);
 			}
-			/* Do not find me any more */
-			shp->shm_perm.mode |= SHM_DEST;
-			shp->shm_perm.key = IPC_PRIVATE; /* Do not find it any more */
-			err = 0;
+			shp->shm_flags |= PRV_DEST;
+			/* Do not find it any more */
+			shp->shm_perm.key = IPC_PRIVATE;
 		}
 		/* Unlock */
 		shm_unlock(shmid);
@@ -1089,8 +1105,8 @@
 		err=-EINVAL;
 		if(shp==NULL)
 			goto out_up;
-		err=-EIDRM;
-		if(shm_checkid(shp,shmid))
+		err = shm_checkid(shp,shmid);
+		if(err)
 			goto out_unlock_up;
 		err=-EPERM;
 		if (current->euid != shp->shm_perm.uid &&
@@ -1101,7 +1117,7 @@
 
 		shp->shm_perm.uid = setbuf.uid;
 		shp->shm_perm.gid = setbuf.gid;
-		shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO)
+		shp->shm_flags = (shp->shm_flags & ~S_IRWXUGO)
 			| (setbuf.mode & S_IRWXUGO);
 		shp->shm_ctim = CURRENT_TIME;
 		break;
@@ -1146,6 +1162,7 @@
 /*
  * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
  */
+/* MOUNT_REWRITE: kernel vfsmnt of shmfs should be passed to __filp_open() */
 asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
 {
 	unsigned long addr;
@@ -1154,6 +1171,8 @@
 	unsigned long flags;
 	unsigned long prot;
 	unsigned long o_flags;
+	int acc_mode;
+	struct dentry *dentry;
 	char   name[SHM_FMT_LEN+1];
 
 	if (!shm_sb || (shmid % SEQ_MULTIPLIER) == zero_id)
@@ -1173,19 +1192,35 @@
 	if (shmflg & SHM_RDONLY) {
 		prot = PROT_READ;
 		o_flags = O_RDONLY;
+		acc_mode = MAY_READ;
 	} else {
 		prot = PROT_READ | PROT_WRITE;
 		o_flags = O_RDWR;
+		acc_mode = MAY_READ | MAY_WRITE;
 	}
 
 	sprintf (name, SHM_FMT, shmid);
 
 	lock_kernel();
-	file = filp_open(name, o_flags, 0, dget(shm_sb->s_root));
+	dentry = lookup_one(name, dget(lock_parent(shm_sb->s_root)));
+	unlock_dir(shm_sb->s_root);
+	err = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
+		goto bad_file;
+	err = -ENOENT;
+	if (!dentry->d_inode)
+		goto bad_file;
+	err = permission(dentry->d_inode, acc_mode);
+	if (err)
+		goto bad_file;
+	file = dentry_open(dentry, NULL, o_flags);
+	err = PTR_ERR(file);
 	if (IS_ERR (file))
 		goto bad_file;
+	down(&current->mm->mmap_sem);
 	*raddr = do_mmap (file, addr, file->f_dentry->d_inode->i_size,
 			  prot, flags, 0);
+	up(&current->mm->mmap_sem);
 	unlock_kernel();
 	if (IS_ERR(*raddr))
 		err = PTR_ERR(*raddr);
@@ -1196,7 +1231,7 @@
 
 bad_file:
 	unlock_kernel();
-	if ((err = PTR_ERR(file)) == -ENOENT)
+	if (err == -ENOENT)
 		return -EINVAL;
 	return err;
 }
@@ -1213,13 +1248,32 @@
  
 static int shm_remove_name(int id)
 {
-	int err;
+	struct dentry *dir;
+	struct dentry *dentry;
+	int error;
 	char name[SHM_FMT_LEN+1];
+
 	sprintf (name, SHM_FMT, id);
 	lock_kernel();
-	err = do_unlink (name, dget(shm_sb->s_root));
+	dir = lock_parent(shm_sb->s_root);
+	dentry = lookup_one(name, dget(dir));
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		/*
+		 * We have to do our own unlink to prevent the vfs
+		 * permission check. The SYSV IPC layer has already
+		 * checked the permissions which do not comply to the
+		 * vfs rules.
+		 */
+		struct inode *inode = dir->d_inode;
+		down(&inode->i_zombie);
+		error = shm_unlink(inode, dentry);
+		up(&inode->i_zombie);
+		dput(dentry);
+	}
+	unlock_dir(dir);
 	unlock_kernel();
-	return err;
+	return error;
 }
 
 /*
@@ -1239,7 +1293,9 @@
 	shp->shm_lprid = current->pid;
 	shp->shm_dtim = CURRENT_TIME;
 	shp->shm_nattch--;
-	if(shp->shm_nattch == 0 && shp->shm_perm.mode & SHM_DEST) {
+	if(shp->shm_nattch == 0 && 
+	   shp->shm_flags & PRV_DEST &&
+	   !(shp->shm_flags & SHM_UNLK)) {
 		int pid=shp->id;
 		int err;
 		shm_unlock(id);
@@ -1453,7 +1509,7 @@
 	shm_lockall();
 check_id:
 	shp = shm_get(swap_id);
-	if(shp==NULL || shp->shm_perm.mode & SHM_LOCKED) {
+	if(shp==NULL || shp->shm_flags & SHM_LOCKED) {
 next_id:
 		swap_idx = 0;
 		if (++swap_id > shm_ids.max_id) {
@@ -1571,7 +1627,7 @@
 			len += sprintf(buffer + len, format,
 				shp->shm_perm.key,
 				shm_buildid(i, shp->shm_perm.seq),
-				shp->shm_perm.mode,
+				shp->shm_flags,
 				shp->shm_segsz,
 				shp->shm_cprid,
 				shp->shm_lprid,
@@ -1585,7 +1641,7 @@
 				shp->shm_ctim,
 				shp->shm_namelen,
 				shp->shm_name,
-				shp->shm_unlinked ? " (deleted)" : "");
+				shp->shm_flags & SHM_UNLK ? " (deleted)" : "");
 			shm_unlock(i);
 
 			pos += len;
@@ -1637,6 +1693,7 @@
  * on the pseudo-file. This is possible because the open/close calls
  * are bracketed by the file count update calls.
  */
+/* MOUNT_REWRITE: set ->f_vfsmnt to shmfs one */
 static struct file *file_setup(struct file *fzero, struct shmid_kernel *shp)
 {
 	struct file *filp;
@@ -1654,6 +1711,7 @@
 		put_filp(filp);
 		return(0);
 	}
+	filp->f_vfsmnt = NULL;
 	d_instantiate(filp->f_dentry, inp);
 
 	/*
@@ -1674,10 +1732,10 @@
 
 	if (!vm_enough_memory((vma->vm_end - vma->vm_start) >> PAGE_SHIFT))
 		return -ENOMEM;
-	if (IS_ERR(shp = newseg_alloc((vma->vm_end - vma->vm_start) / PAGE_SIZE, 0)))
+	if (IS_ERR(shp = seg_alloc((vma->vm_end - vma->vm_start) / PAGE_SIZE, 0)))
 		return PTR_ERR(shp);
 	if ((filp = file_setup(vma->vm_file, shp)) == 0) {
-		killseg_core(shp, 0);
+		seg_free(shp, 0);
 		return -ENOMEM;
 	}
 	vma->vm_file = filp;
@@ -1719,7 +1777,7 @@
 						struct shmid_kernel, zero_list);
 		list_del(&shp->zero_list);
 		spin_unlock(&zmap_list_lock);
-		killseg_core(shp, 0);
+		seg_free(shp, 0);
 	}
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/kernel/acct.c linux/kernel/acct.c
--- v2.3.99-pre3/linux/kernel/acct.c	Sun Mar 19 18:35:31 2000
+++ linux/kernel/acct.c	Sun Apr  2 15:40:11 2000
@@ -36,8 +36,7 @@
  *  but this one obviously doesn't introduce deadlocks. Later. BTW, found
  *  one race (and leak) in BSD implementation.
  *  OK, that's better. ANOTHER race and leak in BSD variant. There always
- *  is one more bug... TODO: move filp_open into open.c and make
- *  parameters sysctl-controllable. 10/11/98, AV.
+ *  is one more bug... 10/11/98, AV.
  */
 
 #include <linux/config.h>
@@ -154,7 +153,7 @@
 		if (IS_ERR(tmp))
 			goto out;
 		/* Difference from BSD - they don't do O_APPEND */
-		file = filp_open(tmp, O_WRONLY|O_APPEND, 0, NULL);
+		file = filp_open(tmp, O_WRONLY|O_APPEND, 0);
 		putname(tmp);
 		if (IS_ERR(file)) {
 			error = PTR_ERR(file);
diff -u --recursive --new-file v2.3.99-pre3/linux/kernel/exit.c linux/kernel/exit.c
--- v2.3.99-pre3/linux/kernel/exit.c	Tue Mar 14 19:10:40 2000
+++ linux/kernel/exit.c	Sun Apr  2 15:49:08 2000
@@ -216,7 +216,9 @@
 		tsk->fs = NULL;
 		if (atomic_dec_and_test(&fs->count)) {
 			dput(fs->root);
+			mntput(fs->rootmnt);
 			dput(fs->pwd);
+			mntput(fs->pwdmnt);
 			kfree(fs);
 		}
 	}
@@ -414,12 +416,12 @@
 #ifdef CONFIG_BSD_PROCESS_ACCT
 	acct_process(code);
 #endif
-	task_lock(tsk);
 	sem_exit();
 	__exit_mm(tsk);
 	__exit_files(tsk);
 	__exit_fs(tsk);
 	__exit_sighand(tsk);
+	task_lock(tsk);
 	exit_thread();
 	tsk->state = TASK_ZOMBIE;
 	tsk->exit_code = code;
diff -u --recursive --new-file v2.3.99-pre3/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.99-pre3/linux/kernel/fork.c	Tue Mar 14 19:10:40 2000
+++ linux/kernel/fork.c	Sun Apr  2 15:49:09 2000
@@ -432,6 +432,8 @@
 	tsk->fs->umask = current->fs->umask;
 	tsk->fs->root = dget(current->fs->root);
 	tsk->fs->pwd = dget(current->fs->pwd);
+	tsk->fs->rootmnt = mntget(current->fs->rootmnt);
+	tsk->fs->pwdmnt = mntget(current->fs->pwdmnt);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/kernel/kmod.c linux/kernel/kmod.c
--- v2.3.99-pre3/linux/kernel/kmod.c	Sat Feb 12 11:22:11 2000
+++ linux/kernel/kmod.c	Sun Apr  2 15:49:09 2000
@@ -54,11 +54,15 @@
 	our_fs = current->fs;
 	dput(our_fs->root);
 	dput(our_fs->pwd);
+	mntput(our_fs->rootmnt);
+	mntput(our_fs->pwdmnt);
 
 	init_fs = init_task.fs;
 	our_fs->umask = init_fs->umask;
 	our_fs->root = dget(init_fs->root);
 	our_fs->pwd = dget(init_fs->pwd);
+	our_fs->rootmnt = mntget(init_fs->rootmnt);
+	our_fs->pwdmnt = mntget(init_fs->pwdmnt);
 
 	unlock_kernel();
 }
@@ -119,10 +123,20 @@
 	return ret;
 }
 
-/*
-	request_module: the function that everyone calls when they need
-	a module.
-*/
+/**
+ *	request_module - try to load a kernel module
+ *	@module_name: Name of module
+ *
+ * 	Load a module using the user mode module loader. The function returns
+ *	zero on success or a negative errno code on failure. Note that a
+ * 	successful module load does not mean the module did not then unload
+ *	and exit on an error of its own. Callers must check that the service
+ *	they requested is now available not blindly invoke it.
+ *
+ *	If module auto-loading support is disabled then this function
+ *	becomes a no-operation.
+ */
+ 
 int request_module(const char * module_name)
 {
 	int pid;
diff -u --recursive --new-file v2.3.99-pre3/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.99-pre3/linux/kernel/ksyms.c	Mon Mar 27 08:08:32 2000
+++ linux/kernel/ksyms.c	Fri Apr  7 13:38:00 2000
@@ -141,8 +141,9 @@
 EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(__namei);
 EXPORT_SYMBOL(lookup_dentry);
+EXPORT_SYMBOL(walk_init);
+EXPORT_SYMBOL(walk_name);
 EXPORT_SYMBOL(lookup_one);
-EXPORT_SYMBOL(__open_namei);
 EXPORT_SYMBOL(sys_close);
 EXPORT_SYMBOL(d_alloc_root);
 EXPORT_SYMBOL(d_delete);
@@ -153,7 +154,7 @@
 EXPORT_SYMBOL(d_instantiate);
 EXPORT_SYMBOL(d_alloc);
 EXPORT_SYMBOL(d_lookup);
-EXPORT_SYMBOL(d_path);
+EXPORT_SYMBOL(__d_path);
 EXPORT_SYMBOL(mark_buffer_dirty);
 EXPORT_SYMBOL(__mark_buffer_dirty);
 EXPORT_SYMBOL(__mark_inode_dirty);
diff -u --recursive --new-file v2.3.99-pre3/linux/kernel/panic.c linux/kernel/panic.c
--- v2.3.99-pre3/linux/kernel/panic.c	Thu Feb 10 17:11:23 2000
+++ linux/kernel/panic.c	Mon Apr 10 23:09:01 2000
@@ -8,6 +8,7 @@
  * This function is used through-out the kernel (including mm and fs)
  * to indicate a major problem.
  */
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
@@ -32,10 +33,24 @@
 
 __setup("panic=", panic_setup);
 
+/**
+ *	panic - halt the system
+ *	@fmt: The text string to print
+ *
+ *	Display a message, then unblank the console and perform
+ *	cleanups. Functions in the panic notifier list are called
+ *	after the filesystem cache is flushed (when possible).
+ *
+ *	This function never returns.
+ */
+ 
 NORET_TYPE void panic(const char * fmt, ...)
 {
 	static char buf[1024];
 	va_list args;
+#if defined(CONFIG_ARCH_S390)
+        unsigned long caller = (unsigned long) __builtin_return_address(0);
+#endif
 
 	va_start(args, fmt);
 	vsprintf(buf, fmt, args);
@@ -78,6 +93,9 @@
 		stop_a_enabled = 1;
 		printk("Press L1-A to return to the boot prom\n");
 	}
+#endif
+#if defined(CONFIG_ARCH_S390)
+        disabled_wait(caller);
 #endif
 	sti();
 	for(;;) {
diff -u --recursive --new-file v2.3.99-pre3/linux/kernel/sched.c linux/kernel/sched.c
--- v2.3.99-pre3/linux/kernel/sched.c	Mon Mar 27 08:08:32 2000
+++ linux/kernel/sched.c	Mon Mar 27 10:42:45 2000
@@ -405,6 +405,7 @@
  */
 static inline void __schedule_tail(struct task_struct *prev)
 {
+	current->need_resched |= prev->need_resched;
 #ifdef __SMP__
 	if ((prev->state == TASK_RUNNING) &&
 			(prev != idle_task(smp_processor_id()))) {
diff -u --recursive --new-file v2.3.99-pre3/linux/mm/bootmem.c linux/mm/bootmem.c
--- v2.3.99-pre3/linux/mm/bootmem.c	Sat Feb 26 22:32:07 2000
+++ linux/mm/bootmem.c	Sun Apr  9 08:12:56 2000
@@ -24,6 +24,7 @@
  * true for the boot process anyway)
  */
 unsigned long max_low_pfn;
+unsigned long min_low_pfn;
 
 /* return the number of _pages_ that will be allocated for the boot bitmap */
 unsigned long __init bootmem_bootmap_pages (unsigned long pages)
@@ -282,6 +283,7 @@
 unsigned long __init init_bootmem (unsigned long start, unsigned long pages)
 {
 	max_low_pfn = pages;
+	min_low_pfn = start;
 	return(init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages));
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.99-pre3/linux/mm/filemap.c	Mon Mar 27 08:08:33 2000
+++ linux/mm/filemap.c	Mon Apr  3 16:18:56 2000
@@ -250,6 +250,11 @@
 		count--;
 
 		dispose = &young;
+
+		/* avoid unscalable SMP locking */
+		if (!page->buffers && page_count(page) > 1)
+			goto dispose_continue;
+
 		if (TryLockPage(page))
 			goto dispose_continue;
 
@@ -260,22 +265,11 @@
 		   page locked down ;). */
 		spin_unlock(&pagemap_lru_lock);
 
-		/* avoid unscalable SMP locking */
-		if (!page->buffers && page_count(page) > 1)
-			goto unlock_noput_continue;
-
-		/* Take the pagecache_lock spinlock held to avoid
-		   other tasks to notice the page while we are looking at its
-		   page count. If it's a pagecache-page we'll free it
-		   in one atomic transaction after checking its page count. */
-		spin_lock(&pagecache_lock);
-
 		/* avoid freeing the page while it's locked */
 		get_page(page);
 
 		/* Is it a buffer page? */
 		if (page->buffers) {
-			spin_unlock(&pagecache_lock);
 			if (!try_to_free_buffers(page))
 				goto unlock_continue;
 			/* page was locked, inode can't go away under us */
@@ -283,9 +277,14 @@
 				atomic_dec(&buffermem_pages);
 				goto made_buffer_progress;
 			}
-			spin_lock(&pagecache_lock);
 		}
 
+		/* Take the pagecache_lock spinlock held to avoid
+		   other tasks to notice the page while we are looking at its
+		   page count. If it's a pagecache-page we'll free it
+		   in one atomic transaction after checking its page count. */
+		spin_lock(&pagecache_lock);
+
 		/*
 		 * We can't free pages unless there's just one user
 		 * (count == 2 because we added one ourselves above).
@@ -294,12 +293,6 @@
 			goto cache_unlock_continue;
 
 		/*
-		 * We did the page aging part.
-		 */
-		if (nr_lru_pages < freepages.min * priority)
-			goto cache_unlock_continue;
-
-		/*
 		 * Is it a page swap page? If so, we want to
 		 * drop it if it is no longer used, even if it
 		 * were to be marked referenced..
@@ -312,8 +305,7 @@
 
 		/* is it a page-cache page? */
 		if (page->mapping) {
-			if (!pgcache_under_min())
-			{
+			if (!PageDirty(page) && !pgcache_under_min()) {
 				remove_page_from_inode_queue(page);
 				remove_page_from_hash_queue(page);
 				page->mapping = NULL;
@@ -329,21 +321,12 @@
 cache_unlock_continue:
 		spin_unlock(&pagecache_lock);
 unlock_continue:
+		spin_lock(&pagemap_lru_lock);
 		UnlockPage(page);
 		put_page(page);
-dispose_relock_continue:
-		/* even if the dispose list is local, a truncate_inode_page()
-		   may remove a page from its queue so always
-		   synchronize with the lru lock while accesing the
-		   page->lru field */
-		spin_lock(&pagemap_lru_lock);
 		list_add(page_lru, dispose);
 		continue;
 
-unlock_noput_continue:
-		UnlockPage(page);
-		goto dispose_relock_continue;
-
 dispose_continue:
 		list_add(page_lru, dispose);
 	}
@@ -484,7 +467,7 @@
 	struct page *alias;
 	unsigned long flags;
 
-	flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error));
+	flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty));
 	page->flags = flags | (1 << PG_locked) | (1 << PG_referenced);
 	get_page(page);
 	page->index = offset;
@@ -1724,10 +1707,8 @@
 		error = vma->vm_ops->sync(vma, start, end-start, flags);
 		if (!error && (flags & MS_SYNC)) {
 			struct file * file = vma->vm_file;
-			if (file) {
-				struct dentry * dentry = file->f_dentry;
-				error = file_fsync(file, dentry);
-			}
+			if (file)
+				error = file_fsync(file, file->f_dentry);
 		}
 		return error;
 	}
@@ -2237,9 +2218,9 @@
 
 	down(&current->mm->mmap_sem);
 
-	if (start & ~PAGE_MASK)
+	if (start & ~PAGE_CACHE_MASK)
 		goto out;
-	len = (len + ~PAGE_MASK) & PAGE_MASK;
+	len = (len + ~PAGE_CACHE_MASK) & PAGE_CACHE_MASK;
 	end = start + len;
 	if (end < start)
 		goto out;
@@ -2371,8 +2352,7 @@
 }
 
 /*
- * Write to a file through the page cache. This is mainly for the
- * benefit of NFS and possibly other network-based file systems.
+ * Write to a file through the page cache. 
  *
  * We currently put everything into the page cache prior to writing it.
  * This is not a problem when writing full pages. With partial pages,
@@ -2389,8 +2369,7 @@
 ssize_t
 generic_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
 {
-	struct dentry	*dentry = file->f_dentry; 
-	struct inode	*inode = dentry->d_inode; 
+	struct inode	*inode = file->f_dentry->d_inode; 
 	struct address_space *mapping = inode->i_mapping;
 	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 	loff_t		pos;
diff -u --recursive --new-file v2.3.99-pre3/linux/mm/memory.c linux/mm/memory.c
--- v2.3.99-pre3/linux/mm/memory.c	Mon Mar 27 08:08:33 2000
+++ linux/mm/memory.c	Mon Apr  3 16:29:15 2000
@@ -1053,7 +1053,7 @@
 
 	pte = mk_pte(page, vma->vm_page_prot);
 
-	set_bit(PG_swap_entry, &page->flags);
+	SetPageSwapEntry(page);
 
 	/*
 	 * Freeze the "shared"ness of the page, ie page_count + swap_count.
diff -u --recursive --new-file v2.3.99-pre3/linux/mm/numa.c linux/mm/numa.c
--- v2.3.99-pre3/linux/mm/numa.c	Sat Feb 12 11:22:11 2000
+++ linux/mm/numa.c	Mon Mar 27 10:24:56 2000
@@ -22,10 +22,11 @@
  * Should be invoked with paramters (0, 0, unsigned long *[], start_paddr).
  */
 void __init free_area_init_node(int nid, pg_data_t *pgdat, 
-		unsigned long *zones_size, unsigned long zone_start_paddr)
+	unsigned long *zones_size, unsigned long zone_start_paddr, 
+	unsigned long *zholes_size)
 {
 	free_area_init_core(0, NODE_DATA(0), &mem_map, zones_size, 
-							zone_start_paddr);
+						zone_start_paddr, zholes_size);
 }
 
 #endif /* !CONFIG_DISCONTIGMEM */
@@ -55,7 +56,8 @@
  * Nodes can be initialized parallely, in no particular order.
  */
 void __init free_area_init_node(int nid, pg_data_t *pgdat, 
-		unsigned long *zones_size, unsigned long zone_start_paddr)
+	unsigned long *zones_size, unsigned long zone_start_paddr, 
+	unsigned long *zholes_size)
 {
 	int i, size = 0;
 	struct page *discard;
@@ -63,7 +65,8 @@
 	if (mem_map == (mem_map_t *)NULL)
 		mem_map = (mem_map_t *)PAGE_OFFSET;
 
-	free_area_init_core(nid, pgdat, &discard, zones_size, zone_start_paddr);
+	free_area_init_core(nid, pgdat, &discard, zones_size, zone_start_paddr,
+						zholes_size);
 	pgdat->node_id = nid;
 
 	/*
diff -u --recursive --new-file v2.3.99-pre3/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.3.99-pre3/linux/mm/page_alloc.c	Mon Mar 27 08:08:33 2000
+++ linux/mm/page_alloc.c	Tue Apr  4 14:37:53 2000
@@ -100,12 +100,16 @@
 
 	if (page->buffers)
 		BUG();
+	if (page->mapping)
+		BUG();
 	if (page-mem_map >= max_mapnr)
 		BUG();
 	if (PageSwapCache(page))
 		BUG();
 	if (PageLocked(page))
 		BUG();
+	if (PageDecrAfter(page))
+		BUG();
 
 	zone = page->zone;
 
@@ -487,12 +491,13 @@
  *   - clear the memory bitmaps
  */
 void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
-	unsigned long *zones_size, unsigned long zone_start_paddr)
+	unsigned long *zones_size, unsigned long zone_start_paddr, 
+	unsigned long *zholes_size)
 {
 	struct page *p, *lmem_map;
 	unsigned long i, j;
 	unsigned long map_size;
-	unsigned long totalpages, offset;
+	unsigned long totalpages, offset, realtotalpages;
 	unsigned int cumulative = 0;
 
 	pgdat->node_next = pgdat_list;
@@ -503,7 +508,12 @@
 		unsigned long size = zones_size[i];
 		totalpages += size;
 	}
-	printk("On node %d totalpages: %lu\n", nid, totalpages);
+	realtotalpages = totalpages;
+	if (zholes_size)
+		for (i = 0; i < MAX_NR_ZONES; i++)
+			realtotalpages -= zholes_size[i];
+			
+	printk("On node %d totalpages: %lu\n", nid, realtotalpages);
 
 	/*
 	 * Select nr of pages we try to keep free for important stuff
@@ -512,7 +522,7 @@
 	 * This is fairly arbitrary, but based on some behaviour
 	 * analysis.
 	 */
-	i = totalpages >> 7;
+	i = realtotalpages >> 7;
 	if (i < 10)
 		i = 10;
 	if (i > 256)
@@ -553,21 +563,24 @@
 	for (j = 0; j < MAX_NR_ZONES; j++) {
 		zone_t *zone = pgdat->node_zones + j;
 		unsigned long mask;
-		unsigned long size;
+		unsigned long size, realsize;
 
-		size = zones_size[j];
+		realsize = size = zones_size[j];
+		if (zholes_size)
+			realsize -= zholes_size[j];
 
 		printk("zone(%lu): %lu pages.\n", j, size);
 		zone->size = size;
 		zone->name = zone_names[j];
 		zone->lock = SPIN_LOCK_UNLOCKED;
 		zone->zone_pgdat = pgdat;
+		zone->free_pages = 0;
 		if (!size)
 			continue;
 
 		zone->offset = offset;
 		cumulative += size;
-		mask = (size / zone_balance_ratio[j]);
+		mask = (realsize / zone_balance_ratio[j]);
 		if (mask < zone_balance_min[j])
 			mask = zone_balance_min[j];
 		else if (mask > zone_balance_max[j])
@@ -611,7 +624,7 @@
 
 void __init free_area_init(unsigned long *zones_size)
 {
-	free_area_init_core(0, NODE_DATA(0), &mem_map, zones_size, 0);
+	free_area_init_core(0, NODE_DATA(0), &mem_map, zones_size, 0, 0);
 }
 
 static int __init setup_mem_frac(char *str)
diff -u --recursive --new-file v2.3.99-pre3/linux/mm/slab.c linux/mm/slab.c
--- v2.3.99-pre3/linux/mm/slab.c	Thu Feb 10 17:11:23 2000
+++ linux/mm/slab.c	Mon Apr 10 10:12:15 2000
@@ -127,7 +127,7 @@
  * SLAB_SELFTEST	- 1 to perform a few tests, mainly for development.
  */
 #define		SLAB_MGMT_CHECKS	1
-#define		SLAB_DEBUG_SUPPORT	0
+#define		SLAB_DEBUG_SUPPORT	1
 #define		SLAB_STATS		0
 #define		SLAB_SELFTEST		0
 
@@ -1019,6 +1019,16 @@
 		slabp = cachep->c_lastp;
 		if (slabp->s_inuse || slabp == kmem_slab_end(cachep))
 			break;
+		/*
+		 * If this slab is the first slab with free objects
+		 * (c_freep), and as we are walking the slab chain
+		 * backwards, it is also the last slab with free
+		 * objects.  After unlinking it, there will be no
+		 * slabs with free objects, so point c_freep into the
+		 * cache structure.
+		 */
+		if (cachep->c_freep == slabp)
+			cachep->c_freep = kmem_slab_end(cachep);
 		kmem_slab_unlink(slabp);
 		spin_unlock_irq(&cachep->c_spinlock);
 		kmem_slab_destroy(cachep, slabp);
diff -u --recursive --new-file v2.3.99-pre3/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.3.99-pre3/linux/mm/swap_state.c	Tue Dec  7 09:32:52 1999
+++ linux/mm/swap_state.c	Tue Apr  4 14:36:13 2000
@@ -88,6 +88,9 @@
  */
 void delete_from_swap_cache_nolock(struct page *page)
 {
+	if (!PageLocked(page))
+		BUG();
+
 	if (block_flushpage(page, 0))
 		lru_cache_del(page);
 
@@ -122,8 +125,8 @@
 		}
 		UnlockPage(page);
 	}
-	
-	clear_bit(PG_swap_entry, &page->flags);
+
+	ClearPageSwapEntry(page);
 
 	__free_page(page);
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.3.99-pre3/linux/mm/swapfile.c	Wed Feb 16 17:03:52 2000
+++ linux/mm/swapfile.c	Mon Apr  3 16:31:42 2000
@@ -207,7 +207,7 @@
 	unsigned long offset, type;
 	swp_entry_t entry;
 
-	if (!test_bit(PG_swap_entry, &page->flags))
+	if (!PageSwapEntry(page))
 		goto new_swap_entry;
 
 	/* We have the old entry in the page offset still */
@@ -538,7 +538,7 @@
 	len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n");
 	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
 		if (ptr->flags & SWP_USED) {
-			char * path = d_path(ptr->swap_file, page, PAGE_SIZE);
+			char * path = d_path(ptr->swap_file, NULL, page, PAGE_SIZE);
 
 			len += sprintf(buf + len, "%-31s ", path);
 
diff -u --recursive --new-file v2.3.99-pre3/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.3.99-pre3/linux/mm/vmscan.c	Mon Mar 27 08:08:33 2000
+++ linux/mm/vmscan.c	Sun Mar 26 22:00:36 2000
@@ -499,19 +499,19 @@
 		 * the processes needing more memory will wake us
 		 * up on a more timely basis.
 		 */
-		do {
-			pgdat = pgdat_list;
-			while (pgdat) {
-				for (i = 0; i < MAX_NR_ZONES; i++) {
-					zone = pgdat->node_zones + i;
-					if ((!zone->size) || (!zone->zone_wake_kswapd))
-						continue;
-					do_try_to_free_pages(GFP_KSWAPD, zone);
-				}
-				pgdat = pgdat->node_next;
+		pgdat = pgdat_list;
+		while (pgdat) {
+			for (i = 0; i < MAX_NR_ZONES; i++) {
+				zone = pgdat->node_zones + i;
+				if (tsk->need_resched)
+					schedule();
+				if ((!zone->size) || (!zone->zone_wake_kswapd))
+					continue;
+				do_try_to_free_pages(GFP_KSWAPD, zone);
 			}
-			run_task_queue(&tq_disk);
-		} while (!tsk->need_resched);
+			pgdat = pgdat->node_next;
+		}
+		run_task_queue(&tq_disk);
 		tsk->state = TASK_INTERRUPTIBLE;
 		interruptible_sleep_on(&kswapd_wait);
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/net/Config.in linux/net/Config.in
--- v2.3.99-pre3/linux/net/Config.in	Sun Mar 19 18:35:31 2000
+++ linux/net/Config.in	Mon Mar 27 10:35:56 2000
@@ -13,9 +13,9 @@
    tristate '  Netlink device emulation' CONFIG_NETLINK_DEV
 fi
 bool 'Network packet filtering (replaces ipchains)' CONFIG_NETFILTER
-#if [ "$CONFIG_NETFILTER" = "y" ]; then
-#   bool '  Network packet filtering debugging' CONFIG_NETFILTER_DEBUG
-#fi
+if [ "$CONFIG_NETFILTER" = "y" ]; then
+   bool '  Network packet filtering debugging' CONFIG_NETFILTER_DEBUG
+fi
 bool 'Socket Filtering'  CONFIG_FILTER
 tristate 'Unix domain sockets' CONFIG_UNIX
 bool 'TCP/IP networking' CONFIG_INET
diff -u --recursive --new-file v2.3.99-pre3/linux/net/Makefile linux/net/Makefile
--- v2.3.99-pre3/linux/net/Makefile	Sun Mar 19 18:35:31 2000
+++ linux/net/Makefile	Mon Mar 27 10:35:56 2000
@@ -10,7 +10,7 @@
 MOD_SUB_DIRS := ipv4
 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \
 		netrom rose lapb x25 wanrouter netlink sched packet sunrpc \
-		econet irda decnet atm khttpd
+		econet irda decnet atm khttpd ipv4/netfilter
 SUB_DIRS     := core ethernet sched
 MOD_LIST_NAME := NET_MISC_MODULES
 
diff -u --recursive --new-file v2.3.99-pre3/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.3.99-pre3/linux/net/bridge/br.c	Mon Mar 27 08:08:33 2000
+++ linux/net/bridge/br.c	Mon Mar 27 10:35:56 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br.c,v 1.40 2000/03/21 21:08:47 davem Exp $
+ *	$Id: br.c,v 1.41 2000/03/24 01:33:36 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
diff -u --recursive --new-file v2.3.99-pre3/linux/net/bridge/br_input.c linux/net/bridge/br_input.c
--- v2.3.99-pre3/linux/net/bridge/br_input.c	Mon Mar 27 08:08:33 2000
+++ linux/net/bridge/br_input.c	Thu Mar 30 16:54:53 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_input.c,v 1.4 2000/03/21 21:08:47 davem Exp $
+ *	$Id: br_input.c,v 1.5 2000/03/30 01:22:23 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -94,6 +94,8 @@
 		br_flood(br, skb, 1);
 		if (!passedup)
 			br_pass_frame_up(br, skb);
+		else
+			kfree_skb(skb);
 		return;
 	}
 
@@ -102,6 +104,8 @@
 	if (dst != NULL && dst->is_local) {
 		if (!passedup)
 			br_pass_frame_up(br, skb);
+		else
+			kfree_skb(skb);
 		br_fdb_put(dst);
 		return;
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/net/core/datagram.c linux/net/core/datagram.c
--- v2.3.99-pre3/linux/net/core/datagram.c	Fri Jan 28 15:09:09 2000
+++ linux/net/core/datagram.c	Mon Mar 27 10:35:56 2000
@@ -87,9 +87,8 @@
 		goto out;
 
 	/* handle signals */
-	error = -ERESTARTSYS;
 	if (signal_pending(current))
-		goto out;
+		goto interrupted;
 
 	*timeo_p = schedule_timeout(*timeo_p);
 
@@ -98,6 +97,8 @@
 	remove_wait_queue(sk->sleep, &wait);
 	return 0;
 
+interrupted:
+	error = sock_intr_errno(*timeo_p);
 out:
 	current->state = TASK_RUNNING;
 	remove_wait_queue(sk->sleep, &wait);
@@ -248,7 +249,7 @@
 	if (sock_writeable(sk))
 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 	else
-		sk->socket->flags |= SO_NOSPACE;
+		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 
 	return mask;
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/net/core/dev.c linux/net/core/dev.c
--- v2.3.99-pre3/linux/net/core/dev.c	Mon Mar 27 08:08:33 2000
+++ linux/net/core/dev.c	Mon Mar 27 14:17:05 2000
@@ -176,6 +176,15 @@
  *	change it and subsequent readers will get broken packet.
  *							--ANK (980803)
  */
+
+/**
+ *	dev_add_pack - add packet handler
+ *	@pt: packet type declaration
+ * 
+ *	Add a protocol handler to the networking stack. The passed packet_type
+ *	is linked into kernel lists and may not be freed until it has been
+ *	removed from the kernel lists.
+ */
  
 void dev_add_pack(struct packet_type *pt)
 {
@@ -203,8 +212,14 @@
 }
 
 
-/*
- *	Remove a protocol ID from the list.
+/**
+ *	dev_remove_pack	 - remove packet handler
+ *	@pt: packet type declaration
+ * 
+ *	Remove a protocol handler that was previously added to the kernel
+ *	protocol handlers by dev_add_pack. The passed packet_type is removed
+ *	from the kernel lists and can be freed or reused once this function
+ *	returns.
  */
  
 void dev_remove_pack(struct packet_type *pt)
@@ -241,9 +256,15 @@
 
 ******************************************************************************************/
 
-/* 
- *	Find an interface by name. May be called under rtnl semaphore
- *	or dev_base_lock.
+/**
+ *	__dev_get_by_name	- find a device by its name 
+ *	@name: name to find
+ *
+ *	Find an interface by name. Must be called under rtnl semaphore
+ *	or dev_base_lock. If the name is found a pointer to the device
+ *	is returned. If the name is not found then NULL is returned. The
+ *	reference counters are not incremented so the caller must be
+ *	careful with locks.
  */
  
 
@@ -258,8 +279,15 @@
 	return NULL;
 }
 
-/* 
- *	Find an interface by name. Any context, dev_put() to release.
+/**
+ *	dev_get_by_name		- find a device by its name
+ *	@name: name to find
+ *
+ *	Find an interface by name. This can be called from any 
+ *	context and does its own locking. The returned handle has
+ *	the usage count incremented and the caller must use dev_put() to
+ *	release it when it is no longer needed. NULL is returned if no
+ *	matching device is found.
  */
 
 struct net_device *dev_get_by_name(const char *name)
@@ -282,6 +310,18 @@
    is meaningless, if it was not issued under rtnl semaphore.
  */
 
+/**
+ *	dev_get	-	test if a device exists
+ *	@name:	name to test for
+ *
+ *	Test if a name exists. Returns true if the name is found. In order
+ *	to be sure the name is not allocated or removed during the test the
+ *	caller must hold the rtnl semaphore.
+ *
+ *	This function primarily exists for back compatibility with older
+ *	drivers. 
+ */
+ 
 int dev_get(const char *name)
 {
 	struct net_device *dev;
@@ -292,8 +332,14 @@
 	return dev != NULL;
 }
 
-/* 
- *	Find an interface by index. May be called under rtnl semaphore
+/**
+ *	__dev_get_by_index - find a device by its ifindex
+ *	@ifindex: index of device
+ *
+ *	Search for an interface by index. Returns NULL if the device
+ *	is not found or a pointer to the device. The device has not
+ *	had its reference counter increased so the caller must be careful
+ *	about locking. The caller must hold either the rtnl semaphore
  *	or dev_base_lock.
  */
 
@@ -308,8 +354,15 @@
 	return NULL;
 }
 
-/* 
- *	Find an interface by index. Any context, dev_put() to release.
+
+/**
+ *	dev_get_by_index - find a device by its ifindex
+ *	@ifindex: index of device
+ *
+ *	Search for an interface by index. Returns NULL if the device
+ *	is not found or a pointer to the device. The device returned has 
+ *	had a reference added and the pointer is safe until the user calls
+ *	dev_put to indicate they have finished with it.
  */
 
 struct net_device * dev_get_by_index(int ifindex)
@@ -324,8 +377,18 @@
 	return dev;
 }
 
-/* 
- *	Find an interface by ll addr. May be called only under rtnl semaphore.
+/**
+ *	dev_getbyhwaddr - find a device by its hardware addres
+ *	@type: media type of device
+ *	@ha: hardware address
+ *
+ *	Search for an interface by MAC address. Returns NULL if the device
+ *	is not found or a pointer to the device. The caller must hold the
+ *	rtnl semaphore. The returned device has not had its ref count increased
+ *	and the caller must therefore be careful about locking
+ *
+ *	BUGS:
+ *	If the API was consistent this would be __dev_get_by_hwaddr
  */
 
 struct net_device *dev_getbyhwaddr(unsigned short type, char *ha)
@@ -342,9 +405,16 @@
 	return NULL;
 }
 
-/*
+/**
+ *	dev_alloc_name - allocate a name for a device
+ *	@dev: device 
+ *	@name: name format string
+ *
  *	Passed a format string - eg "lt%d" it will try and find a suitable
- *	id. Not efficient for many devices, not called a lot..
+ *	id. Not efficient for many devices, not called a lot. The caller
+ *	must hold the dev_base or rtnl lock while allocating the name and
+ *	adding the device in order to avoid duplicates. Returns the number
+ *	of the unit assigned or a negative errno code.
  */
 
 int dev_alloc_name(struct net_device *dev, const char *name)
@@ -365,6 +435,22 @@
 	return -ENFILE;	/* Over 100 of the things .. bail out! */
 }
 
+/**
+ *	dev_alloc - allocate a network device and name
+ *	@name: name format string
+ *	@err: error return pointer
+ *
+ *	Passed a format string - eg "lt%d" it will allocate a network device
+ *	and space for the name. NULL is returned if no memory is available.
+ *	If the allocation succeeds then the name is assigned and the 
+ *	device pointer returned. NULL is returned if the name allocation failed.
+ *	The cause of an error is returned as a negative errno code in the 
+ *	variable err points to.
+ *
+ *	The claler must hold the dev_base or rtnl locks when doing this in order
+ *	to avoid duplicate name allocations.
+ */
+
 struct net_device *dev_alloc(const char *name, int *err)
 {
 	struct net_device *dev=kmalloc(sizeof(struct net_device)+16, GFP_KERNEL);
@@ -382,6 +468,15 @@
 	return dev;
 }
 
+/**
+ *	netdev_state_change - device changes state
+ *	@dev: device to cause notification
+ *
+ *	Called to indicate a device has changed state. This function calls
+ *	the notifier chains for netdev_chain and sends a NEWLINK message
+ *	to the routing socket.
+ */
+ 
 void netdev_state_change(struct net_device *dev)
 {
 	if (dev->flags&IFF_UP) {
@@ -391,12 +486,17 @@
 }
 
 
-/*
- *	Find and possibly load an interface.
- */
- 
 #ifdef CONFIG_KMOD
 
+/**
+ *	dev_load 	- load a network module
+ *	@name: name of interface
+ *
+ *	If a network interface is not present and the process has suitable
+ *	privileges this function loads the module. If module loading is not
+ *	available in this kernel then it becomes a nop.
+ */
+
 void dev_load(const char *name)
 {
 	if (!__dev_get_by_name(name) && capable(CAP_SYS_MODULE))
@@ -416,8 +516,17 @@
 	return 1;
 }
 
-/*
- *	Prepare an interface for use. 
+/**
+ *	dev_open	- prepare an interface for use. 
+ *	@dev:	device to open
+ *
+ *	Takes a device from down to up state. The devices private open
+ *	function is invoked and then the multicast lists are loaded. Finally
+ *	the device is moved into the up state and a NETDEV_UP message is
+ *	sent to the netdev notifier chain.
+ *
+ *	Calling this function on an active interface is a nop. On a failure
+ *	a negative errno code is returned.
  */
  
 int dev_open(struct net_device *dev)
@@ -508,8 +617,14 @@
 }
 #endif
 
-/*
- *	Completely shutdown an interface.
+/**
+ *	dev_close - shutdown an interface.
+ *	@dev: device to shutdown
+ *
+ *	This function moves an active device into down state. A 
+ *	NETDEV_GOING_DOWN is sent to the netev notifier chain. The device
+ *	is then deactivated and finally a NETDEV_DOWN is sent to the notifier
+ *	chain.
  */
  
 int dev_close(struct net_device *dev)
@@ -560,12 +675,31 @@
  *	Device change register/unregister. These are not inline or static
  *	as we export them to the world.
  */
+ 
+/**
+ *	register_netdevice_notifier - register a network notifier block
+ *	@nb: notifier
+ *
+ *	Register a notifier to be called when network device events occur.
+ *	The notifier passed is linked into the kernel structures and must
+ *	not be reused until it has been unregistered. A negative errno code
+ *	is returned on a failure.
+ */
 
 int register_netdevice_notifier(struct notifier_block *nb)
 {
 	return notifier_chain_register(&netdev_chain, nb);
 }
 
+/**
+ *	unregister_netdevice_notifier - unregister a network notifier block
+ *	@nb: notifier
+ *
+ *	Unregister a notifier previously registered by register_netdevice_notifier
+ *	The notifier is unlinked into the kernel structures and may
+ *	then be reused. A negative errno code is returned on a failure.
+ */
+
 int unregister_netdevice_notifier(struct notifier_block *nb)
 {
 	return notifier_chain_unregister(&netdev_chain,nb);
@@ -637,6 +771,19 @@
 	netif_rx(newskb);
 }
 
+/**
+ *	dev_queue_xmit - transmit a buffer
+ *	@skb: buffer to transmit
+ *	
+ *	Queue a buffer for transmission to a network device. The caller must
+ *	have set the device and priority and built the buffer before calling this 
+ *	function. The function can be called from an interrupt.
+ *
+ *	A negative errno code is returned on a failure. A success does not
+ *	guarantee the frame will be transmitted as it may be dropped due
+ *	to congestion or traffic shaping.
+ */
+ 
 int dev_queue_xmit(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
@@ -770,9 +917,14 @@
 }
 #endif
 
-/*
- *	Receive a packet from a device driver and queue it for the upper
- *	(protocol) levels.  It always succeeds. 
+/**
+ *	netif_rx	-	post buffer to the network code
+ *	@skb: buffer to post
+ *
+ *	This function receives a packet from a device driver and queues it for
+ *	the upper (protocol) levels to process.  It always succeeds. The buffer
+ *	may be dropped during processing for congestion control or by the 
+ *	protocol layers.
  */
 
 void netif_rx(struct sk_buff *skb)
@@ -922,6 +1074,14 @@
 	}
 }
 
+/**
+ *	net_call_rx_atomic
+ *	@fn: function to call
+ *
+ *	Make a function call that is atomic with respect to the protocol
+ *	layers
+ */
+ 
 void net_call_rx_atomic(void (*fn)(void))
 {
 	br_write_lock_bh(BR_NETPROTO_LOCK);
@@ -1063,10 +1223,18 @@
 	return;
 }
 
-/* Protocol dependent address dumping routines */
-
 static gifconf_func_t * gifconf_list [NPROTO];
 
+/**
+ *	register_gifconf	-	register a SIOCGIF handler
+ *	@family: Address family
+ *	@gifconf: Function handler
+ *
+ *	Register protocol dependent address dumping routines. The handler
+ *	that is passed must not be freed or reused until it has been replaced
+ *	by another handler.
+ */
+ 
 int register_gifconf(unsigned int family, gifconf_func_t * gifconf)
 {
 	if (family>=NPROTO)
@@ -1381,6 +1549,18 @@
 #endif	/* CONFIG_PROC_FS */
 #endif	/* WIRELESS_EXT */
 
+/**
+ *	netdev_set_master	-	set up master/slave pair
+ *	@slave: slave device
+ *	@master: new master device
+ *
+ *	Changes the master device of the slave. Pass NULL to break the
+ *	bonding. The caller must hold the RTNL semaphore. On a failure
+ *	a negative errno code is returned. On success the reference counts
+ *	are adjusted, RTM_NEWLINK is sent to the routing socket and the
+ *	function returns zero.
+ */
+ 
 int netdev_set_master(struct net_device *slave, struct net_device *master)
 {
 	struct net_device *old = slave->master;
@@ -1409,6 +1589,17 @@
 	return 0;
 }
 
+/**
+ *	dev_set_promiscuity	- update promiscuity count on a device
+ *	@dev: device
+ *	@inc: modifier
+ *
+ *	Add or remove promsicuity from a device. While the count in the device
+ *	remains above zero the interface remains promiscuous. Once it hits zero
+ *	the device reverts back to normal filtering operation. A negative inc
+ *	value is used to drop promiscuity on the device.
+ */
+ 
 void dev_set_promiscuity(struct net_device *dev, int inc)
 {
 	unsigned short old_flags = dev->flags;
@@ -1430,6 +1621,18 @@
 	}
 }
 
+/**
+ *	dev_set_allmulti	- update allmulti count on a device
+ *	@dev: device
+ *	@inc: modifier
+ *
+ *	Add or remove reception of all multicast frames to a device. While the
+ *	count in the device remains above zero the interface remains listening
+ *	to all interfaces. Once it hits zero the device reverts back to normal
+ *	filtering operation. A negative inc value is used to drop the counter
+ *	when releasing a resource needing all multicasts.
+ */
+
 void dev_set_allmulti(struct net_device *dev, int inc)
 {
 	unsigned short old_flags = dev->flags;
@@ -1673,12 +1876,22 @@
 	return -EINVAL;
 }
 
-
 /*
  *	This function handles all "interface"-type I/O control requests. The actual
  *	'doing' part of this is dev_ifsioc above.
  */
 
+/**
+ *	dev_ioctl	-	network device ioctl
+ *	@cmd: command to issue
+ *	@arg: pointer to a struct ifreq in user space
+ *
+ *	Issue ioctl functions to devices. This is normally called by the
+ *	user space syscall interfaces but can sometimes be useful for 
+ *	other purposes. The return value is the return from the syscall if
+ *	positive or a negative errno code on error.
+ */
+
 int dev_ioctl(unsigned int cmd, void *arg)
 {
 	struct ifreq ifr;
@@ -1811,6 +2024,15 @@
 	}
 }
 
+
+/**
+ *	dev_new_index	-	allocate an ifindex
+ *
+ *	Returns a suitable unique value for a new device interface number.
+ *	The caller must hold the rtnl semaphore to be sure it remains 
+ *	unique.
+ */
+ 
 int dev_new_index(void)
 {
 	static int ifindex;
@@ -1824,6 +2046,19 @@
 
 static int dev_boot_phase = 1;
 
+/**
+ *	register_netdevice	- register a network device
+ *	@dev: device to register
+ *	
+ *	Take a completed network device structure and add it to the kernel
+ *	interfaces. A NETDEV_REGISTER message is sent to the netdev notifier
+ *	chain. 0 is returned on success. A negative errno code is returned
+ *	on a failure to set up the device, or if the name is a duplicate.
+ *
+ *	BUGS:
+ *	The locking appears insufficient to guarantee two parallel registers
+ *	will not get the same name.
+ */
 
 int register_netdevice(struct net_device *dev)
 {
@@ -1917,6 +2152,14 @@
 	return 0;
 }
 
+/**
+ *	netdev_finish_unregister - complete unregistration
+ *	@dev: device
+ *
+ *	Destroy and free a dead device. A value of zero is returned on
+ *	success.
+ */
+ 
 int netdev_finish_unregister(struct net_device *dev)
 {
 	BUG_TRAP(dev->ip_ptr==NULL);
@@ -1924,7 +2167,7 @@
 	BUG_TRAP(dev->dn_ptr==NULL);
 
 	if (!dev->deadbeaf) {
-		printk("Freeing alive device %p, %s\n", dev, dev->name);
+		printk(KERN_ERR "Freeing alive device %p, %s\n", dev, dev->name);
 		return 0;
 	}
 #ifdef NET_REFCNT_DEBUG
@@ -1936,6 +2179,15 @@
 		kfree(dev);
 	return 0;
 }
+
+/**
+ *	unregister_netdevice - remove device from the kernel
+ *	@dev: device
+ *
+ *	This function shuts down a device interface and removes it
+ *	from the kernel tables. On success 0 is returned, on a failure
+ *	a negative errno code is returned.
+ */
 
 int unregister_netdevice(struct net_device *dev)
 {
diff -u --recursive --new-file v2.3.99-pre3/linux/net/core/filter.c linux/net/core/filter.c
--- v2.3.99-pre3/linux/net/core/filter.c	Fri Jan  7 19:13:23 2000
+++ linux/net/core/filter.c	Sun Apr  2 15:38:54 2000
@@ -54,7 +54,12 @@
 	return NULL;
 }
 
-/*
+/**
+ *	sk_run_filter	- 	run a filter on a socket
+ *	@skb: buffer to run the filter on
+ *	@filter: filter to apply
+ *	@flen: length of filter
+ *
  * Decode and apply filter instructions to the skb->data.
  * Return length to keep, 0 for none. skb is the data we are
  * filtering, filter is the array of filter instructions, and
@@ -341,9 +346,17 @@
 	return (0);
 }
 
-/*
+/**
+ *	sk_chk_filter - verify socket filter code
+ *	@filter: filter to verify
+ *	@flen: length of filter
+ *
  * Check the user's filter code. If we let some ugly
- * filter code slip through kaboom!
+ * filter code slip through kaboom! The filter must contain
+ * no references or jumps that are out of range, no illegal instructions
+ * and no backward jumps. It must end with a RET instruction
+ *
+ * Returns 0 if the rule set is legal or a negative errno code if not.
  */
 
 int sk_chk_filter(struct sock_filter *filter, int flen)
@@ -413,9 +426,15 @@
         return (BPF_CLASS(filter[flen - 1].code) == BPF_RET)?0:-EINVAL;
 }
 
-/*
+/**
+ *	sk_attach_filter - attach a socket filter
+ *	@fprog: the filter program
+ *	@sk: the socket to use
+ *
  * Attach the user's filter code. We first run some sanity checks on
- * it to make sure it does not explode on us later.
+ * it to make sure it does not explode on us later. If an error
+ * occurs or there is insufficient memory for the filter a negative
+ * errno code is returned. On success the return is zero.
  */
 
 int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
diff -u --recursive --new-file v2.3.99-pre3/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.3.99-pre3/linux/net/core/skbuff.c	Sun Mar 19 18:35:31 2000
+++ linux/net/core/skbuff.c	Thu Mar 30 16:54:53 2000
@@ -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.70 2000/03/17 14:41:39 davem Exp $
+ *	Version:	$Id: skbuff.c,v 1.71 2000/03/29 11:58:33 davem Exp $
  *
  *	Fixes:	
  *		Alan Cox	:	Fixed the worst of the load balancer bugs.
@@ -77,6 +77,15 @@
  *	reliable. 
  */
 
+/**
+ *	skb_over_panic	- 	private function
+ *	@skb: buffer
+ *	@sz: size
+ *	@here: address
+ *
+ *	Out of line support code for skb_put. Not user callable
+ */
+ 
 void skb_over_panic(struct sk_buff *skb, int sz, void *here)
 {
 	printk("skput:over: %p:%d put:%d dev:%s", 
@@ -84,6 +93,16 @@
 	*(int*)0 = 0;
 }
 
+/**
+ *	skb_under_panic	- 	private function
+ *	@skb: buffer
+ *	@sz: size
+ *	@here: address
+ *
+ *	Out of line support code for skb_push. Not user callable
+ */
+ 
+
 void skb_under_panic(struct sk_buff *skb, int sz, void *here)
 {
         printk("skput:under: %p:%d put:%d dev:%s",
@@ -130,6 +149,19 @@
  * 
  */
 
+/**
+ *	alloc_skb	-	allocate a network buffer
+ *	@size: size to allocate
+ *	@gfp_mask: allocation mask
+ *
+ *	Allocate a new sk_buff. The returned buffer has no headroom and a
+ *	tail room of size bytes. The object has a reference count of one.
+ *	The return is the buffer. On a failure the return is NULL.
+ *
+ *	Buffers may only be allocated from interrupts using a gfp_mask of
+ *	GFP_ATOMIC.
+ */
+ 
 struct sk_buff *alloc_skb(unsigned int size,int gfp_mask)
 {
 	struct sk_buff *skb;
@@ -227,8 +259,13 @@
 	skb_head_to_pool(skb);
 }
 
-/*
- *	Free an sk_buff. Release anything attached to the buffer. Clean the state.
+/**
+ *	__kfree_skb - private function 
+ *	@skb: buffer
+ *
+ *	Free an sk_buff. Release anything attached to the buffer. 
+ *	Clean the state. This is an internal helper function. Users should
+ *	always call kfree_skb
  */
 
 void __kfree_skb(struct sk_buff *skb)
@@ -258,8 +295,18 @@
 	kfree_skbmem(skb);
 }
 
-/*
- *	Duplicate an sk_buff. The new one is not owned by a socket.
+/**
+ *	skb_clone	-	duplicate an sk_buff
+ *	@skb: buffer to clone
+ *	@gfp_mask: allocation priority
+ *
+ *	Duplicate an sk_buff. The new one is not owned by a socket. Both
+ *	copies share the same packet data but not structure. The new
+ *	buffer has a reference count of 1. If the allocation fails the 
+ *	function returns NULL otherwise the new buffer is returned.
+ *	
+ *	If this function is called from an interrupt gfp_mask must be
+ *	GFP_ATOMIC.
  */
 
 struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
@@ -331,8 +378,18 @@
 #endif
 }
 
-/*
- *	This is slower, and copies the whole data area 
+/**
+ *	skb_copy	-	copy an sk_buff
+ *	@skb: buffer to copy
+ *	@gfp_mask: allocation priority
+ *
+ *	Make a copy of both an sk_buff and its data. This is used when the
+ *	caller wishes to modify the data and needs a private copy of the 
+ *	data to alter. Returns NULL on failure or the pointer to the buffer
+ *	on success. The returned buffer has a reference count of 1.
+ *
+ *	You must pass GFP_ATOMIC as the allocation priority if this function
+ *	is called from an interrupt.
  */
  
 struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
@@ -358,6 +415,26 @@
 
 	return n;
 }
+
+/**
+ *	skb_copy	-	copy and expand sk_buff
+ *	@skb: buffer to copy
+ *	@newheadroom: new free bytes at head
+ *	@newtailroom: new free bytes at tail
+ *	@gfp_mask: allocation priority
+ *
+ *	Make a copy of both an sk_buff and its data and while doing so 
+ *	allocate additional space.
+ *
+ *	This is used when the caller wishes to modify the data and needs a 
+ *	private copy of the data to alter as well as more space for new fields.
+ *	 Returns NULL on failure or the pointer to the buffer
+ *	on success. The returned buffer has a reference count of 1.
+ *
+ *	You must pass GFP_ATOMIC as the allocation priority if this function
+ *	is called from an interrupt.
+ */
+ 
 
 struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
 				int newheadroom,
diff -u --recursive --new-file v2.3.99-pre3/linux/net/core/sock.c linux/net/core/sock.c
--- v2.3.99-pre3/linux/net/core/sock.c	Thu Mar  2 14:36:23 2000
+++ linux/net/core/sock.c	Mon Mar 27 10:35:56 2000
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.90 2000/02/27 19:48:11 davem Exp $
+ * Version:	$Id: sock.c,v 1.91 2000/03/25 01:55:03 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -731,11 +731,12 @@
 {
 	DECLARE_WAITQUEUE(wait, current);
 
-	sk->socket->flags &= ~SO_NOSPACE;
+	clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 	add_wait_queue(sk->sleep, &wait);
 	for (;;) {
 		if (signal_pending(current))
 			break;
+		set_bit(SOCK_NOSPACE, &sk->socket->flags);
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (atomic_read(&sk->wmem_alloc) < sk->sndbuf)
 			break;
@@ -802,18 +803,20 @@
 		 *	This means we have too many buffers for this socket already.
 		 */
 
-		sk->socket->flags |= SO_NOSPACE;
+		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+		set_bit(SOCK_NOSPACE, &sk->socket->flags);
 		err = -EAGAIN;
 		if (!timeo)
 			goto failure;
-		err = -ERESTARTSYS;
 		if (signal_pending(current))
-			goto failure;
+			goto interrupted;
 		timeo = sock_wait_for_wmem(sk, timeo);
 	}
 
 	return skb;
 
+interrupted:
+	err = sock_intr_errno(timeo);
 failure:
 	*errcode = err;
 	return NULL;
@@ -1079,7 +1082,7 @@
 void sock_def_wakeup(struct sock *sk)
 {
 	read_lock(&sk->callback_lock);
-	if(!sk->dead)
+	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible_all(sk->sleep);
 	read_unlock(&sk->callback_lock);
 }
@@ -1087,20 +1090,18 @@
 void sock_def_error_report(struct sock *sk)
 {
 	read_lock(&sk->callback_lock);
-	if (!sk->dead) {
+	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,0,POLL_ERR); 
-	}
+	sk_wake_async(sk,0,POLL_ERR); 
 	read_unlock(&sk->callback_lock);
 }
 
 void sock_def_readable(struct sock *sk, int len)
 {
 	read_lock(&sk->callback_lock);
-	if(!sk->dead) {
+	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,1,POLL_IN);
-	}
+	sk_wake_async(sk,1,POLL_IN);
 	read_unlock(&sk->callback_lock);
 }
 
@@ -1111,14 +1112,15 @@
 	/* Do not wake up a writer until he can make "significant"
 	 * progress.  --DaveM
 	 */
-	if(!sk->dead &&
-	   ((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf)) {
-		wake_up_interruptible(sk->sleep);
+	if((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf) {
+		if (sk->sleep && waitqueue_active(sk->sleep))
+			wake_up_interruptible(sk->sleep);
 
 		/* Should agree with poll, otherwise some programs break */
 		if (sock_writeable(sk))
-			sock_wake_async(sk->socket, 2, POLL_OUT);
+			sk_wake_async(sk, 2, POLL_OUT);
 	}
+
 	read_unlock(&sk->callback_lock);
 }
 
diff -u --recursive --new-file v2.3.99-pre3/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- v2.3.99-pre3/linux/net/decnet/af_decnet.c	Fri Mar 10 16:40:50 2000
+++ linux/net/decnet/af_decnet.c	Mon Mar 27 10:35:56 2000
@@ -1670,14 +1670,14 @@
 			goto out;
 		}
 
-		sock->flags |= SO_WAITDATA;
+		set_bit(SOCK_ASYNC_WAITDATA, &sock->flags);
 		SOCK_SLEEP_PRE(sk)
 
 		if (!dn_data_ready(sk, queue, flags, target))
 			schedule();
 
 		SOCK_SLEEP_POST(sk)
-		sock->flags &= ~SO_WAITDATA;
+		clear_bit(SOCK_ASYNC_WAITDATA, &sock->flags);
 	}
 
 	for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) {
diff -u --recursive --new-file v2.3.99-pre3/linux/net/decnet/dn_nsp_in.c linux/net/decnet/dn_nsp_in.c
--- v2.3.99-pre3/linux/net/decnet/dn_nsp_in.c	Fri Mar 10 16:40:50 2000
+++ linux/net/decnet/dn_nsp_in.c	Mon Mar 27 10:35:56 2000
@@ -438,7 +438,8 @@
         if (!sk->dead) {
 		struct socket *sock = sk->socket;
 		wake_up_interruptible(sk->sleep);
-		if (!(sock->flags & SO_WAITDATA) && sock->fasync_list)
+		if (sock && sock->fasync_list &&
+		    !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
 			kill_fasync(sock->fasync_list, sig, 
 				    (sig == SIGURG) ? POLL_PRI : POLL_IN);
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/net/decnet/dn_nsp_out.c linux/net/decnet/dn_nsp_out.c
--- v2.3.99-pre3/linux/net/decnet/dn_nsp_out.c	Fri Mar 10 16:40:50 2000
+++ linux/net/decnet/dn_nsp_out.c	Mon Mar 27 10:35:56 2000
@@ -133,13 +133,13 @@
 		}
 
 		if (space < len) {
-			sk->socket->flags |= SO_NOSPACE;
+			set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 			if (noblock) {
 				*err = EWOULDBLOCK;
 				break;
 			}
 
-			sk->socket->flags &= ~SO_NOSPACE;
+			clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 			SOCK_SLEEP_PRE(sk)
 
 			if ((sk->sndbuf - atomic_read(&sk->wmem_alloc)) < len)
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.3.99-pre3/linux/net/ipv4/af_inet.c	Sat Feb 26 22:32:08 2000
+++ linux/net/ipv4/af_inet.c	Mon Mar 27 10:35:56 2000
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.108 2000/02/21 16:25:59 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.109 2000/03/25 01:55:10 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -607,7 +607,7 @@
 		if (!timeo || !inet_wait_for_connect(sk, timeo))
 			goto out;
 
-		err = -ERESTARTSYS;
+		err = sock_intr_errno(timeo);
 		if (signal_pending(current))
 			goto out;
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.3.99-pre3/linux/net/ipv4/icmp.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/icmp.c	Mon Mar 27 10:35:56 2000
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@redhat.com>
  *
- *	Version: $Id: icmp.c,v 1.66 2000/03/17 14:41:50 davem Exp $
+ *	Version: $Id: icmp.c,v 1.67 2000/03/25 01:55:11 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -1128,6 +1128,7 @@
 	if ((err=ops->create(icmp_socket, IPPROTO_ICMP))<0)
 		panic("Failed to create the ICMP control socket.\n");
 	icmp_socket->sk->allocation=GFP_ATOMIC;
+	icmp_socket->sk->sndbuf = SK_WMEM_MAX*2;
 	icmp_socket->sk->protinfo.af_inet.ttl = MAXTTL;
 
 	/* Unhash it so that IP input processing does not even
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.3.99-pre3/linux/net/ipv4/ip_output.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/ip_output.c	Mon Mar 27 10:35:56 2000
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.82 2000/03/17 14:41:50 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.83 2000/03/25 01:52:08 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -415,14 +415,13 @@
 
 	/* OK, we know where to send it, allocate and build IP header. */
 	iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
-	iph->version  = 4;
-	iph->ihl      = 5;
-	iph->tos      = sk->protinfo.af_inet.tos;
+	*((__u16 *)iph)	= htons((4 << 12) | (5 << 8) | (sk->protinfo.af_inet.tos & 0xff));
+	iph->tot_len = htons(skb->len);
 	iph->frag_off = 0;
 	iph->ttl      = sk->protinfo.af_inet.ttl;
-	iph->daddr    = rt->rt_dst;
-	iph->saddr    = rt->rt_src;
 	iph->protocol = sk->protocol;
+	iph->saddr    = rt->rt_src;
+	iph->daddr    = rt->rt_dst;
 	skb->nh.iph   = iph;
 	/* Transport layer set skb->h.foo itself. */
 
@@ -430,8 +429,6 @@
 		iph->ihl += opt->optlen >> 2;
 		ip_options_build(skb, opt, sk->daddr, rt, 0);
 	}
-
-	iph->tot_len = htons(skb->len);
 
 	return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
 		       ip_queue_xmit2);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in
--- v2.3.99-pre3/linux/net/ipv4/netfilter/Config.in	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/Config.in	Mon Mar 27 10:35:56 2000
@@ -39,6 +39,7 @@
   if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
     dep_tristate '  Full NAT' CONFIG_IP_NF_NAT $CONFIG_IP_NF_IPTABLES 
     if [ "$CONFIG_IP_NF_NAT" != "n" ]; then
+      define_bool CONFIG_IP_NF_NAT_NEEDED y
       dep_tristate '    MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
       dep_tristate '    REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
     fi
@@ -56,8 +57,14 @@
 if [ "$CONFIG_IP_NF_CONNTRACK" != "y" ]; then
   if [ "$CONFIG_IP_NF_IPTABLES" != "y" ]; then
     tristate 'ipchains (2.2-style) support' CONFIG_IP_NF_COMPAT_IPCHAINS
+    if [ "$CONFIG_IP_NF_COMPAT_IPCHAINS" != "n" ]; then
+      define_bool CONFIG_IP_NF_NAT_NEEDED y
+    fi
     if [ "$CONFIG_IP_NF_COMPAT_IPCHAINS" != "y" ]; then
       tristate 'ipfwadm (2.0-style) support' CONFIG_IP_NF_COMPAT_IPFWADM
+      if [ "$CONFIG_IP_NF_COMPAT_IPFWADM" != "n" ]; then
+	define_bool CONFIG_IP_NF_NAT_NEEDED y
+      fi
     fi
   fi
 fi
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
--- v2.3.99-pre3/linux/net/ipv4/netfilter/Makefile	Mon Mar 27 08:08:33 2000
+++ linux/net/ipv4/netfilter/Makefile	Mon Mar 27 10:35:56 2000
@@ -15,10 +15,12 @@
 
 IP_NF_NAT_OBJ:=ip_nat_core.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
 
+# All the parts of conntrack and NAT required for compatibility layer.
+IP_NF_COMPAT_LAYER:=ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(IP_NF_CONNTRACK_OBJ) $(IP_NF_NAT_OBJ)
+
 # Link order matters here.
 ifeq ($(CONFIG_IP_NF_CONNTRACK),y)
-OX_OBJS += ip_conntrack_standalone.o
-O_OBJS += $(IP_NF_CONNTRACK_OBJ)
+O_OBJS += ip_conntrack_standalone.o $(IP_NF_CONNTRACK_OBJ)
 else
   ifeq ($(CONFIG_IP_NF_CONNTRACK),m)
   MI_OBJS += $(IP_NF_CONNTRACK_OBJ)
@@ -27,16 +29,8 @@
   endif
 endif
 
-ifeq ($(CONFIG_IP_NF_QUEUE),y)
-O_OBJS += ip_queue.o
-else
-  ifeq ($(CONFIG_IP_NF_QUEUE),m)
-  M_OBJS += ip_queue.o
-  endif
-endif
-
 ifeq ($(CONFIG_IP_NF_FTP),y)
-OX_OBJS += ip_conntrack_ftp.o
+O_OBJS += ip_conntrack_ftp.o
 else
   ifeq ($(CONFIG_IP_NF_FTP),m)
   MX_OBJS += ip_conntrack_ftp.o
@@ -47,7 +41,7 @@
 O_OBJS += ip_tables.o
 else
   ifeq ($(CONFIG_IP_NF_IPTABLES),m)
-  M_OBJS += ip_tables.o
+  MX_OBJS += ip_tables.o
   endif
 endif
 
@@ -115,17 +109,8 @@
   endif
 endif
 
-ifeq ($(CONFIG_IP_NF_FILTER),y)
-O_OBJS += iptable_filter.o
-else
-  ifeq ($(CONFIG_IP_NF_FILTER),m)
-  M_OBJS += iptable_filter.o
-  endif
-endif
-
 ifeq ($(CONFIG_IP_NF_NAT),y)
-OX_OBJS += ip_nat_standalone.o
-O_OBJS += ip_nat_rule.o $(IP_NF_NAT_OBJ) 
+O_OBJS += ip_nat_standalone.o ip_nat_rule.o $(IP_NF_NAT_OBJ) 
   ifeq ($(CONFIG_IP_NF_FTP),y)
   O_OBJS += ip_nat_ftp.o
   endif
@@ -140,6 +125,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_IP_NF_FILTER),y)
+O_OBJS += iptable_filter.o
+else
+  ifeq ($(CONFIG_IP_NF_FILTER),m)
+  M_OBJS += iptable_filter.o
+  endif
+endif
+
 ifeq ($(CONFIG_IP_NF_MANGLE),y)
 O_OBJS += iptable_mangle.o
 else
@@ -205,7 +198,7 @@
 endif
 
 ifeq ($(CONFIG_IP_NF_COMPAT_IPCHAINS),y)
-O_OBJS += ipchains.o
+O_OBJS += ipchains_core.o $(IP_NF_COMPAT_LAYER)
 else
   ifeq ($(CONFIG_IP_NF_COMPAT_IPCHAINS),m)
   M_OBJS += ipchains.o
@@ -213,13 +206,21 @@
 endif
 
 ifeq ($(CONFIG_IP_NF_COMPAT_IPFWADM),y)
-O_OBJS += ipfwadm.o
+O_OBJS += ipfwadm_core.o $(IP_NF_COMPAT_LAYER)
 else
   ifeq ($(CONFIG_IP_NF_COMPAT_IPFWADM),m)
   M_OBJS += ipfwadm.o
   endif
 endif
 
+ifeq ($(CONFIG_IP_NF_QUEUE),y)
+O_OBJS += ip_queue.o
+else
+  ifeq ($(CONFIG_IP_NF_QUEUE),m)
+  M_OBJS += ip_queue.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 ip_conntrack.o: ip_conntrack_standalone.o $(IP_NF_CONNTRACK_OBJ)
@@ -228,11 +229,8 @@
 iptable_nat.o: ip_nat_standalone.o ip_nat_rule.o $(IP_NF_NAT_OBJ) 
 	$(LD) -r -o $@ ip_nat_standalone.o ip_nat_rule.o $(IP_NF_NAT_OBJ)
 
-# All the parts of conntrack and NAT required for compatibility layer.
-IP_NF_COMPAT_LAYER:=ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(IP_NF_CONNTRACK_OBJ) $(IP_NF_NAT_OBJ)
-
 ipfwadm.o: ipfwadm_core.o $(IP_NF_COMPAT_LAYER)
 	$(LD) -r -o $@ ipfwadm_core.o $(IP_NF_COMPAT_LAYER)
 
-ipchains.o: ipchains_core.o $(IP_NF_COMPAT_LAYER)
+ipchains.o: ipchains_core.o $(IP_NF_COMPAT_LAYER) 
 	$(LD) -r -o $@ ipchains_core.o $(IP_NF_COMPAT_LAYER)
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_core.c linux/net/ipv4/netfilter/ip_conntrack_core.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_core.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_core.c	Mon Mar 27 10:35:56 2000
@@ -22,6 +22,7 @@
 #include <net/checksum.h>
 #include <linux/stddef.h>
 #include <linux/sysctl.h>
+#include <linux/slab.h>
 
 /* This rwlock protects the main hash table, protocol/helper/expected
    registrations, conntrack timers*/
@@ -43,13 +44,14 @@
 DECLARE_RWLOCK(ip_conntrack_lock);
 
 void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
-static LIST_HEAD(expect_list);
-static LIST_HEAD(protocol_list);
+LIST_HEAD(expect_list);
+LIST_HEAD(protocol_list);
 static LIST_HEAD(helpers);
 unsigned int ip_conntrack_htable_size = 0;
 static int ip_conntrack_max = 0;
 static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
 struct list_head *ip_conntrack_hash;
+static kmem_cache_t *ip_conntrack_cachep;
 
 extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
 
@@ -167,7 +169,7 @@
 
 	if (ip_conntrack_destroyed)
 		ip_conntrack_destroyed(ct);
-	kfree(ct);
+	kmem_cache_free(ip_conntrack_cachep, ct);
 	atomic_dec(&ip_conntrack_count);
 }
 
@@ -355,7 +357,7 @@
 		return 1;
 	}
 
-	conntrack = kmalloc(sizeof(struct ip_conntrack), GFP_ATOMIC);
+	conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
 	if (!conntrack) {
 		DEBUGP("Can't allocate conntrack.\n");
 		return 1;
@@ -374,7 +376,7 @@
 		conntrack->infos[i].master = &conntrack->ct_general;
 
 	if (!protocol->new(conntrack, skb->nh.iph, skb->len)) {
-		kfree(conntrack);
+		kmem_cache_free(ip_conntrack_cachep, conntrack);
 		return 1;
 	}
 
@@ -384,7 +386,7 @@
 	if (__ip_conntrack_find(tuple, NULL)) {
 		WRITE_UNLOCK(&ip_conntrack_lock);
 		printk("ip_conntrack: Wow someone raced us!\n");
-		kfree(conntrack);
+		kmem_cache_free(ip_conntrack_cachep, conntrack);
 		return 0;
 	}
 	conntrack->helper = LIST_FIND(&helpers, helper_cmp,
@@ -796,6 +798,7 @@
 #define NET_IP_CONNTRACK_MAX 2089
 #define NET_IP_CONNTRACK_MAX_NAME "ip_conntrack_max"
 
+#ifdef CONFIG_SYSCTL
 static struct ctl_table_header *ip_conntrack_sysctl_header;
 
 static ctl_table ip_conntrack_table[] = {
@@ -813,6 +816,7 @@
 	{CTL_NET, "net", NULL, 0, 0555, ip_conntrack_dir_table, 0, 0, 0, 0, 0},
 	{ 0 }
 };
+#endif /*CONFIG_SYSCTL*/
 
 static int kill_all(const struct ip_conntrack *i, void *data)
 {
@@ -823,8 +827,11 @@
    supposed to kill the mall. */
 void ip_conntrack_cleanup(void)
 {
+#ifdef CONFIG_SYSCTL
 	unregister_sysctl_table(ip_conntrack_sysctl_header);
+#endif
 	ip_ct_selective_cleanup(kill_all, NULL);
+	kmem_cache_destroy(ip_conntrack_cachep);
 	vfree(ip_conntrack_hash);
 	nf_unregister_sockopt(&so_getorigdst);
 }
@@ -855,6 +862,16 @@
 		return -ENOMEM;
 	}
 
+	ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
+	                                        sizeof(struct ip_conntrack), 0,
+	                                        SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!ip_conntrack_cachep) {
+		printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
+		vfree(ip_conntrack_hash);
+		nf_unregister_sockopt(&so_getorigdst);
+		return -ENOMEM;
+	}
+	
 	/* Don't NEED lock here, but good form anyway. */
 	WRITE_LOCK(&ip_conntrack_lock);
 	/* Sew in builtin protocols. */
@@ -873,19 +890,12 @@
 	ip_conntrack_sysctl_header
 		= register_sysctl_table(ip_conntrack_root_table, 0);
 	if (ip_conntrack_sysctl_header == NULL) {
+		kmem_cache_destroy(ip_conntrack_cachep);
 		vfree(ip_conntrack_hash);
 		nf_unregister_sockopt(&so_getorigdst);
 		return -ENOMEM;
 	}
 #endif /*CONFIG_SYSCTL*/
 
-	ret = ip_conntrack_protocol_tcp_init();
-	if (ret != 0) {
-		unregister_sysctl_table(ip_conntrack_sysctl_header);
-		vfree(ip_conntrack_hash);
-		nf_unregister_sockopt(&so_getorigdst);
-	}
-
 	return ret;
 }
-
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_ftp.c linux/net/ipv4/netfilter/ip_conntrack_ftp.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_ftp.c	Mon Mar 27 08:08:33 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_ftp.c	Mon Mar 27 10:35:56 2000
@@ -10,6 +10,7 @@
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
 
 DECLARE_LOCK(ip_ftp_lock);
+struct module *ip_conntrack_ftp = THIS_MODULE;
 
 #define SERVER_STRING "227 Entering Passive Mode ("
 #define CLIENT_STRING "PORT "
@@ -239,10 +240,6 @@
 {
 	ip_conntrack_helper_unregister(&ftp);
 }
-
-struct module *ip_conntrack_ftp = THIS_MODULE;
-EXPORT_SYMBOL(ip_conntrack_ftp);
-EXPORT_SYMBOL(ip_ftp_lock);
 
 module_init(init);
 module_exit(fini);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Thu Mar 30 16:56:25 2000
@@ -2,6 +2,7 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/netfilter.h>
+#include <linux/in.h>
 #include <linux/icmp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Thu Mar 30 16:56:25 2000
@@ -4,6 +4,7 @@
 #include <linux/timer.h>
 #include <linux/netfilter.h>
 #include <linux/module.h>
+#include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
@@ -220,8 +221,3 @@
 = { { NULL, NULL }, IPPROTO_TCP, "tcp",
     tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
     tcp_packet, tcp_new, NULL };
-
-int __init ip_conntrack_protocol_tcp_init(void)
-{
-	return 0;
-}
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Thu Mar 30 16:56:25 2000
@@ -2,6 +2,7 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/netfilter.h>
+#include <linux/in.h>
 #include <linux/udp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_standalone.c linux/net/ipv4/netfilter/ip_conntrack_standalone.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_conntrack_standalone.c	Mon Mar 27 08:08:33 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c	Mon Mar 27 10:35:56 2000
@@ -276,6 +276,7 @@
 module_init(init);
 module_exit(fini);
 
+#ifdef MODULE
 EXPORT_SYMBOL(ip_conntrack_protocol_register);
 EXPORT_SYMBOL(invert_tuplepr);
 EXPORT_SYMBOL(ip_conntrack_alter_reply);
@@ -284,11 +285,9 @@
 EXPORT_SYMBOL(ip_conntrack_module);
 EXPORT_SYMBOL(ip_conntrack_helper_register);
 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
-EXPORT_SYMBOL(ip_conntrack_lock);
-EXPORT_SYMBOL(find_proto);
-EXPORT_SYMBOL(get_tuple);
 EXPORT_SYMBOL(ip_ct_selective_cleanup);
 EXPORT_SYMBOL(ip_ct_refresh);
 EXPORT_SYMBOL(ip_conntrack_expect_related);
 EXPORT_SYMBOL(ip_conntrack_tuple_taken);
 EXPORT_SYMBOL(ip_ct_gather_frags);
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_fw_compat.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ip_fw_compat.c	Mon Mar 27 10:35:56 2000
@@ -14,8 +14,6 @@
 #include <linux/netfilter_ipv4/compat_firewall.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 
-EXPORT_NO_SYMBOLS;
-
 static struct firewall_ops *fwops;
 
 /* From ip_fw_compat_redir.c */
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_fw_compat_masq.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c	Thu Mar 30 16:56:25 2000
@@ -5,6 +5,7 @@
    DO IT.
  */
 #include <linux/skbuff.h>
+#include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/icmp.h>
 #include <linux/udp.h>
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_nat_ftp.c linux/net/ipv4/netfilter/ip_nat_ftp.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_nat_ftp.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ip_nat_ftp.c	Mon Mar 27 10:35:56 2000
@@ -11,8 +11,6 @@
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 
-EXPORT_NO_SYMBOLS;
-
 #if 0
 #define DEBUGP printk
 #else
@@ -374,8 +372,6 @@
 static struct ip_nat_expect ftp_expect
 = { { NULL, NULL }, ftp_nat_expected };
 
-extern struct module *ip_conntrack_ftp;
-
 static int __init init(void)
 {
 	int ret;
@@ -384,9 +380,7 @@
 	if (ret == 0) {
 		ret = ip_nat_helper_register(&ftp);
 
-		if (ret == 0)
-			__MOD_INC_USE_COUNT(ip_conntrack_ftp);
-		else
+		if (ret != 0)
 			ip_nat_expect_unregister(&ftp_expect);
 	}
 	return ret;
@@ -394,7 +388,6 @@
 
 static void __exit fini(void)
 {
-	__MOD_DEC_USE_COUNT(ip_conntrack_ftp);
 	ip_nat_helper_unregister(&ftp);
 	ip_nat_expect_unregister(&ftp_expect);
 }
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_nat_standalone.c	Mon Mar 27 08:08:33 2000
+++ linux/net/ipv4/netfilter/ip_nat_standalone.c	Mon Mar 27 10:35:56 2000
@@ -230,11 +230,13 @@
 		printk("ip_nat_init: can't register local out hook.\n");
 		goto cleanup_outops;
 	}
-	__MOD_INC_USE_COUNT(ip_conntrack_module);
+	if (ip_conntrack_module)
+		__MOD_INC_USE_COUNT(ip_conntrack_module);
 	return ret;
 
  cleanup:
-	__MOD_DEC_USE_COUNT(ip_conntrack_module);
+	if (ip_conntrack_module)
+		__MOD_DEC_USE_COUNT(ip_conntrack_module);
 	nf_unregister_hook(&ip_nat_local_out_ops);
  cleanup_outops:
 	nf_unregister_hook(&ip_nat_out_ops);
@@ -262,9 +264,11 @@
 module_init(init);
 module_exit(fini);
 
+#ifdef MODULE
 EXPORT_SYMBOL(ip_nat_setup_info);
 EXPORT_SYMBOL(ip_nat_helper_register);
 EXPORT_SYMBOL(ip_nat_helper_unregister);
 EXPORT_SYMBOL(ip_nat_expect_register);
 EXPORT_SYMBOL(ip_nat_expect_unregister);
 EXPORT_SYMBOL(ip_nat_cheat_check);
+#endif
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_queue.c linux/net/ipv4/netfilter/ip_queue.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_queue.c	Mon Mar 27 08:08:33 2000
+++ linux/net/ipv4/netfilter/ip_queue.c	Thu Mar 30 16:54:54 2000
@@ -2,7 +2,7 @@
  * This is a module which is used for queueing IPv4 packets and
  * communicating with userspace via netlink.
  *
- * (C) 2000 James Morris
+ * (C) 2000 James Morris, this code is GPL.
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -13,7 +13,6 @@
 #include <linux/netfilter.h>
 #include <linux/netlink.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/rtnetlink.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
@@ -21,20 +20,13 @@
 
 #include <linux/netfilter_ipv4/ip_queue.h>
 
-EXPORT_NO_SYMBOLS;
-
-#define IPQ_THR_NAME "kipq"
-#define IPQ_NAME "ip_queue"
 #define IPQ_QMAX_DEFAULT 1024
-
 #define IPQ_PROC_FS_NAME "ip_queue"
-
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
 
 typedef struct ipq_queue_element {
 	struct list_head list;		/* Links element into queue */
-	unsigned char state;		/* State of this element */
 	int verdict;			/* Current verdict */
 	struct nf_info *info;		/* Extra info from netfilter */
 	struct sk_buff *skb;		/* Packet inside */
@@ -50,178 +42,70 @@
 	ipq_send_cb_t send;		/* Callback for sending data to peer */
 } ipq_peer_t;
 
-typedef struct ipq_thread {
-	pid_t pid;			/* PID of kernel thread */
- 	unsigned char terminate;	/* Termination flag */
- 	unsigned char running;		/* Running flag */
- 	wait_queue_head_t wq;		/* I/O wait queue */
- 	void (*process)(void *data);	/* Queue processing function */
-} ipq_thread_t;
-
 typedef struct ipq_queue {
  	int len;			/* Current queue len */
  	int *maxlen;			/* Maximum queue len, via sysctl */
- 	unsigned char state;		/* Current queue state */
+ 	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 */
  	ipq_peer_t peer;		/* Userland peer */
- 	ipq_thread_t thread;		/* Thread context */
 } ipq_queue_t;
 
 
 /****************************************************************************
-*
-* Kernel thread
-*
-****************************************************************************/
-
-static void ipq_thread_init(char *thread_name)
-{
- 	lock_kernel();
- 	exit_files(current);
- 	daemonize();
- 	strcpy(current->comm, thread_name);
- 	unlock_kernel();
- 	spin_lock_irq(&current->sigmask_lock);
- 	flush_signals(current);
- 	sigfillset(&current->blocked);
- 	recalc_sigpending(current);
- 	spin_unlock_irq(&current->sigmask_lock);
-}
-
-static int ipq_thread_start(void *data)
-{
- 	ipq_queue_t *q = (ipq_queue_t *)data;
-
- 	q->thread.running = 1;
- 	ipq_thread_init(IPQ_THR_NAME);
- 	q->thread.pid = current->pid;
- 	while (!q->thread.terminate) {
- 		interruptible_sleep_on(&q->thread.wq);
- 		q->thread.process(q);
- 	}
- 	q->thread.running = 0;
- 	return 0;
-}
-
-static void ipq_thread_stop(ipq_queue_t *q)
-{
- 	if (!(q->thread.pid || q->thread.running))
- 		return;
- 	q->state = IPQ_QS_FLUSH;
- 	q->thread.terminate = 1;
- 	wake_up_interruptible(&q->thread.wq);
- 	current->state = TASK_INTERRUPTIBLE;
- 	while (q->thread.running) {
- 		schedule_timeout(HZ/10);
- 		current->state = TASK_RUNNING;
- 	}
-}
-
-static int ipq_thread_create(ipq_queue_t *q)
-{
-	int status = kernel_thread(ipq_thread_start, q, 0);
-	return (status < 0) ? status : 0;
-}
-
-
-/****************************************************************************
  *
  * Packet queue
  *
  ****************************************************************************/
 
-/* Must be called under spinlock */
-static __inline__ void
-ipq_dequeue(ipq_queue_t *q,
-            ipq_queue_element_t *e)
+/* Dequeue with element packet ID, or from end of queue if ID is zero. */
+static ipq_queue_element_t *ipq_dequeue(ipq_queue_t *q, unsigned long id)
 {
-	list_del(&e->list);
-	nf_reinject(e->skb, e->info, e->verdict);
-	kfree(e);
-	q->len--;
-}
-
-/* Must be called under spinlock */
-static __inline__ void
-ipq_queue_drop(ipq_queue_t *q,
-               ipq_queue_element_t *e)
-{
-	e->verdict = NF_DROP;
-	ipq_dequeue(q, e);
-}
-
-static int
-ipq_notify_peer(ipq_queue_t *q,
-                ipq_queue_element_t *e)
-{
-	int status = q->peer.send(e);
+	struct list_head *i;
+	ipq_queue_element_t *e = NULL;
 
-	if (status >= 0) {
-		e->state = IPQ_PS_WAITING;
-		return status;
+	spin_lock_bh(&q->lock);
+	if (q->len == 0)
+		goto out_unlock;
+	i = q->list.prev;
+	if (id > 0) {
+		while (i != &q->list) {
+			if (id == (unsigned long )i)
+				goto out_unlink;
+			i = i->prev;	
+		}
+		goto out_unlock;
 	}
-	if (status == -ERESTARTSYS || status == -EAGAIN)
-		return 0;
-	printk(KERN_INFO "%s: error notifying peer %d, resetting "
-	       "state and flushing queue\n", IPQ_NAME, q->peer.pid);
-	q->state = IPQ_QS_FLUSH;
-	q->peer.died = 1;
-	q->peer.pid = 0;
-	q->peer.copy_mode = IPQ_COPY_META;
-	q->peer.copy_range = 0;
-	return status;
+out_unlink:
+	e = (ipq_queue_element_t *)i;
+	list_del(&e->list);
+	q->len--;
+out_unlock:
+	spin_unlock_bh(&q->lock);
+	return e;
 }
 
-static void
-ipq_queue_process(void *data)
+static void ipq_flush(ipq_queue_t *q)
 {
-	struct list_head *i;
-	ipq_queue_t *q = (ipq_queue_t *)data;
-
-restart:
-	if (q->state == IPQ_QS_HOLD)
-		return;
+	ipq_queue_element_t *e;
+	
 	spin_lock_bh(&q->lock);
-	for (i = q->list.prev; i != &q->list; i = i->prev) {
-		ipq_queue_element_t *e = (ipq_queue_element_t *)i;
-
-		if (q->state == IPQ_QS_FLUSH) {
-			QDEBUG("flushing packet %p\n", e);
-			ipq_queue_drop(q, e);
-			continue;
-		}
-		switch (e->state) {
-			case IPQ_PS_NEW: {
-				int status = ipq_notify_peer(q, e);
-				if (status < 0) {
-					spin_unlock_bh(&q->lock);
-					goto restart;
-				}
-				break;
-			}
-			case IPQ_PS_VERDICT:
-				ipq_dequeue(q, e);
-				break;
-			case IPQ_PS_WAITING:
-				break;
-			default:
-				printk(KERN_INFO "%s: dropping stuck packet %p "
-				       "with ps=%d qs=%d\n", IPQ_NAME,
-				       e, e->state, q->state);
-				ipq_queue_drop(q, e);
-		}
+	q->flushing = 1;
+	spin_unlock_bh(&q->lock);
+	while ((e = ipq_dequeue(q, 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);
-	if (q->state == IPQ_QS_FLUSH)
-		q->state = IPQ_QS_HOLD;
 }
 
-static ipq_queue_t *
-ipq_queue_create(nf_queue_outfn_t outfn,
-                 ipq_send_cb_t send_cb,
-                 int *errp,
-                 int *sysctl_qmax)
+static ipq_queue_t *ipq_create_queue(nf_queue_outfn_t outfn,
+                                     ipq_send_cb_t send_cb,
+                                     int *errp, int *sysctl_qmax)
 {
 	int status;
 	ipq_queue_t *q;
@@ -232,18 +116,15 @@
 		*errp = -ENOMEM;
 		return NULL;
 	}
-	q->thread.terminate = 0;
-	q->thread.running = 0;
-	q->thread.process = ipq_queue_process;
-	init_waitqueue_head(&q->thread.wq);
 	q->peer.pid = 0;
 	q->peer.died = 0;
-	q->peer.copy_mode = IPQ_COPY_META;
+	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->state = IPQ_QS_HOLD;
+	q->flushing = 0;
+	q->terminate = 0;
 	INIT_LIST_HEAD(&q->list);
 	spin_lock_init(&q->lock);
 	status = nf_register_queue_handler(PF_INET, outfn, q);
@@ -252,91 +133,92 @@
 		kfree(q);
 		return NULL;
 	}
-	status = ipq_thread_create(q);
-	if (status < 0) {
-		nf_unregister_queue_handler(PF_INET);
-		*errp = status;
-		kfree(q);
-		return  NULL;
-	}
 	return q;
 }
 
-static int
-ipq_enqueue(ipq_queue_t *q,
-            struct sk_buff *skb,
-            struct nf_info *info)
+static int ipq_enqueue(ipq_queue_t *q,
+                       struct sk_buff *skb, struct nf_info *info)
 {
-	ipq_queue_element_t *e = NULL;
-
+	ipq_queue_element_t *e;
+	int status;
+	
 	e = kmalloc(sizeof(*e), GFP_ATOMIC);
 	if (e == NULL) {
-		printk(KERN_ERR "%s: out of memory in %s\n",
-		       IPQ_NAME, __FUNCTION__);
-		return  -ENOMEM;
+		printk(KERN_ERR "ip_queue: OOM in enqueue\n");
+		return -ENOMEM;
 	}
-	e->state = IPQ_PS_NEW;
 	e->verdict = NF_DROP;
 	e->info = info;
 	e->skb = skb;
 	spin_lock_bh(&q->lock);
 	if (q->len >= *q->maxlen) {
 		spin_unlock_bh(&q->lock);
-		printk(KERN_WARNING "%s: queue full at %d entries, "
-		       "dropping packet.\n", IPQ_NAME, q->len);
-		kfree(e);
-		nf_reinject(skb, info, NF_DROP);
-		return 0;
+		if (net_ratelimit()) 
+			printk(KERN_WARNING "ip_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;
 	}
-	list_add(&e->list, &q->list);
-	q->len++;
 	spin_unlock_bh(&q->lock);
-	wake_up_interruptible(&q->thread.wq);
-	return 0;
+	if (status == -ECONNREFUSED) {
+		printk(KERN_INFO "ip_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;
+			ipq_flush(q);
+	}
+free_drop:
+	kfree(e);
+	return -EBUSY;
 }
 
-/* FIXME: need to find a way to notify user during module unload */
-static void
-ipq_queue_destroy(ipq_queue_t *q)
+static void ipq_destroy_queue(ipq_queue_t *q)
 {
-	ipq_thread_stop(q);
 	nf_unregister_queue_handler(PF_INET);
+	spin_lock_bh(&q->lock);
+	q->terminate = 1;
+	spin_unlock_bh(&q->lock);
+	ipq_flush(q);
 	kfree(q);
 }
 
-static int
-ipq_queue_mangle_ipv4(unsigned char *buf,
-                      ipq_verdict_msg_t *v,
-                      ipq_queue_element_t *e)
+static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
 {
-	struct iphdr *user_iph = (struct iphdr *)buf;
+	struct iphdr *user_iph = (struct iphdr *)v->payload;
 
 	if (v->data_len < sizeof(*user_iph))
 		return 0;
-
 	if (e->skb->nh.iph->check != user_iph->check) {
 		int 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) {
-				e->verdict = NF_DROP;
+			if (v->data_len > 0xFFFF)
 				return -EINVAL;
-			}
 			if (diff > skb_tailroom(e->skb)) {
 				struct sk_buff *newskb;
 
-				/* Ack, we waste a memcpy() of data here */
 				newskb = skb_copy_expand(e->skb,
 				                         skb_headroom(e->skb),
 				                         diff,
 				                         GFP_ATOMIC);
 				if (newskb == NULL) {
-					printk(KERN_WARNING "%s: OOM in %s, "
-					       "dropping packet\n",
-					       IPQ_THR_NAME, __FUNCTION__);
-					e->verdict = NF_DROP;
+					printk(KERN_WARNING "ip_queue: OOM "
+					       "in mangle, dropping packet\n");
 					return -ENOMEM;
 				}
 				kfree_skb(e->skb);
@@ -344,101 +226,76 @@
 			}
 			skb_put(e->skb, diff);
 		}
-		memcpy(e->skb->data, buf, v->data_len);
+		memcpy(e->skb->data, v->payload, v->data_len);
 		e->skb->nfcache |= NFC_ALTERED;
 	}
 	return 0;
 }
 
-static int
-ipq_queue_set_verdict(ipq_queue_t *q,
-                      ipq_verdict_msg_t *v,
-                      unsigned char *buf,
-                      unsigned int len)
+static int ipq_set_verdict(ipq_queue_t *q,
+                           ipq_verdict_msg_t *v, unsigned int len)
 {
-	struct list_head *i;
+	ipq_queue_element_t *e;
 
 	if (v->value < 0 || v->value > NF_MAX_VERDICT)
 		return -EINVAL;
-	spin_lock_bh(&q->lock);
-	for (i = q->list.next; i != &q->list; i = i->next) {
-		ipq_queue_element_t *e = (ipq_queue_element_t *)i;
-
-		if (v->id == (unsigned long )e) {
-			int status = 0;
-			e->state = IPQ_PS_VERDICT;
-			e->verdict = v->value;
-
-			if (buf && v->data_len == len)
-				status = ipq_queue_mangle_ipv4(buf, v, e);
-			spin_unlock_bh(&q->lock);
-			return status;
-		}
+	e = ipq_dequeue(q, v->id);
+	if (e == NULL)
+		return -ENOENT;
+	else {
+		e->verdict = v->value;
+		if (v->data_len && v->data_len == len)
+			if (ipq_mangle_ipv4(v, e) < 0)
+				e->verdict = NF_DROP;
+		nf_reinject(e->skb, e->info, e->verdict);
+		kfree(e);
+		return 0;
 	}
-	spin_unlock_bh(&q->lock);
-	return -ENOENT;
 }
 
-static int
-ipq_receive_peer(ipq_queue_t *q,
-                 ipq_peer_msg_t *m,
-                 unsigned char type,
-                 unsigned int len)
+static int ipq_receive_peer(ipq_queue_t *q, ipq_peer_msg_t *m,
+                            unsigned char type, unsigned int len)
 {
-	if (q->state == IPQ_QS_FLUSH)
-		return -EBUSY;
 
+	int status = 0;
+		
+	spin_lock_bh(&q->lock);
+	if (q->terminate || q->flushing)
+		return -EBUSY;
+	spin_unlock_bh(&q->lock);
 	if (len < sizeof(ipq_peer_msg_t))
 		return -EINVAL;
-
 	switch (type) {
 		case IPQM_MODE:
 			switch (m->msg.mode.value) {
-				case IPQ_COPY_NONE:
-					q->peer.copy_mode = IPQ_COPY_NONE;
-					q->peer.copy_range = 0;
-					q->state = IPQ_QS_FLUSH;
-					break;
 				case IPQ_COPY_META:
-					if (q->state == IPQ_QS_FLUSH)
-						return -EAGAIN;
 					q->peer.copy_mode = IPQ_COPY_META;
 					q->peer.copy_range = 0;
-					q->state = IPQ_QS_COPY;
 					break;
 				case IPQ_COPY_PACKET:
-					if (q->state == IPQ_QS_FLUSH)
-						return -EAGAIN;
 					q->peer.copy_mode = IPQ_COPY_PACKET;
 					q->peer.copy_range = m->msg.mode.range;
-					q->state = IPQ_QS_COPY;
+					if (q->peer.copy_range > 0xFFFF)
+						q->peer.copy_range = 0xFFFF;
 					break;
 				default:
-					return -EINVAL;
+					status = -EINVAL;
 			}
 			break;
-		case IPQM_VERDICT: {
-			int status;
-			unsigned char *data = NULL;
-
+		case IPQM_VERDICT:
 			if (m->msg.verdict.value > NF_MAX_VERDICT)
-				return -EINVAL;
-			if (m->msg.verdict.data_len)
-				data = (unsigned char *)m + sizeof(*m);
-			status = ipq_queue_set_verdict(q, &m->msg.verdict,
-			                               data, len - sizeof(*m));
-			if (status < 0)
-				return status;
+				status = -EINVAL;
+			else
+				status = ipq_set_verdict(q,
+				                         &m->msg.verdict,
+				                         len - sizeof(*m));
 			break;
-		}
 		default:
-			return -EINVAL;
+			 status = -EINVAL;
 	}
-	wake_up_interruptible(&q->thread.wq);
-	return 0;
+	return status;
 }
 
-
 /****************************************************************************
  *
  * Netfilter interface
@@ -449,16 +306,10 @@
  * 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
-receive_netfilter(struct sk_buff *skb,
-                  struct nf_info *info,
-                  void *data)
+static int netfilter_receive(struct sk_buff *skb,
+                             struct nf_info *info, void *data)
 {
-	ipq_queue_t *q = (ipq_queue_t *)data;
-
-	if (q->state == IPQ_QS_FLUSH)
-		return -EBUSY;
-	return ipq_enqueue(q, skb, info);
+	return ipq_enqueue((ipq_queue_t *)data, skb, info);
 }
 
 /****************************************************************************
@@ -467,36 +318,10 @@
  *
  ****************************************************************************/
 
-static struct sk_buff *
-netlink_build_message(ipq_queue_element_t *e,
-                      int *errp);
-
-extern __inline__ void
-receive_user_skb(struct sk_buff *skb);
-
-static int
-netlink_send_peer(ipq_queue_element_t *e);
-
 static struct sock *nfnl = NULL;
 ipq_queue_t *nlq = NULL;
 
-static int
-netlink_send_peer(ipq_queue_element_t *e)
-{
-	int status = 0;
-	struct sk_buff *skb;
-
-	if (!nlq->peer.pid)
-		return -EINVAL;
-	skb = netlink_build_message(e, &status);
-	if (skb == NULL)
-		return status;
-	return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT);
-}
-
-static struct sk_buff *
-netlink_build_message(ipq_queue_element_t *e,
-                      int *errp)
+static struct sk_buff *netlink_build_message(ipq_queue_element_t *e, int *errp)
 {
 	unsigned char *old_tail;
 	size_t size = 0;
@@ -519,6 +344,7 @@
 			else
 				data_len = copy_range;
 			size = NLMSG_SPACE(sizeof(*pm) + data_len);
+			
 			break;
 		case IPQ_COPY_NONE:
 		default:
@@ -542,7 +368,7 @@
 	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
 	else pm->outdev_name[0] = '\0';
 	if (data_len)
-		memcpy(++pm, e->skb->data, 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;
@@ -550,16 +376,24 @@
 	if (skb)
 		kfree(skb);
 	*errp = 0;
-	printk(KERN_ERR "%s: error creating netlink message\n", IPQ_NAME);
+	printk(KERN_ERR "ip_queue: error creating netlink message\n");
 	return NULL;
 }
 
+static int netlink_send_peer(ipq_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, nlq->peer.pid, MSG_DONTWAIT);
+}
+
 #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
-/*
- * FIXME: ping old peer if we detect a new peer then resend.
- */
-extern __inline__ void
-receive_user_skb(struct sk_buff *skb)
+
+extern __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
 {
 	int status, type;
 	struct nlmsghdr *nlh;
@@ -581,9 +415,11 @@
 	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
 		RCV_SKB_FAIL(-EPERM);
 	if (nlq->peer.pid && !nlq->peer.died
-	    && (nlq->peer.pid != nlh->nlmsg_pid))
-	    	printk(KERN_WARNING "%s: peer pid changed from %d to %d\n",
-	    	       IPQ_NAME, nlq->peer.pid, nlh->nlmsg_pid);
+	    && (nlq->peer.pid != nlh->nlmsg_pid)) {
+	    	printk(KERN_WARNING "ip_queue: peer pid changed from %d to "
+	    	      "%d, flushing queue\n", nlq->peer.pid, nlh->nlmsg_pid);
+		ipq_flush(nlq);
+	}	
 	nlq->peer.pid = nlh->nlmsg_pid;
 	nlq->peer.died = 0;
 	status = ipq_receive_peer(nlq, NLMSG_DATA(nlh),
@@ -596,9 +432,7 @@
 }
 
 /* Note: we are only dealing with single part messages at the moment. */
-static void
-receive_user_sk(struct sock *sk,
-                int len)
+static void netlink_receive_user_sk(struct sock *sk, int len)
 {
 	do {
 		struct sk_buff *skb;
@@ -606,28 +440,25 @@
 		if (rtnl_shlock_nowait())
 			return;
 		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
-			receive_user_skb(skb);
+			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)
+static int receive_event(struct notifier_block *this,
+                         unsigned long event, void *ptr)
 {
 	if (event == NETDEV_UNREGISTER)
 		if (nlq)
-			ipq_thread_stop(nlq);
+			ipq_destroy_queue(nlq);
 	return NOTIFY_DONE;
 }
 
@@ -637,7 +468,6 @@
 	0
 };
 
-
 /****************************************************************************
  *
  * Sysctl - queue tuning.
@@ -670,33 +500,28 @@
  *
  ****************************************************************************/
 
-static int
-ipq_get_info(char *buffer, char **start, off_t offset, int length)
+static int ipq_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	int len;
 
 	spin_lock_bh(&nlq->lock);
 	len = sprintf(buffer,
- 	              "Thread pid        : %d\n"
- 	              "Thread terminate  : %d\n"
- 	              "Thread running    : %d\n"
-	              "Peer pid          : %d\n"
-	              "Peer died         : %d\n"
-	              "Peer copy mode    : %d\n"
-	              "Peer copy range   : %d\n"
-	              "Queue length      : %d\n"
-	              "Queue max. length : %d\n"
-	              "Queue state       : %d\n",
- 	              nlq->thread.pid,
- 	              nlq->thread.terminate,
- 	              nlq->thread.running,
+	              "Peer pid            : %d\n"
+	              "Peer died           : %d\n"
+	              "Peer copy mode      : %d\n"
+	              "Peer copy range     : %d\n"
+	              "Queue length        : %d\n"
+	              "Queue max. length   : %d\n"
+	              "Queue flushing      : %d\n"
+	              "Queue terminate     : %d\n",
 	              nlq->peer.pid,
 	              nlq->peer.died,
 	              nlq->peer.copy_mode,
 	              nlq->peer.copy_range,
 	              nlq->len,
 	              *nlq->maxlen,
-	              nlq->state);
+	              nlq->flushing,
+	              nlq->terminate);
 	spin_unlock_bh(&nlq->lock);
 	*start = buffer + offset;
 	len -= offset;
@@ -716,18 +541,18 @@
 static int __init init(void)
 {
 	int status = 0;
-
-	nfnl = netlink_kernel_create(NETLINK_FIREWALL, receive_user_sk);
+	
+	nfnl = netlink_kernel_create(NETLINK_FIREWALL, netlink_receive_user_sk);
 	if (nfnl == NULL) {
-		printk(KERN_ERR "%s: initialisation failed: unable to "
-		       "create kernel netlink socket\n", IPQ_NAME);
+		printk(KERN_ERR "ip_queue: initialisation failed: unable to "
+		       "create kernel netlink socket\n");
 		return -ENOMEM;
 	}
-	nlq = ipq_queue_create(receive_netfilter,
+	nlq = ipq_create_queue(netfilter_receive,
 	                       netlink_send_peer, &status, &sysctl_maxlen);
 	if (nlq == NULL) {
-		printk(KERN_ERR "%s: initialisation failed: unable to "
-		       "initialise queue\n", IPQ_NAME);
+		printk(KERN_ERR "ip_queue: initialisation failed: unable to "
+		       "create queue\n");
 		sock_release(nfnl->socket);
 		return status;
 	}
@@ -742,11 +567,12 @@
 	unregister_sysctl_table(ipq_sysctl_header);
 	proc_net_remove(IPQ_PROC_FS_NAME);
 	unregister_netdevice_notifier(&ipq_dev_notifier);
-	ipq_queue_destroy(nlq);
+	ipq_destroy_queue(nlq);
 	sock_release(nfnl->socket);
 }
 
 MODULE_DESCRIPTION("IPv4 packet queue handler");
 module_init(init);
 module_exit(fini);
+
 
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ip_tables.c linux/net/ipv4/netfilter/ip_tables.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ip_tables.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ip_tables.c	Mon Mar 27 10:35:56 2000
@@ -12,15 +12,13 @@
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/icmp.h>
+#include <net/ip.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
+#include <linux/proc_fs.h>
 
 #include <linux/netfilter_ipv4/ip_tables.h>
 
-#ifndef IP_OFFSET
-#define IP_OFFSET 0x1FFF
-#endif
-
 /*#define DEBUG_IP_FIREWALL*/
 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
 /*#define DEBUG_IP_FIREWALL_USER*/
@@ -288,9 +286,16 @@
 		+ TABLE_OFFSET(table->private, smp_processor_id());
 	e = get_entry(table_base, table->private->hook_entry[hook]);
 
-	/* Check noone else using our table */
-	IP_NF_ASSERT(((struct ipt_entry *)table_base)->comefrom == 0xdead57ac);
 #ifdef CONFIG_NETFILTER_DEBUG
+	/* Check noone else using our table */
+	if (((struct ipt_entry *)table_base)->comefrom != 0xdead57ac
+	    && ((struct ipt_entry *)table_base)->comefrom != 0xeeeeeeec) {
+		printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
+		       smp_processor_id(),
+		       table->name,
+		       &((struct ipt_entry *)table_base)->comefrom,
+		       ((struct ipt_entry *)table_base)->comefrom);
+	}
 	((struct ipt_entry *)table_base)->comefrom = 0x57acc001;
 #endif
 
@@ -343,11 +348,28 @@
 
 				e = get_entry(table_base, v);
 			} else {
+				/* Targets which reenter must return
+                                   abs. verdicts */
+#ifdef CONFIG_NETFILTER_DEBUG
+				((struct ipt_entry *)table_base)->comefrom
+					= 0xeeeeeeec;
+#endif
 				verdict = t->u.target->target(pskb, hook,
 							      in, out,
 							      t->data,
 							      userdata);
 
+#ifdef CONFIG_NETFILTER_DEBUG
+				if (((struct ipt_entry *)table_base)->comefrom
+				    != 0xeeeeeeec
+				    && verdict == IPT_CONTINUE) {
+					printk("Target %s reentered!\n",
+					       t->u.target->name);
+					verdict = NF_DROP;
+				}
+				((struct ipt_entry *)table_base)->comefrom
+					= 0x57acc001;
+#endif
 				/* Target might have changed stuff. */
 				ip = (*pskb)->nh.iph;
 				protohdr = (u_int32_t *)ip + ip->ihl;
@@ -1631,6 +1653,43 @@
 static struct ipt_match icmp_matchstruct
 = { { NULL, NULL }, "icmp", &icmp_match, &icmp_checkentry, NULL };
 
+#ifdef CONFIG_PROC_FS
+static inline int print_name(const struct ipt_table *t,
+			     off_t start_offset, char *buffer, int length,
+			     off_t *pos, unsigned int *count)
+{
+	if ((*count)++ >= start_offset) {
+		unsigned int namelen;
+
+		namelen = sprintf(buffer + *pos, "%s\n", t->name);
+		if (*pos + namelen > length) {
+			/* Stop iterating */
+			return 1;
+		}
+		*pos += namelen;
+	}
+	return 0;
+}
+
+static int ipt_get_tables(char *buffer, char **start, off_t offset, int length)
+{
+	off_t pos = 0;
+	unsigned int count = 0;
+
+	if (down_interruptible(&ipt_mutex) != 0)
+		return 0;
+
+	LIST_FIND(&ipt_tables, print_name, struct ipt_table *,
+		  offset, buffer, length, &pos, &count);
+
+	up(&ipt_mutex);
+
+	/* `start' hack - see fs/proc/generic.c line ~105 */
+	*start=(char *)((unsigned long)count-offset);
+	return pos;
+}
+#endif /*CONFIG_PROC_FS*/
+
 static int __init init(void)
 {
 	int ret;
@@ -1651,13 +1710,23 @@
 		return ret;
 	}
 
-	printk("iptables: (c)2000 Netfilter core team\n");
+#ifdef CONFIG_PROC_FS
+	if (!proc_net_create("ip_tables_names", 0, ipt_get_tables)) {
+		nf_unregister_sockopt(&ipt_sockopts);
+		return -ENOMEM;
+	}
+#endif
+
+	printk("ip_tables: (c)2000 Netfilter core team\n");
 	return 0;
 }
 
 static void __exit fini(void)
 {
 	nf_unregister_sockopt(&ipt_sockopts);
+#ifdef CONFIG_PROC_FS
+	proc_net_remove("ip_tables_names");
+#endif
 }
 
 module_init(init);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipchains_core.c linux/net/ipv4/netfilter/ipchains_core.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipchains_core.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipchains_core.c	Mon Mar 27 10:35:56 2000
@@ -145,7 +145,9 @@
 /*#define DEBUG_IP_FIREWALL_USER*/
 /*#define DEBUG_IP_FIREWALL_LOCKING*/
 
+#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
 static struct sock *ipfwsk;
+#endif
 
 #ifdef CONFIG_SMP
 #define SLOT_NUMBER() (cpu_number_map(smp_processor_id())*2 + !in_interrupt())
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_LOG.c linux/net/ipv4/netfilter/ipt_LOG.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_LOG.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_LOG.c	Mon Mar 27 10:35:56 2000
@@ -24,10 +24,6 @@
 	__u32   spi;
 }; /* FIXME evil kludge */
         
-/* Make init and cleanup non-static, so gcc doesn't warn about unused,
-   but don't export the symbols */
-EXPORT_NO_SYMBOLS;
-
 /* Use lock to serialize, so printks don't overlap */
 static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
 
@@ -353,15 +349,15 @@
 
 static int __init init(void)
 {
-    if (ipt_register_target(&ipt_log_reg))
-	return -EINVAL;
+	if (ipt_register_target(&ipt_log_reg))
+		return -EINVAL;
 
-    return 0;
+	return 0;
 }
 
 static void __exit fini(void)
 {
-    ipt_unregister_target(&ipt_log_reg);
+	ipt_unregister_target(&ipt_log_reg);
 }
 
 module_init(init);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_MARK.c linux/net/ipv4/netfilter/ipt_MARK.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_MARK.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_MARK.c	Mon Mar 27 10:35:56 2000
@@ -7,8 +7,6 @@
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_MARK.h>
 
-EXPORT_NO_SYMBOLS;
-
 static unsigned int
 target(struct sk_buff **pskb,
        unsigned int hooknum,
@@ -53,15 +51,15 @@
 
 static int __init init(void)
 {
-    if (ipt_register_target(&ipt_mark_reg))
-	return -EINVAL;
+	if (ipt_register_target(&ipt_mark_reg))
+		return -EINVAL;
 
-    return 0;
+	return 0;
 }
 
 static void __exit fini(void)
 {
-    ipt_unregister_target(&ipt_mark_reg);
+	ipt_unregister_target(&ipt_mark_reg);
 }
 
 module_init(init);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_MASQUERADE.c linux/net/ipv4/netfilter/ipt_MASQUERADE.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_MASQUERADE.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_MASQUERADE.c	Mon Mar 27 10:35:56 2000
@@ -11,8 +11,6 @@
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 
-EXPORT_NO_SYMBOLS;
-
 #if 0
 #define DEBUGP printk
 #else
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_MIRROR.c linux/net/ipv4/netfilter/ipt_MIRROR.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_MIRROR.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_MIRROR.c	Mon Mar 27 10:35:56 2000
@@ -29,7 +29,6 @@
 #include <linux/route.h>
 struct in_device;
 #include <net/route.h>
-EXPORT_NO_SYMBOLS;
 
 #if 0
 #define DEBUGP printk
@@ -49,7 +48,7 @@
 	}
 	/* check if the interface we are living by is the same as the one we arrived on */
 
-	if (skb->rx_dev != rt->u.dst.dev) {
+	if (skb->rx_dev == rt->u.dst.dev) {
 		/* Drop old route. */
 		dst_release(skb->dst);
 		skb->dst = &rt->u.dst;
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_REDIRECT.c linux/net/ipv4/netfilter/ipt_REDIRECT.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_REDIRECT.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_REDIRECT.c	Mon Mar 27 10:35:56 2000
@@ -12,8 +12,6 @@
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 
-EXPORT_NO_SYMBOLS;
-
 #if 0
 #define DEBUGP printk
 #else
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_REJECT.c linux/net/ipv4/netfilter/ipt_REJECT.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_REJECT.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_REJECT.c	Mon Mar 27 10:35:56 2000
@@ -6,12 +6,11 @@
 #include <linux/skbuff.h>
 #include <linux/ip.h>
 #include <net/icmp.h>
-#include <net/tcp.h>
+#include <net/ip.h>
 struct in_device;
 #include <net/route.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_REJECT.h>
-EXPORT_NO_SYMBOLS;
 
 #if 0
 #define DEBUGP printk
@@ -28,6 +27,9 @@
 {
 	const struct ipt_reject_info *reject = targinfo;
 
+	/* WARNING: This code has causes reentry within iptables.
+	   This means that the iptables jump stack is now crap.  We
+	   must return an absolute verdict. --RR */
     	switch (reject->with) {
     	case IPT_ICMP_NET_UNREACHABLE:
     		icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0);
@@ -62,9 +64,6 @@
 		}
 	}
 	break;
-	case IPT_TCP_RESET:
-		tcp_v4_send_reset(*pskb);
-		break;
 	}
 
 	return NF_DROP;
@@ -113,12 +112,6 @@
 		/* Must contain ICMP match. */
 		if (IPT_MATCH_ITERATE(e, find_ping_match) == 0) {
 			DEBUGP("REJECT: ECHOREPLY illegal for non-ping\n");
-			return 0;
-		}
-	} else if (rejinfo->with == IPT_TCP_RESET) {
-		if (e->ip.proto != IPPROTO_TCP
-		    || (e->ip.invflags & IPT_INV_PROTO)) {
-			DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n");
 			return 0;
 		}
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_TOS.c linux/net/ipv4/netfilter/ipt_TOS.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_TOS.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_TOS.c	Mon Mar 27 10:35:56 2000
@@ -7,8 +7,6 @@
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_TOS.h>
 
-EXPORT_NO_SYMBOLS;
-
 static unsigned int
 target(struct sk_buff **pskb,
        unsigned int hooknum,
@@ -72,15 +70,15 @@
 
 static int __init init(void)
 {
-    if (ipt_register_target(&ipt_tos_reg))
-	return -EINVAL;
+	if (ipt_register_target(&ipt_tos_reg))
+		return -EINVAL;
 
-    return 0;
+	return 0;
 }
 
 static void __exit fini(void)
 {
-    ipt_unregister_target(&ipt_tos_reg);
+	ipt_unregister_target(&ipt_tos_reg);
 }
 
 module_init(init);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_limit.c linux/net/ipv4/netfilter/ipt_limit.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_limit.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_limit.c	Mon Mar 27 10:35:56 2000
@@ -14,7 +14,6 @@
 
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_limit.h>
-EXPORT_NO_SYMBOLS;
 
 #define IP_PARTS_NATIVE(n)			\
 (unsigned int)((n)>>24)&0xFF,			\
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_mac.c linux/net/ipv4/netfilter/ipt_mac.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_mac.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_mac.c	Mon Mar 27 10:35:56 2000
@@ -5,7 +5,6 @@
 
 #include <linux/netfilter_ipv4/ipt_mac.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
-EXPORT_NO_SYMBOLS;
 
 static int
 match(const struct sk_buff *skb,
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_mark.c linux/net/ipv4/netfilter/ipt_mark.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_mark.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_mark.c	Mon Mar 27 10:35:56 2000
@@ -5,8 +5,6 @@
 #include <linux/netfilter_ipv4/ipt_mark.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 
-EXPORT_NO_SYMBOLS;
-
 static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_multiport.c linux/net/ipv4/netfilter/ipt_multiport.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_multiport.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_multiport.c	Mon Mar 27 10:35:56 2000
@@ -14,8 +14,6 @@
 #define duprintf(format, args...)
 #endif
 
-EXPORT_NO_SYMBOLS;
-
 /* Returns 1 if the port is matched by the test, 0 otherwise. */
 static inline int
 ports_match(const u_int16_t *portlist, enum ipt_multiport_flags flags,
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_owner.c linux/net/ipv4/netfilter/ipt_owner.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_owner.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_owner.c	Mon Mar 27 10:35:56 2000
@@ -1,7 +1,7 @@
 /* Kernel module to match various things tied to sockets associated with
    locally generated outgoing packets.
 
-   (C)2000 Marc Boucher
+   Copyright (C) 2000 Marc Boucher
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -10,8 +10,6 @@
 
 #include <linux/netfilter_ipv4/ipt_owner.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
-
-EXPORT_NO_SYMBOLS;
 
 static int
 match_pid(const struct sk_buff *skb, pid_t pid)
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_state.c linux/net/ipv4/netfilter/ipt_state.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_state.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_state.c	Mon Mar 27 10:35:56 2000
@@ -6,7 +6,6 @@
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_state.h>
-EXPORT_NO_SYMBOLS;
 
 static int
 match(const struct sk_buff *skb,
@@ -47,14 +46,17 @@
 
 static int __init init(void)
 {
-	__MOD_INC_USE_COUNT(ip_conntrack_module);
+	/* NULL if ip_conntrack not a module */
+	if (ip_conntrack_module)
+		__MOD_INC_USE_COUNT(ip_conntrack_module);
 	return ipt_register_match(&state_match);
 }
 
 static void __exit fini(void)
 {
 	ipt_unregister_match(&state_match);
-	__MOD_DEC_USE_COUNT(ip_conntrack_module);
+	if (ip_conntrack_module)
+		__MOD_DEC_USE_COUNT(ip_conntrack_module);
 }
 
 module_init(init);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_tos.c linux/net/ipv4/netfilter/ipt_tos.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_tos.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_tos.c	Mon Mar 27 10:35:56 2000
@@ -5,8 +5,6 @@
 #include <linux/netfilter_ipv4/ipt_tos.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 
-EXPORT_NO_SYMBOLS;
-
 static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_unclean.c linux/net/ipv4/netfilter/ipt_unclean.c
--- v2.3.99-pre3/linux/net/ipv4/netfilter/ipt_unclean.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipt_unclean.c	Mon Mar 27 10:35:56 2000
@@ -9,8 +9,6 @@
 
 #include <linux/netfilter_ipv4/ip_tables.h>
 
-EXPORT_NO_SYMBOLS;
-
 #define limpk(format, args...)						 \
 do {									 \
 	if (net_ratelimit())						 \
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.3.99-pre3/linux/net/ipv4/tcp.c	Mon Mar 27 08:08:33 2000
+++ linux/net/ipv4/tcp.c	Mon Mar 27 10:35:56 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.165 2000/03/23 05:30:32 davem Exp $
+ * Version:	$Id: tcp.c,v 1.166 2000/03/25 01:55:11 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -445,12 +445,6 @@
 }
 
 /*
- *	Compute minimal free write space needed to queue new packets. 
- */
-#define tcp_min_write_space(__sk) \
-	(atomic_read(&(__sk)->wmem_alloc) / 2)
-
-/*
  *	Wait for a TCP event.
  *
  *	Note that we don't need to lock the socket, as the upper poll layers
@@ -520,7 +514,15 @@
 			if (sock_wspace(sk) >= tcp_min_write_space(sk)) {
 				mask |= POLLOUT | POLLWRNORM;
 			} else {  /* send SIGIO later */
-				sk->socket->flags |= SO_NOSPACE;
+				set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+				set_bit(SOCK_NOSPACE, &sk->socket->flags);
+
+				/* Race breaker. If space is freed after
+				 * wspace test but before the flags are set,
+				 * IO signal will be lost.
+				 */
+				if (sock_wspace(sk) >= tcp_min_write_space(sk))
+					mask |= POLLOUT | POLLWRNORM;
 			}
 		}
 
@@ -534,18 +536,26 @@
  *	Socket write_space callback.
  *	This (or rather the sock_wake_async) should agree with poll.
  *
- *	WARNING. This callback is called from any context (process,
- *	bh or irq). Do not make anything more smart from it.
+ *	WARNING. This callback is called, when socket is not locked.
+ *
+ *	This wakeup is used by TCP only as dead-lock breaker, real
+ *	wakeup occurs when incoming ack frees some space in buffer.
  */
 void tcp_write_space(struct sock *sk)
 {
+	struct socket *sock;
+
 	read_lock(&sk->callback_lock);
-	if (!sk->dead) {
-		/* Why??!! Does it really not overshedule? --ANK */
-		wake_up_interruptible(sk->sleep);
+	if ((sock = sk->socket) != NULL && atomic_read(&sk->wmem_alloc) == 0) {
+		if (test_bit(SOCK_NOSPACE, &sock->flags)) {
+			if (sk->sleep && waitqueue_active(sk->sleep)) {
+				clear_bit(SOCK_NOSPACE, &sock->flags);
+				wake_up_interruptible(sk->sleep);
+			}
+		}
 
-		if (sock_wspace(sk) >= tcp_min_write_space(sk))
-			sock_wake_async(sk->socket, 2, POLL_OUT);
+		if (sock->fasync_list)
+			sock_wake_async(sock, 2, POLL_OUT);
 	}
 	read_unlock(&sk->callback_lock);
 }
@@ -636,7 +646,6 @@
 		sk->write_space = tcp_listen_write_space;
 		sk_dst_reset(sk);
 		sk->prot->hash(sk);
-		sk->socket->flags |= SO_ACCEPTCON;
 
 		return 0;
 	}
@@ -742,7 +751,7 @@
 		if(!*timeo_p)
 			return -EAGAIN;
 		if(signal_pending(tsk))
-			return -ERESTARTSYS;
+			return sock_intr_errno(*timeo_p);
 
 		__set_task_state(tsk, TASK_INTERRUPTIBLE);
 		add_wait_queue(sk->sleep, &wait);
@@ -772,9 +781,12 @@
 	if (!tcp_memory_free(sk)) {
 		DECLARE_WAITQUEUE(wait, current);
 
-		sk->socket->flags &= ~SO_NOSPACE;
+		clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+
 		add_wait_queue(sk->sleep, &wait);
 		for (;;) {
+			set_bit(SOCK_NOSPACE, &sk->socket->flags);
+
 			set_current_state(TASK_INTERRUPTIBLE);
 
 			if (signal_pending(current))
@@ -830,7 +842,7 @@
 			goto out_unlock;
 
 	/* This should be in poll */
-	sk->socket->flags &= ~SO_NOSPACE; /* clear SIGIO XXX */
+	clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 
 	mss_now = tcp_current_mss(sk);
 
@@ -943,13 +955,15 @@
 
 			/* If we didn't get any memory, we need to sleep. */
 			if (skb == NULL) {
-				sk->socket->flags |= SO_NOSPACE;
+				set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+				set_bit(SOCK_NOSPACE, &sk->socket->flags);
+
 				if (!timeo) {
 					err = -EAGAIN;
 					goto do_interrupted;
 				}
 				if (signal_pending(current)) {
-					err = -ERESTARTSYS;
+					err = sock_intr_errno(timeo);
 					goto do_interrupted;
 				}
 				__tcp_push_pending_frames(sk, tp, mss_now);
@@ -1062,7 +1076,8 @@
 		msg->msg_flags|=MSG_OOB;
 
 		if(len>0) {
-			err = memcpy_toiovec(msg->msg_iov, &c, 1);
+			if (!(flags & MSG_PEEK))
+				err = memcpy_toiovec(msg->msg_iov, &c, 1);
 			len = 1;
 		} else
 			msg->msg_flags|=MSG_TRUNC;
@@ -1188,14 +1203,14 @@
 
 	__set_current_state(TASK_INTERRUPTIBLE);
 
-	sk->socket->flags |= SO_WAITDATA;
+	set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 	release_sock(sk);
 
 	if (skb_queue_empty(&sk->receive_queue))
 		timeo = schedule_timeout(timeo);
 
 	lock_sock(sk);
-	sk->socket->flags &= ~SO_WAITDATA;
+	clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 
 	remove_wait_queue(sk->sleep, &wait);
 	__set_current_state(TASK_RUNNING);
@@ -1287,9 +1302,7 @@
 		if (signal_pending(current)) {
 			if (copied)
 				break;
-			copied = -ERESTARTSYS;
-			if (!timeo)
-				copied = -EAGAIN;
+			copied = timeo ? sock_intr_errno(timeo) : -EAGAIN;
 			break;
 		}
 
@@ -1362,7 +1375,7 @@
 
 		if (tp->ucopy.task == user_recv) {
 			/* Install new reader */
-			if (user_recv == NULL && !(flags&MSG_PEEK)) {
+			if (user_recv == NULL && !(flags&(MSG_TRUNC|MSG_PEEK))) {
 				user_recv = current;
 				tp->ucopy.task = user_recv;
 				tp->ucopy.iov = msg->msg_iov;
@@ -1370,7 +1383,7 @@
 
 			tp->ucopy.len = len;
 
-			BUG_TRAP(tp->copied_seq == tp->rcv_nxt || (flags&MSG_PEEK));
+			BUG_TRAP(tp->copied_seq == tp->rcv_nxt || (flags&(MSG_PEEK|MSG_TRUNC)));
 
 			/* Ugly... If prequeue is not empty, we have to
 			 * process it before releasing socket, otherwise
@@ -1458,12 +1471,15 @@
 			}
 		}
 
-		err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used);
-		if (err) {
-			/* Exception. Bailout! */
-			if (!copied)
-				copied = -EFAULT;
-			break;
+		err = 0;
+		if (!(flags&MSG_TRUNC)) {
+			err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used);
+			if (err) {
+				/* Exception. Bailout! */
+				if (!copied)
+					copied = -EFAULT;
+				break;
+			}
 		}
 
 		*seq += used;
@@ -1961,7 +1977,7 @@
 		err = -EINVAL;
 		if (sk->state != TCP_LISTEN)
 			break;
-		err = -ERESTARTSYS;
+		err = sock_intr_errno(timeo);
 		if (signal_pending(current))
 			break;
 		err = -EAGAIN;
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.3.99-pre3/linux/net/ipv4/tcp_input.c	Mon Mar 27 08:08:34 2000
+++ linux/net/ipv4/tcp_input.c	Mon Mar 27 10:35:57 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.190 2000/03/21 19:34:23 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.191 2000/03/25 01:55:13 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1181,6 +1181,9 @@
 	if (ack != tp->snd_una || (flag == 0 && !th->fin))
 		dst_confirm(sk->dst_cache);
 
+	if (ack != tp->snd_una)
+		tp->sorry = 1;
+
 	/* Remember the highest ack received. */
 	tp->snd_una = ack;
 	return 1;
@@ -1614,7 +1617,7 @@
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
 	tp->fin_seq = TCP_SKB_CB(skb)->end_seq;
-	tcp_send_ack(sk);
+	tp->ack.pending = 1;
 
 	sk->shutdown |= RCV_SHUTDOWN;
 
@@ -1644,6 +1647,7 @@
 			break;
 		case TCP_FIN_WAIT2:
 			/* Received a FIN -- send ACK and enter TIME_WAIT. */
+			tcp_send_ack(sk);
 			tcp_time_wait(sk, TCP_TIME_WAIT, 0);
 			break;
 		default:
@@ -1944,7 +1948,7 @@
 
 		if (eaten) {
 			kfree_skb(skb);
-		} else
+		} else if (!sk->dead)
 			sk->data_ready(sk, 0);
 		return;
 	}
@@ -2074,6 +2078,30 @@
 	kfree_skb(skb);
 }
 
+/* When incoming ACK allowed to free some skb from write_queue,
+ * we remember this in flag tp->sorry and wake up socket on the exit
+ * from tcp input handler. Probably, handler has already eat this space
+ * sending ACK and cloned frames from tcp_write_xmit().
+ */
+static __inline__ void tcp_new_space(struct sock *sk)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	struct socket *sock;
+
+	tp->sorry = 0;
+
+	if (sock_wspace(sk) >= tcp_min_write_space(sk) &&
+	    (sock = sk->socket) != NULL) {
+		clear_bit(SOCK_NOSPACE, &sock->flags);
+
+		if (sk->sleep && waitqueue_active(sk->sleep))
+			wake_up_interruptible(sk->sleep);
+
+		if (sock->fasync_list)
+			sock_wake_async(sock, 2, POLL_OUT);
+	}
+}
+
 static void __tcp_data_snd_check(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
@@ -2114,7 +2142,14 @@
 	 */
 
 	    /* More than one full frame received or... */
-	if (((tp->rcv_nxt - tp->rcv_wup) > tp->ack.rcv_mss) ||
+	if (((tp->rcv_nxt - tp->rcv_wup) > tp->ack.rcv_mss
+#ifdef TCP_MORE_COARSE_ACKS
+	     /* Avoid to send immediate ACK from input path, if it
+	      * does not advance window far enough. tcp_recvmsg() will do this.
+	      */
+	     && (!sysctl_tcp_retrans_collapse || __tcp_select_window(sk) >= tp->rcv_wnd)
+#endif
+	     ) ||
 	    /* We ACK each frame or... */
 	    tcp_in_quickack_mode(tp) ||
 	    /* We have out of order data or */
@@ -2480,6 +2515,8 @@
 					TCP_SKB_CB(skb)->ack_seq, len); 
 				kfree_skb(skb); 
 				tcp_data_snd_check(sk);
+				if (tp->sorry)
+					tcp_new_space(sk);
 				return 0;
 			} else { /* Header too small */
 				TCP_INC_STATS_BH(TcpInErrs);
@@ -2633,6 +2670,8 @@
 	if(sk->state != TCP_CLOSE) {
 		tcp_data_snd_check(sk);
 		tcp_ack_snd_check(sk);
+		if (tp->sorry)
+			tcp_new_space(sk);
 	}
 
 	return 0;
@@ -2739,6 +2778,7 @@
 		newtp->saw_tstamp = 0;
 
 		newtp->probes_out = 0;
+		newtp->num_sacks = 0;
 		newtp->syn_seq = req->rcv_isn;
 		newtp->fin_seq = req->rcv_isn;
 		newtp->urg_data = 0;
@@ -3112,6 +3152,7 @@
 		tcp_sync_mss(sk, tp->pmtu_cookie);
 		tcp_initialize_rcv_mss(sk);
 		tcp_init_metrics(sk);
+		tcp_init_buffer_space(sk);
 
 		if (sk->keepopen)
 			tcp_reset_keepalive_timer(sk, keepalive_time_when(tp));
@@ -3516,6 +3557,8 @@
 	if (sk->state != TCP_CLOSE) {
 		tcp_data_snd_check(sk);
 		tcp_ack_snd_check(sk);
+		if (tp->sorry)
+			tcp_new_space(sk);
 	}
 
 	if (!queued) { 
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.99-pre3/linux/net/ipv4/tcp_ipv4.c	Mon Mar 27 08:08:34 2000
+++ linux/net/ipv4/tcp_ipv4.c	Mon Mar 27 10:35:57 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.203 2000/03/22 17:55:03 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.205 2000/03/26 09:16:08 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -1039,7 +1039,6 @@
 void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len, 
 		       struct sk_buff *skb)
 {
-	th->check = 0;
 	th->check = tcp_v4_check(th, len, sk->saddr, sk->daddr,
 				 csum_partial((char *)th, th->doff<<2, skb->csum));
 }
@@ -1057,7 +1056,7 @@
  *	Exception: precedence violation. We do not implement it in any case.
  */
 
-void tcp_v4_send_reset(struct sk_buff *skb)
+static void tcp_v4_send_reset(struct sk_buff *skb)
 {
 	struct tcphdr *th = skb->h.th;
 	struct tcphdr rth;
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.3.99-pre3/linux/net/ipv4/tcp_output.c	Sat Feb 26 22:32:08 2000
+++ linux/net/ipv4/tcp_output.c	Mon Mar 27 10:35:57 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.122 2000/02/21 15:51:41 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.123 2000/03/25 01:52:05 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -126,7 +126,7 @@
 #define SYSCTL_FLAG_SACK	0x4
 
 		sysctl_flags = 0;
-		if(tcb->flags & TCPCB_FLAG_SYN) {
+		if (tcb->flags & TCPCB_FLAG_SYN) {
 			tcp_header_size = sizeof(struct tcphdr) + TCPOLEN_MSS;
 			if(sysctl_tcp_timestamps) {
 				tcp_header_size += TCPOLEN_TSTAMP_ALIGNED;
@@ -141,7 +141,7 @@
 				if(!(sysctl_flags & SYSCTL_FLAG_TSTAMPS))
 					tcp_header_size += TCPOLEN_SACKPERM_ALIGNED;
 			}
-		} else if(tp->sack_ok && tp->num_sacks) {
+		} else if (tp->num_sacks) {
 			/* A SACK is 2 pad bytes, a 2 byte header, plus
 			 * 2 32-bit sequence numbers for each SACK block.
 			 */
@@ -157,16 +157,19 @@
 		th->dest		= sk->dport;
 		th->seq			= htonl(TCP_SKB_CB(skb)->seq);
 		th->ack_seq		= htonl(tp->rcv_nxt);
-		th->doff		= (tcp_header_size >> 2);
-		th->res1		= 0;
-		*(((__u8 *)th) + 13)	= tcb->flags;
-		th->check		= 0;
-		th->urg_ptr		= ntohs(tcb->urg_ptr);
-		if(tcb->flags & TCPCB_FLAG_SYN) {
+		*(((__u16 *)th) + 6)	= htons(((tcp_header_size >> 2) << 12) | tcb->flags);
+		if (tcb->flags & TCPCB_FLAG_SYN) {
 			/* RFC1323: The window in SYN & SYN/ACK segments
 			 * is never scaled.
 			 */
 			th->window	= htons(tp->rcv_wnd);
+		} else {
+			th->window	= htons(tcp_select_window(sk));
+		}
+		th->check		= 0;
+		th->urg_ptr		= ntohs(tcb->urg_ptr);
+
+		if (tcb->flags & TCPCB_FLAG_SYN) {
 			tcp_syn_build_options((__u32 *)(th + 1),
 					      tcp_advertise_mss(sk),
 					      (sysctl_flags & SYSCTL_FLAG_TSTAMPS),
@@ -176,13 +179,12 @@
 					      TCP_SKB_CB(skb)->when,
 		      			      tp->ts_recent);
 		} else {
-			th->window	= htons(tcp_select_window(sk));
 			tcp_build_and_update_options((__u32 *)(th + 1),
 						     tp, TCP_SKB_CB(skb)->when);
 		}
 		tp->af_specific->send_check(sk, th, skb->len, skb);
 
-		if (th->ack)
+		if (tcb->flags & TCPCB_FLAG_ACK)
 			tcp_event_ack_sent(sk);
 
 		if (skb->len != tcp_header_size)
@@ -1097,10 +1099,26 @@
 void tcp_send_delayed_ack(struct sock *sk)
 {
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	long ato = tp->ack.ato;
 	unsigned long timeout;
 
+	if (ato > TCP_DELACK_MIN) {
+		int max_ato;
+
+		/* If some rtt estimate is known, use it to bound delayed ack.
+		 * Do not use tp->rto here, use results of rtt measurements
+		 * directly.
+		 */
+		if (tp->srtt)
+			max_ato = (tp->srtt >> 3) + tp->mdev;
+		else
+			max_ato = TCP_DELACK_MAX;
+
+		ato = min(ato, max_ato);
+	}
+
 	/* Stay within the limit we were given */
-	timeout = jiffies + tp->ack.ato;
+	timeout = jiffies + ato;
 
 	/* Use new timeout only if there wasn't a older one earlier. */
 	spin_lock_bh(&sk->timer_lock);
@@ -1111,7 +1129,7 @@
 		/* If delack timer was blocked or is about to expire,
 		 * send ACK now.
 		 */
-		if (tp->ack.blocked || time_before_eq(tp->delack_timer.expires, jiffies+(tp->ack.ato>>2))) {
+		if (tp->ack.blocked || time_before_eq(tp->delack_timer.expires, jiffies+(ato>>2))) {
 			spin_unlock_bh(&sk->timer_lock);
 
 			tcp_send_ack(sk);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c
--- v2.3.99-pre3/linux/net/ipv6/icmp.c	Thu Mar  2 14:36:23 2000
+++ linux/net/ipv6/icmp.c	Mon Mar 27 10:35:57 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *
- *	$Id: icmp.c,v 1.27 2000/02/22 23:54:28 davem Exp $
+ *	$Id: icmp.c,v 1.28 2000/03/25 01:55:20 davem Exp $
  *
  *	Based on net/ipv4/icmp.c
  *
@@ -660,6 +660,7 @@
 
 	sk = icmpv6_socket->sk;
 	sk->allocation = GFP_ATOMIC;
+	sk->sndbuf = SK_WMEM_MAX*2;
 	sk->prot->unhash(sk);
 
 	inet6_add_protocol(&icmpv6_protocol);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.3.99-pre3/linux/net/ipv6/tcp_ipv6.c	Fri Mar 10 16:40:51 2000
+++ linux/net/ipv6/tcp_ipv6.c	Mon Mar 27 10:35:57 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.121 2000/03/08 19:36:47 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.122 2000/03/25 01:52:11 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -910,7 +910,6 @@
 			      struct sk_buff *skb)
 {
 	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
-	th->check = 0;
 	
 	th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 
 				    csum_partial((char *)th, th->doff<<2, 
diff -u --recursive --new-file v2.3.99-pre3/linux/net/ipx/af_spx.c linux/net/ipx/af_spx.c
--- v2.3.99-pre3/linux/net/ipx/af_spx.c	Fri Jan  7 19:13:23 2000
+++ linux/net/ipx/af_spx.c	Thu Mar 30 16:54:54 2000
@@ -89,7 +89,7 @@
 	if (sock_writeable(sk))
 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 	else
-		sk->socket->flags |= SO_NOSPACE;
+		set_bit(SOCK_ASYNC_NOSPACE,&sk->socket->flags);
 
 	return mask;
 }
@@ -231,7 +231,7 @@
                 sk->ack_backlog = 0;
                 sk->state = TCP_LISTEN;
         }
-        sk->socket->flags |= SO_ACCEPTCON;
+        sk->socket->flags |= __SO_ACCEPTCON;
 
         return (0);
 }
@@ -248,7 +248,7 @@
 		return (-EINVAL);
 	sk = sock->sk;
 
-        if((sock->state != SS_UNCONNECTED) || !(sock->flags & SO_ACCEPTCON))
+        if((sock->state != SS_UNCONNECTED) || !(sock->flags & __SO_ACCEPTCON))
                 return (-EINVAL);
         if(sock->type != SOCK_SEQPACKET)
 		return (-EOPNOTSUPP);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/khttpd/security.c linux/net/khttpd/security.c
--- v2.3.99-pre3/linux/net/khttpd/security.c	Mon Mar 27 08:08:34 2000
+++ linux/net/khttpd/security.c	Sun Apr  2 15:53:28 2000
@@ -115,14 +115,12 @@
 
 	lock_kernel();
 		
-	filp = filp_open(Filename, 0, O_RDONLY, NULL);
+	filp = filp_open(Filename, O_RDONLY, 0);
 	
 	unlock_kernel();
 	
-	if ((IS_ERR(filp))||(filp==NULL)||(filp->f_dentry==NULL))
-	{
+	if (IS_ERR(filp))
 		return NULL;
-	}
 
 #ifndef BENCHMARK		
 	permission = filp->f_dentry->d_inode->i_mode;
diff -u --recursive --new-file v2.3.99-pre3/linux/net/khttpd/sockets.c linux/net/khttpd/sockets.c
--- v2.3.99-pre3/linux/net/khttpd/sockets.c	Sun Feb 13 19:29:04 2000
+++ linux/net/khttpd/sockets.c	Mon Mar 27 10:35:57 2000
@@ -79,7 +79,6 @@
 	error=sock->ops->listen(sock,48);	
 	if (error!=0)
 		(void)printk(KERN_ERR "kHTTPd: Error listening on socket \n");
-	sock->flags |= SO_ACCEPTCON;	
 	
 	MainSocket = sock;
 	
diff -u --recursive --new-file v2.3.99-pre3/linux/net/khttpd/waitheaders.c linux/net/khttpd/waitheaders.c
--- v2.3.99-pre3/linux/net/khttpd/waitheaders.c	Fri Jan 28 15:09:09 2000
+++ linux/net/khttpd/waitheaders.c	Sun Apr  2 15:53:28 2000
@@ -239,7 +239,6 @@
 		return 0;
 	}
 	else
-	if ((Request->filp->f_dentry!=NULL)&&(Request->filp->f_dentry->d_inode!=NULL))
 	{
 		Request->FileLength = (int)Request->filp->f_dentry->d_inode->i_size;
 		Request->Time       = Request->filp->f_dentry->d_inode->i_mtime;
@@ -262,12 +261,6 @@
 		}
 		
 	
-	} else 
-	{
-		/* Ehhh... */
-		
-		printk(KERN_CRIT "kHTTPd: Unexpected filesystem response\n");
-		return -1;	
 	}
 	
 	LeaveFunction("DecodeHeader");
diff -u --recursive --new-file v2.3.99-pre3/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- v2.3.99-pre3/linux/net/netlink/af_netlink.c	Fri Jan 28 15:09:09 2000
+++ linux/net/netlink/af_netlink.c	Mon Mar 27 10:35:57 2000
@@ -436,7 +436,7 @@
 
 		if (signal_pending(current)) {
 			kfree_skb(skb);
-			return -ERESTARTSYS;
+			return sock_intr_errno(timeo);
 		}
 		goto retry;
 	}
diff -u --recursive --new-file v2.3.99-pre3/linux/net/netsyms.c linux/net/netsyms.c
--- v2.3.99-pre3/linux/net/netsyms.c	Sun Mar 19 18:35:31 2000
+++ linux/net/netsyms.c	Mon Mar 27 10:35:57 2000
@@ -340,7 +340,6 @@
 EXPORT_SYMBOL(tcp_v4_rebuild_header);
 EXPORT_SYMBOL(tcp_v4_send_check);
 EXPORT_SYMBOL(tcp_v4_conn_request);
-EXPORT_SYMBOL(tcp_v4_send_reset);
 EXPORT_SYMBOL(tcp_create_openreq_child);
 EXPORT_SYMBOL(tcp_bucket_create);
 EXPORT_SYMBOL(__tcp_put_port);
@@ -594,6 +593,51 @@
 EXPORT_SYMBOL(nf_hooks);
 EXPORT_SYMBOL(nf_setsockopt);
 EXPORT_SYMBOL(nf_getsockopt);
+#endif
+
+#ifdef CONFIG_IP_NF_CONNTRACK
+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+EXPORT_SYMBOL(ip_conntrack_protocol_register);
+EXPORT_SYMBOL(invert_tuplepr);
+EXPORT_SYMBOL(ip_conntrack_alter_reply);
+EXPORT_SYMBOL(ip_conntrack_destroyed);
+EXPORT_SYMBOL(ip_conntrack_get);
+EXPORT_SYMBOL(ip_conntrack_module);
+EXPORT_SYMBOL(ip_conntrack_helper_register);
+EXPORT_SYMBOL(ip_conntrack_helper_unregister);
+EXPORT_SYMBOL(ip_ct_selective_cleanup);
+EXPORT_SYMBOL(ip_ct_refresh);
+EXPORT_SYMBOL(ip_conntrack_expect_related);
+EXPORT_SYMBOL(ip_conntrack_tuple_taken);
+EXPORT_SYMBOL(ip_ct_gather_frags);
+#ifdef CONFIG_IP_NF_FTP
+#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+EXPORT_SYMBOL(ip_ftp_lock);
+#endif
+#endif /*CONFIG_IP_NF_CONNTRACK*/
+
+#ifdef CONFIG_IP_NF_NAT
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+EXPORT_SYMBOL(ip_nat_setup_info);
+EXPORT_SYMBOL(ip_nat_helper_register);
+EXPORT_SYMBOL(ip_nat_helper_unregister);
+EXPORT_SYMBOL(ip_nat_expect_register);
+EXPORT_SYMBOL(ip_nat_expect_unregister);
+EXPORT_SYMBOL(ip_nat_cheat_check);
+#endif
+
+#ifdef CONFIG_IP_NF_IPTABLES
+#include <linux/netfilter_ipv4/ip_tables.h>
+EXPORT_SYMBOL(ipt_register_table);
+EXPORT_SYMBOL(ipt_unregister_table);
+EXPORT_SYMBOL(ipt_register_target);
+EXPORT_SYMBOL(ipt_unregister_target);
+EXPORT_SYMBOL(ipt_register_match);
+EXPORT_SYMBOL(ipt_unregister_match);
 #endif
 
 EXPORT_SYMBOL(register_gifconf);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/socket.c linux/net/socket.c
--- v2.3.99-pre3/linux/net/socket.c	Sat Feb 12 11:22:11 2000
+++ linux/net/socket.c	Mon Mar 27 10:35:57 2000
@@ -690,20 +690,17 @@
 	switch (how)
 	{
 	case 1:
-		if (sock->flags & SO_WAITDATA)
+		
+		if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
 			break;
 		goto call_kill;
 	case 2:
-		if (!(sock->flags & SO_NOSPACE))
+		if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags))
 			break;
-		sock->flags &= ~SO_NOSPACE;
 		/* fall through */
 	case 0:
 	call_kill:
-		/* read_lock(&sock->sk->callback_lock); */
-		if(sock->fasync_list != NULL)
-			kill_fasync(sock->fasync_list, SIGIO, band);
-		/* read_unlock(&sock->sk->callback_lock); */
+		kill_fasync(sock->fasync_list, SIGIO, band);
 		break;
 	case 3:
 		kill_fasync(sock->fasync_list, SIGURG, band);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c
--- v2.3.99-pre3/linux/net/sunrpc/clnt.c	Mon Mar 27 08:08:34 2000
+++ linux/net/sunrpc/clnt.c	Mon Apr  3 13:24:06 2000
@@ -32,6 +32,8 @@
 
 #include <linux/sunrpc/clnt.h>
 
+#include <linux/nfs.h>
+
 
 #define RPC_SLACK_SPACE		1024	/* total overkill */
 
@@ -78,6 +80,7 @@
 #ifdef RPC_DEBUG
 	rpc_register_sysctl();
 #endif
+	xdr_init();
 
 	if (!xprt)
 		goto out;
@@ -198,7 +201,6 @@
 static void
 rpc_default_callback(struct rpc_task *task)
 {
-	rpc_release_task(task);
 }
 
 /*
@@ -263,9 +265,10 @@
 	/* Set up the call info struct and execute the task */
 	if (task->tk_status == 0)
 		status = rpc_execute(task);
-	else
+	else {
 		status = task->tk_status;
-	rpc_release_task(task);
+		rpc_release_task(task);
+	}
 
 	rpc_clnt_sigunmask(clnt, &oldset);		
 
@@ -344,10 +347,9 @@
 void
 rpc_restart_call(struct rpc_task *task)
 {
-	if (task->tk_flags & RPC_TASK_KILLED) {
-		rpc_release_task(task);
+	if (RPC_ASSASSINATED(task))
 		return;
-	}
+
 	task->tk_action = call_reserve;
 	rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
 }
@@ -715,7 +717,7 @@
 	 * The following is an NFS-specific hack to cater for setuid
 	 * processes whose uid is mapped to nobody on the server.
 	 */
-	if (task->tk_client->cl_prog == 100003 && 
+	if (task->tk_client->cl_prog == NFS_PROGRAM && 
             (ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) {
 		if (RPC_IS_SETUID(task) && task->tk_suid_retry) {
 			dprintk("RPC: %4d retry squashed uid\n", task->tk_pid);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.3.99-pre3/linux/net/sunrpc/sched.c	Mon Mar 27 08:08:34 2000
+++ linux/net/sunrpc/sched.c	Wed Apr  5 16:58:38 2000
@@ -508,6 +508,7 @@
 		return 0;
 	}
 
+ restarted:
 	while (1) {
 		/*
 		 * Execute any pending callback.
@@ -586,10 +587,29 @@
 		}
 	}
 
+	if (task->tk_exit) {
+		task->tk_exit(task);
+		/* If tk_action is non-null, the user wants us to restart */
+		if (task->tk_action) {
+			if (!RPC_ASSASSINATED(task)) {
+				/* Release RPC slot and buffer memory */
+				if (task->tk_rqstp)
+					xprt_release(task);
+				if (task->tk_buffer) {
+					rpc_free(task->tk_buffer);
+					task->tk_buffer = NULL;
+				}
+				goto restarted;
+			}
+			printk(KERN_ERR "RPC: dead task tries to walk away.\n");
+		}
+	}
+
 	dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status);
 	status = task->tk_status;
-	if (task->tk_exit)
-		task->tk_exit(task);
+
+	/* Release all resources associated with the task */
+	rpc_release_task(task);
 
 	return status;
 }
@@ -599,22 +619,32 @@
  *
  * This may be called recursively if e.g. an async NFS task updates
  * the attributes and finds that dirty pages must be flushed.
+ * NOTE: Upon exit of this function the task is guaranteed to be
+ *	 released. In particular note that tk_release() will have
+ *	 been called, so your task memory may have been freed.
  */
 int
 rpc_execute(struct rpc_task *task)
 {
+	int status = -EIO;
 	if (rpc_inhibit) {
 		printk(KERN_INFO "RPC: execution inhibited!\n");
-		return -EIO;
+		goto out_release;
 	}
-	task->tk_flags |= RPC_TASK_RUNNING;
+
+	status = -EWOULDBLOCK;
 	if (task->tk_active) {
 		printk(KERN_ERR "RPC: active task was run twice!\n");
-		return -EWOULDBLOCK;
+		goto out_err;
 	}
+
 	task->tk_active = 1;
-	
+	task->tk_flags |= RPC_TASK_RUNNING;
 	return __rpc_execute(task);
+ out_release:
+	rpc_release_task(task);
+ out_err:
+	return status;
 }
 
 /*
@@ -700,7 +730,7 @@
 		}
 		if (flags & RPC_TASK_ASYNC)
 			return NULL;
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ>>4);
 	} while (!signalled());
 
@@ -758,6 +788,13 @@
 				current->pid);
 }
 
+static void
+rpc_default_free_task(struct rpc_task *task)
+{
+	dprintk("RPC: %4d freeing task\n", task->tk_pid);
+	rpc_free(task);
+}
+
 /*
  * Create a new task for the specified client.  We have to
  * clean up after an allocation failure, as the client may
@@ -774,6 +811,9 @@
 
 	rpc_init_task(task, clnt, callback, flags);
 
+	/* Replace tk_release */
+	task->tk_release = rpc_default_free_task;
+
 	dprintk("RPC: %4d allocated task\n", task->tk_pid);
 	task->tk_flags |= RPC_TASK_DYNAMIC;
 out:
@@ -849,12 +889,8 @@
 #ifdef RPC_DEBUG
 	task->tk_magic = 0;
 #endif
-
-	if (task->tk_flags & RPC_TASK_DYNAMIC) {
-		dprintk("RPC: %4d freeing task\n", task->tk_pid);
-		task->tk_flags &= ~RPC_TASK_DYNAMIC;
-		rpc_free(task);
-	}
+	if (task->tk_release)
+		task->tk_release(task);
 }
 
 /*
@@ -886,7 +922,6 @@
 		__rpc_wake_up(parent);
 	}
 	spin_unlock_bh(&rpc_queue_lock);
-	rpc_release_task(child);
 }
 
 /*
@@ -1028,7 +1063,7 @@
 		__rpc_schedule();
 		if (all_tasks) {
 			dprintk("rpciod_killall: waiting for tasks to exit\n");
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(1);
 		}
 	}
@@ -1099,7 +1134,7 @@
 	 * wait briefly before checking the process id.
 	 */
 	current->sigpending = 0;
-	current->state = TASK_INTERRUPTIBLE;
+	set_current_state(TASK_INTERRUPTIBLE);
 	schedule_timeout(1);
 	/*
 	 * Display a message if we're going to wait longer.
diff -u --recursive --new-file v2.3.99-pre3/linux/net/sunrpc/sunrpc_syms.c linux/net/sunrpc/sunrpc_syms.c
--- v2.3.99-pre3/linux/net/sunrpc/sunrpc_syms.c	Mon Mar 27 08:08:34 2000
+++ linux/net/sunrpc/sunrpc_syms.c	Mon Apr  3 13:24:06 2000
@@ -27,7 +27,6 @@
 EXPORT_SYMBOL(rpc_free);
 EXPORT_SYMBOL(rpc_execute);
 EXPORT_SYMBOL(rpc_init_task);
-EXPORT_SYMBOL(rpc_release_task);
 EXPORT_SYMBOL(rpc_sleep_on);
 EXPORT_SYMBOL(rpc_wake_up_next);
 EXPORT_SYMBOL(rpc_wake_up_task);
@@ -89,12 +88,15 @@
 #endif
 
 /* Generic XDR */
+EXPORT_SYMBOL(xdr_encode_array);
 EXPORT_SYMBOL(xdr_encode_string);
 EXPORT_SYMBOL(xdr_decode_string);
 EXPORT_SYMBOL(xdr_decode_netobj);
 EXPORT_SYMBOL(xdr_encode_netobj);
 EXPORT_SYMBOL(xdr_zero);
 EXPORT_SYMBOL(xdr_one);
+EXPORT_SYMBOL(xdr_shift_iovec);
+EXPORT_SYMBOL(xdr_zero_iovec);
 
 /* RPC errors */
 EXPORT_SYMBOL(rpc_success);
diff -u --recursive --new-file v2.3.99-pre3/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- v2.3.99-pre3/linux/net/sunrpc/svcsock.c	Sun Mar 19 18:35:31 2000
+++ linux/net/sunrpc/svcsock.c	Wed Apr  5 16:58:38 2000
@@ -769,7 +769,7 @@
 		 * We have to be able to interrupt this wait
 		 * to bring down the daemons ...
 		 */
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&rqstp->rq_wait, &wait);
 		spin_unlock_bh(&serv->sv_lock);
 
@@ -940,7 +940,6 @@
 	if (protocol == IPPROTO_TCP) {
 		if ((error = sock->ops->listen(sock, 5)) < 0)
 			goto bummer;
-		sock->flags |= SO_ACCEPTCON;
 	}
 
 	if ((svsk = svc_setup_socket(serv, sock, &error, 1)) != NULL)
diff -u --recursive --new-file v2.3.99-pre3/linux/net/sunrpc/xdr.c linux/net/sunrpc/xdr.c
--- v2.3.99-pre3/linux/net/sunrpc/xdr.c	Mon Apr  7 11:35:33 1997
+++ linux/net/sunrpc/xdr.c	Sat Apr  1 08:04:27 2000
@@ -9,6 +9,7 @@
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/string.h>
+#include <linux/kernel.h>
 #include <linux/in.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/msg_prot.h>
@@ -56,8 +57,8 @@
 {
 	unsigned int	quadlen = XDR_QUADLEN(obj->len);
 
+	p[quadlen] = 0;		/* zero trailing bytes */
 	*p++ = htonl(obj->len);
-	p[quadlen-1] = 0;	/* zero trailing bytes */
 	memcpy(p, obj->data, obj->len);
 	return p + XDR_QUADLEN(obj->len);
 }
@@ -84,18 +85,23 @@
 }
 
 u32 *
-xdr_encode_string(u32 *p, const char *string)
+xdr_encode_array(u32 *p, const char *array, unsigned int len)
 {
-	int len = strlen(string);
 	int quadlen = XDR_QUADLEN(len);
 
 	p[quadlen] = 0;
 	*p++ = htonl(len);
-	memcpy(p, string, len);
+	memcpy(p, array, len);
 	return p + quadlen;
 }
 
 u32 *
+xdr_encode_string(u32 *p, const char *string)
+{
+	return xdr_encode_array(p, string, strlen(string));
+}
+
+u32 *
 xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen)
 {
 	unsigned int	len;
@@ -116,3 +122,51 @@
 	return p + XDR_QUADLEN(len);
 }
 
+/*
+ * Realign the iovec if the server missed out some reply elements
+ * (such as post-op attributes,...)
+ * Note: This is a simple implementation that assumes that
+ *            len <= iov->iov_len !!!
+ *       The RPC header (assumed to be the 1st element in the iov array)
+ *            is not shifted.
+ */
+void xdr_shift_iovec(struct iovec *iov, int nr, size_t len)
+{
+	struct iovec *pvec;
+
+	for (pvec = iov + nr - 1; nr > 1; nr--, pvec--) {
+		struct iovec *svec = pvec - 1;
+
+		if (len > pvec->iov_len) {
+			printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
+			return;
+		}
+		memmove((char *)pvec->iov_base + len, pvec->iov_base,
+			pvec->iov_len - len);
+
+		if (len > svec->iov_len) {
+			printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
+			return;
+		}
+		memcpy(pvec->iov_base,
+		       (char *)svec->iov_base + svec->iov_len - len, len);
+	}
+}
+
+/*
+ * Zero the last n bytes in an iovec array of 'nr' elements
+ */
+void xdr_zero_iovec(struct iovec *iov, int nr, size_t n)
+{
+	struct iovec *pvec;
+
+	for (pvec = iov + nr - 1; n && nr > 0; nr--, pvec--) {
+		if (n < pvec->iov_len) {
+			memset((char *)pvec->iov_base + pvec->iov_len - n, 0, n);
+			n = 0;
+		} else {
+			memset(pvec->iov_base, 0, pvec->iov_len);
+			n -= pvec->iov_len;
+		}
+	}
+}
diff -u --recursive --new-file v2.3.99-pre3/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- v2.3.99-pre3/linux/net/sunrpc/xprt.c	Mon Mar 27 08:08:34 2000
+++ linux/net/sunrpc/xprt.c	Wed Apr  5 16:58:38 2000
@@ -48,6 +48,7 @@
 #include <linux/version.h>
 #include <linux/types.h>
 #include <linux/malloc.h>
+#include <linux/capability.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/socket.h>
@@ -227,7 +228,7 @@
 		 */
 		break;
 	case -EAGAIN:
-		if (sock->flags & SO_NOSPACE)
+		if (test_bit(SOCK_NOSPACE, &sock->flags))
 			result = -ENOMEM;
 		break;
 	case -ENOTCONN:
@@ -1569,8 +1570,8 @@
 		goto failed;
 	}
 
-	/* If the caller has root privs, bind to a reserved port */
-	if (!current->fsuid && xprt_bindresvport(sock) < 0)
+	/* If the caller has the capability, bind to a reserved port */
+	if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0)
 		goto failed;
 
 	return sock;
diff -u --recursive --new-file v2.3.99-pre3/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.3.99-pre3/linux/net/unix/af_unix.c	Sun Mar 19 18:35:31 2000
+++ linux/net/unix/af_unix.c	Fri Apr  7 13:38:00 2000
@@ -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.90 2000/03/16 20:38:45 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.91 2000/03/25 01:55:34 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -297,9 +297,10 @@
 static void unix_write_space(struct sock *sk)
 {
 	read_lock(&sk->callback_lock);
-	if (!sk->dead && unix_writable(sk)) {
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 2, POLL_OUT);
+	if (unix_writable(sk)) {
+		if (sk->sleep && waitqueue_active(sk->sleep))
+			wake_up_interruptible(sk->sleep);
+		sk_wake_async(sk, 2, POLL_OUT);
 	}
 	read_unlock(&sk->callback_lock);
 }
@@ -356,8 +357,10 @@
 			if (!skb_queue_empty(&sk->receive_queue) || embrion)
 				skpair->err = ECONNRESET;
 			unix_state_wunlock(skpair);
-			sk->state_change(skpair);
-			sock_wake_async(sk->socket,1,POLL_HUP);
+			skpair->state_change(skpair);
+			read_lock(&skpair->callback_lock);
+			sk_wake_async(skpair,1,POLL_HUP);
+			read_unlock(&skpair->callback_lock);
 		}
 		sock_put(skpair); /* It may now die */
 		unix_peer(sk) = NULL;
@@ -418,7 +421,6 @@
 		wake_up_interruptible_all(&sk->protinfo.af_unix.peer_wait);
 	sk->max_ack_backlog=backlog;
 	sk->state=TCP_LISTEN;
-	sock->flags |= SO_ACCEPTCON;
 	/* set credentials so connect can copy them */
 	sk->peercred.pid = current->pid;
 	sk->peercred.uid = current->euid;
@@ -562,39 +564,51 @@
 				    int type, unsigned hash, int *error)
 {
 	unix_socket *u;
+	struct dentry *dentry;
+	int err;
 	
-	if (sunname->sun_path[0])
-	{
-		struct dentry *dentry;
-
+	if (sunname->sun_path[0]) {
 		/* Do not believe to VFS, grab kernel lock */
 		lock_kernel();
-		dentry = __open_namei(sunname->sun_path, 2|O_NOFOLLOW, S_IFSOCK, NULL);
+		dentry = lookup_dentry(sunname->sun_path,LOOKUP_POSITIVE);
+		err = PTR_ERR(dentry);
 		if (IS_ERR(dentry)) {
-			*error = PTR_ERR(dentry);
 			unlock_kernel();
-			return NULL;
+			goto fail;
 		}
+		err = permission(dentry->d_inode,MAY_WRITE);
+		if (err)
+			goto put_fail;
+
+		err = -ECONNREFUSED;
+		if (!S_ISSOCK(dentry->d_inode->i_mode))
+			goto put_fail;
 		u=unix_find_socket_byinode(dentry->d_inode);
+		if (!u)
+			goto put_fail;
+
 		dput(dentry);
 		unlock_kernel();
 
-		if (u && u->type != type)
-		{
-			*error=-EPROTOTYPE;
+		err=-EPROTOTYPE;
+		if (u->type != type) {
 			sock_put(u);
-			return NULL;
+			goto fail;
 		}
-	}
-	else
+	} else {
+		err = -ECONNREFUSED;
 		u=unix_find_socket_byname(sunname, len, type, hash);
-
-	if (u==NULL)
-	{
-		*error=-ECONNREFUSED;
-		return NULL;
+		if (!u)
+			goto fail;
 	}
 	return u;
+
+put_fail:
+	dput(dentry);
+	unlock_kernel();
+fail:
+	*error=err;
+	return NULL;
 }
 
 
@@ -827,7 +841,7 @@
 
 		timeo = unix_wait_for_peer(other, timeo);
 
-		err = -ERESTARTSYS;
+		err = sock_intr_errno(timeo);
 		if (signal_pending(current))
 			goto out;
 		sock_put(other);
@@ -1156,7 +1170,7 @@
 
 		timeo = unix_wait_for_peer(other, timeo);
 
-		err = -ERESTARTSYS;
+		err = sock_intr_errno(timeo);
 		if (signal_pending(current))
 			goto out_free;
 
@@ -1228,8 +1242,8 @@
 		 *	much.
 		 */
 
-		if (size > 4096-16)
-			limit = 4096-16; /* Fall back to a page if we can't grab a big buffer this instant */
+		if (size > PAGE_SIZE-16)
+			limit = PAGE_SIZE-16; /* Fall back to a page if we can't grab a big buffer this instant */
 		else
 			limit = 0;	/* Otherwise just grab and wait */
 
@@ -1383,11 +1397,11 @@
 		    !timeo)
 			break;
 
-		sk->socket->flags |= SO_WAITDATA;
+		set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 		unix_state_runlock(sk);
 		timeo = schedule_timeout(timeo);
 		unix_state_rlock(sk);
-		sk->socket->flags &= ~SO_WAITDATA;
+		clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 	}
 
 	__set_current_state(TASK_RUNNING);
@@ -1455,7 +1469,7 @@
 			timeo = unix_stream_data_wait(sk, timeo);
 
 			if (signal_pending(current)) {
-				err = -ERESTARTSYS;
+				err = sock_intr_errno(timeo);
 				goto out;
 			}
 			down(&sk->protinfo.af_unix.readsem);
@@ -1556,10 +1570,12 @@
 			other->shutdown |= peer_mode;
 			unix_state_wunlock(other);
 			other->state_change(other);
+			read_lock(&other->callback_lock);
 			if (peer_mode == SHUTDOWN_MASK)
-				sock_wake_async(other->socket,1,POLL_HUP);
+				sk_wake_async(other,1,POLL_HUP);
 			else if (peer_mode & RCV_SHUTDOWN)
-				sock_wake_async(other->socket,1,POLL_IN);
+				sk_wake_async(other,1,POLL_IN);
+			read_unlock(&other->callback_lock);
 		}
 		if (other)
 			sock_put(other);
@@ -1658,7 +1674,7 @@
 			s,
 			atomic_read(&s->refcnt),
 			0,
-			s->state == TCP_LISTEN ? SO_ACCEPTCON : 0,
+			s->state == TCP_LISTEN ? __SO_ACCEPTCON : 0,
 			s->type,
 			s->socket ?
 			(s->state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) :
diff -u --recursive --new-file v2.3.99-pre3/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.3.99-pre3/linux/scripts/Menuconfig	Sun Feb 20 21:12:40 2000
+++ linux/scripts/Menuconfig	Sun Apr  2 17:28:22 2000
@@ -404,7 +404,7 @@
 		$DIALOG	--backtitle "$backtitle" \
 			--textbox help.out $ROWS $COLS
 	fi
-	rm help.out
+	rm -f help.out
 }
 
 #
@@ -1362,7 +1362,7 @@
 
 DIALOG="./scripts/lxdialog/lxdialog"
 
-kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}"
+kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
 
 backtitle="Linux Kernel v$kernel_version Configuration"
 
@@ -1450,4 +1450,10 @@
 	echo Your kernel configuration changes were NOT saved.
 	echo
 fi
+
+# Remove log if empty.
+if [ ! -s .menuconfig.log ] ; then
+	rm -f .menuconfig.log
+fi
+
 exit 0
diff -u --recursive --new-file v2.3.99-pre3/linux/scripts/checkincludes.pl linux/scripts/checkincludes.pl
--- v2.3.99-pre3/linux/scripts/checkincludes.pl	Wed Dec 31 16:00:00 1969
+++ linux/scripts/checkincludes.pl	Sun Apr  2 17:28:22 2000
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+#
+# checkincludes: Find files included more than once in (other) files.
+# Copyright abandoned, 2000, Niels Kristian Bech Jensen <nkbj@image.dk>.
+
+foreach $file (@ARGV) {
+	open(FILE, $file) or die "Cannot open $file: $!.\n";
+
+	my %includedfiles = ();
+
+	while (<FILE>) {
+		if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) {
+			++$includedfiles{$1};
+		}
+	}
+	
+	foreach $filename (keys %includedfiles) {
+		if ($includedfiles{$filename} > 1) {
+			print "$file: $filename is included more than once.\n";
+		}
+	}
+
+	close(FILE);
+}
diff -u --recursive --new-file v2.3.99-pre3/linux/scripts/docproc.c linux/scripts/docproc.c
--- v2.3.99-pre3/linux/scripts/docproc.c	Tue Mar 14 19:10:40 2000
+++ linux/scripts/docproc.c	Mon Mar 27 14:17:05 2000
@@ -12,7 +12,7 @@
 int main(int argc, char *argv[])
 {
 	char buf[1024];
-	char *vec[1024];
+	char *vec[8192];
 	char type[64];
 	int i;
 	int vp=2;
@@ -30,7 +30,7 @@
 	 */
 	vec[0]="kernel-doc";
 	vec[1]="-docbook";
-	for(i=1;vp<1021;i++)
+	for(i=1;vp<8189;i++)
 	{
 		if(argv[i]==NULL)
 			break;
@@ -67,7 +67,7 @@
 					exit(1);
 				case  0:
 					execvp("scripts/kernel-doc", vec);
-					perror("exec");
+					perror("exec scripts/kernel-doc");
 					exit(1);
 				default:
 					waitpid(pid, NULL,0);
diff -u --recursive --new-file v2.3.99-pre3/linux/scripts/gen-all-syms linux/scripts/gen-all-syms
--- v2.3.99-pre3/linux/scripts/gen-all-syms	Tue Mar 14 19:10:40 2000
+++ linux/scripts/gen-all-syms	Sun Apr  2 15:38:54 2000
@@ -3,5 +3,5 @@
 do
 	grep "EXPORT_SYMBOL.*(.*)" "$i" \
 		| sed -e "s/EXPORT_SYMBOL.*(/  /" \
-		| sed -e "s/).*$//"
+		| sed -e "s/).*$//" | sed -e "s/^  //"
 done
diff -u --recursive --new-file v2.3.99-pre3/linux/scripts/kernel-doc linux/scripts/kernel-doc
--- v2.3.99-pre3/linux/scripts/kernel-doc	Tue Mar 14 19:10:40 2000
+++ linux/scripts/kernel-doc	Mon Mar 27 14:17:05 2000
@@ -238,6 +238,7 @@
 	if ($line eq ""){
 	    print $lineprefix, $blankline;
 	} else {
+            $line =~ s/\\\\\\/\&/g;
 	    print $lineprefix, $line;
 	}
 	print "\n";
@@ -640,6 +641,12 @@
 	    }
 	    $type = join " ", @args;
 
+	    if ($type eq "" && $param eq "...")
+	    {
+		$type="...";
+		$param="...";
+		$parameters{"..."} = "variable arguments";
+	    }
 	    if ($type eq "")
 	    {
 		$type="";
@@ -753,6 +760,9 @@
 		$newcontents = $2;
 
 		if ($contents ne "") {
+		    $contents =~ s/\&/\\\\\\amp;/g;
+		    $contents =~ s/\</\\\\\\lt;/g;
+		    $contents =~ s/\>/\\\\\\gt;/g;
 		    dump_section($section, $contents);
 		    $section = $section_default;
 		}
@@ -765,6 +775,9 @@
 	    } elsif (/$doc_end/) {
 
 		if ($contents ne "") {
+		    $contents =~ s/\&/\\\\\\amp;/g;
+		    $contents =~ s/\</\\\\\\lt;/g;
+		    $contents =~ s/\>/\\\\\\gt;/g;
 		    dump_section($section, $contents);
 		    $section = $section_default;
 		    $contents = "";
@@ -777,6 +790,9 @@
 		# miguel-style comment kludge, look for blank lines after
 		# @parameter line to signify start of description
 		if ($1 eq "" && $section =~ m/^@/) {
+		    $contents =~ s/\&/\\\\\\amp;/g;
+		    $contents =~ s/\</\\\\\\lt;/g;
+		    $contents =~ s/\>/\\\\\\gt;/g;
 		    dump_section($section, $contents);
 		    $section = $section_default;
 		    $contents = "";
