diff -u --recursive --new-file v2.3.19/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.19/linux/Documentation/Configure.help	Fri Sep 10 23:57:27 1999
+++ linux/Documentation/Configure.help	Thu Oct  7 21:32:14 1999
@@ -5,29 +5,35 @@
 #
 # Translations of this file available on the WWW:
 #
-#   - Japanese, by Tetsuyasu YAMADA (tetsu@cauchy.nslab.ntt.co.jp), at
-#     http://jf.gee.kyoto-u.ac.jp/JF/JF-ftp/euc/Configure.help.euc
+#   - Japanese, maintained by the JF Project (JF@linux.or.jp), at
+#     http://www.linux.or.jp/JF/JFdocs/Configure.help/
 #   - Russian, by kaf@linux.nevod.perm.su, at
 #     http://nevod.perm.su/service/linux/doc/kernel/Configure.help
-#   - French, by David Bourgin (dbourgin@wsc.com), at
-#     http://www.linux-kheops.com/traduc/kernels/
+#   - French, by Tane Pierre (tanep@bigfoot.com), at
+#     http://www.kernelfr.org
 #   - Spanish, by Carlos Perelló Marín (fperllo@ehome.encis.es), at
 #     http://visar.csustan.edu/~carlos/
 #   - Italian, by Alessandro Rubini (rubini@linux.it), at
 #     ftp://ftp-pavia1.linux.it/pub/linux/Configure.help
 #   - Polish, by Cezar Cichocki (cezar@cs.net.pl), at
 #     http://www.cs.net.pl/~cezar/Kernel
-#   - German, by Jörg Strebel (jstrebel@suse.de) and Karl Eichwalder
-#     (ke@suse.de), at http://www.suse.de/~ke/kernel/Configure.de.help.gz
+#   - German, by SuSE, at http://www.suse.de/~ke/kernel . This patch
+#     includes infrastructure to support different languages as well.
+#
+# To access a document on the WWW, you need to have a direct Internet
+# connection and a browser program such as netscape or lynx. If you
+# only have email access, you can still use FTP and WWW servers: send
+# an email to mail-server@rtfm.mit.edu with the text 
+#   send usenet/news.answers/internet-services/access-via-email 
+# in the body of the message.
 #
 # Information about what a kernel is, what it does, how to patch and
 # compile it and much more is contained in the Kernel-HOWTO, available
-# via FTP (user: anonymous) from metalab.unc.edu in the directory
-# /pub/Linux/docs/HOWTO. Before you start compiling, make sure that
-# you have the necessary versions of all programs and libraries
-# required to compile and run this kernel; they are listed in the file
-# Documentation/Changes. Make sure to read the toplevel kernel README 
-# file as well.
+# at http://metalab.unc.edu/mdw/linux.html#howto . Before you start
+# compiling, make sure that you have the necessary versions of all
+# programs and libraries required to compile and run this kernel; they
+# are listed in the file Documentation/Changes. Make sure to read the
+# toplevel kernel README file as well.
 #
 # Format of this file: description<nl>variable<nl>help text<nl><nl>. If
 # the question being documented is of type "choice", we list only the
@@ -104,9 +110,7 @@
 
   See also: Documentation/SMP.txt, Documentation/smp.tex,
   Documentation/smp.txt, and Documentation/IO-APIC.txt.  Also see the
-  SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ (to
-  browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape).
+  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.
   
@@ -126,39 +130,38 @@
   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 via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.) This means that it is a
-  good idea to say Y here if you intend to use this kernel on
-  different machines. 
+  available from http://metalab.unc.edu/mdw/linux.html#howto .) 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.
 
   If you are not sure, say Y; apart from resulting in a 45 KB bigger
   kernel, it won't hurt.
-  
+
 Timer and CPU usage LEDs
 CONFIG_LEDS
-  If you define this option, the LEDs on your machine will be used
+  If you say Y here, the LEDs on your machine will be used
   to provide useful information about your current system status.
 
-  If you are compiling a kernel for a NetWinder or EBSA-285, you
-  will be able to select which LEDs are active using the options
-  below. If you are compiling a kernel for the EBSA-110 however,
-  the red LED will simply flash regularly to indicate that the
-  system is still functional. It is still safe to say yes here if
-  you have a CATS system, but the driver will do nothing.
+  If you are compiling a kernel for a NetWinder or EBSA-285, you will
+  be able to select which LEDs are active using the options below. If
+  you are compiling a kernel for the EBSA-110 however, the red LED
+  will simply flash regularly to indicate that the system is still
+  functional. It is safe to say Y here if you have a CATS system, but
+  the driver will do nothing.
 
 Timer LED
 CONFIG_LEDS_TIMER
-  If you say yes here, one of the system LEDs (the green one on the
+  If you say Y here, one of the system LEDs (the green one on the
   NetWinder or the amber one on the EBSA285) will flash regularly to
   indicate that the system is still operational. This is mainly
   useful to kernel hackers who are debugging unstable kernels.
 
 CPU usage LED
 CONFIG_LEDS_CPU
-  If you say yes here, the red LED will be used to give a good real
+  If you say Y here, the red LED will be used to give a good real
   time indication of CPU usage, by lighting whenever the idle task
   is not currently executing.
 
@@ -170,8 +173,16 @@
 
 Big memory support
 CONFIG_BIGMEM
-  This option is required if you want to utilize physical memory which
-  is not covered by the kernel virtual address space (> 1GB).
+  Linux can use up to 2 Gigabytes (= 2^31 bytes) of physical memory.
+  If you are compiling a kernel which will never run on a machine with
+  more than 1 Gigabyte, answer N here. Otherwise, say Y.
+
+  The actual amount of physical memory should be specified using a
+  kernel command line option such as "mem=256M". (Try "man bootparam"
+  or see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel at boot time. The lilo procedure
+  is also explained in the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .)
 
 Normal PC floppy disk support
 CONFIG_BLK_DEV_FD
@@ -238,16 +249,16 @@
   on a remote file server. If you want to do this, you will first have
   to acquire and install a kernel patch from
   ftp://ftp.replay.com/pub/crypto/linux/all or
-  ftp://verden.pvv.org/pub/linux/kerneli/v2.1/, and then you need to
+  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 filesystems are provided
-  by the cfs package, which can be gotten via FTP (user: anonymous)
-  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 filesystem support" below while using tcfs
-  requires applying a kernel patch.
+  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 filesystem 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
@@ -295,8 +306,8 @@
 CONFIG_BLK_DEV_IDE
   If you say Y here, you will use the full-featured IDE driver to
   control up to eight IDE interfaces, each being able to serve a
-  "master" and a "slave" device, for a total of up to sixteen (16)
-  IDE disk/cdrom/tape/floppy drives.  People with SCSI-only systems
+  "master" and a "slave" device, for a total of up to sixteen IDE
+  disk/cdrom/tape/floppy drives. People with SCSI-only systems
   can say N here.
 
   Useful information about large (>540 MB) IDE disks, multiple
@@ -304,12 +315,11 @@
   detected, sound card 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 via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  available from http://metalab.unc.edu/mdw/linux.html#howto .
 
   To fine-tune IDE drive/interface parameters for improved
   performance, look for the hdparm package at
-  ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/
+  ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ .
 
   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),
@@ -337,8 +347,8 @@
 
   If you are unsure, then just choose the Enhanced IDE/MFM/RLL driver
   instead of this one. For more detailed information, read the
-  Disk-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  Disk-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   People with SCSI-only systems can say N here.
 
@@ -377,7 +387,7 @@
 
 Use multi-mode by default
 CONFIG_IDEDISK_MULTI_MODE
-  If you get this error, try to enable this option.
+  If you get this error, try to say Y here:
 
   hda: set_multmode: status=0x51 { DriveReady SeekComplete Error }
   hda: set_multmode: error=0x04 { DriveStatusError }
@@ -398,12 +408,12 @@
   CDROM drive, you can say N to all other CDROM options, but be sure
   to say Y or M to "ISO 9660 CDROM filesystem support".
 
-  Read the CDROM-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and the file
+  Read the CDROM-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto and the file
   Documentation/cdrom/ide-cd. Note that older versions of lilo (the
   Linux boot loader) cannot properly deal with IDE/ATAPI CDROMs, so
   install lilo-16 or higher, available from
-  ftp://metalab.unc.edu/pub/Linux/system/Linux-boot/lilo.
+  ftp://metalab.unc.edu/pub/Linux/system/boot/lilo .
 
   If you want to compile the driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -413,11 +423,11 @@
 Include CD-Changer Reporting
 CONFIG_IDECD_SLOTS
   If you have an IDE/ATAPI multi-slot cd-changer and you want
-  to report which slots have disk-present, say Y.  If you say Y
-  and there is not a multi-slot cdrom present, this code is skipped.
+  to report which slots have a disk present, say Y.  If you say Y
+  and there is no multi-slot cdrom present, this code is skipped.
 
-  This could be the bases of multi-disk access based on multi-mounts.
-  This is still pie-in-the-sky.
+  This code could be the basis of multi-disk access based on
+  multi-mounts, but this is still pie-in-the-sky.
 
   If unsure, say N.
 
@@ -497,8 +507,8 @@
   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 via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.)
+  the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .)
 
   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
@@ -543,172 +553,211 @@
   enabled automatically. By default, DMA is not enabled automatically
   for these drives, but you can change that by saying Y to the
   following question "Use DMA by default when available". You can get
-  the latest version of the hdparm utility via anonymous FTP from
-  ftp://metalab.unc.edu/pub/Linux/system/hardware/.
+  the latest version of the hdparm utility from
+  ftp://metalab.unc.edu/pub/Linux/system/hardware/ .
 
   Read the comments at the beginning of drivers/block/idedma.c and the
   file Documentation/ide.txt for more information. 
 
   It is safe to say Y to this question.
 
-Use DMA by default when available
-CONFIG_IDEDMA_PCI_AUTO
-  Prior to kernel version 2.1.112, Linux used to automatically use
-  DMA for IDE drives and chipsets which support it. Due to concerns
-  about a couple of cases where buggy hardware may have caused damage,
-  the default is now to NOT use DMA automatically. To revert to the
-  previous behaviour, say Y to this question.
-
-  If you suspect your hardware is at all flakey, say N here.
-  Do NOT email the IDE kernel people regarding this issue!
-
-  It is normally safe to answer Y to this question unless your
-  motherboard uses a VIA VP2 chipset, in which case you should say N.
-
 Good-Bad DMA Model-Firmware (EXPERIMENTAL)
 IDEDMA_NEW_DRIVE_LISTINGS
-  This test compares both the model and firmware revision for buggy drives
-  that claim to (U)DMA capable.  This is a blanket on/off test with no speed
-  limit options.  Straight GNU GCC 2.7.3/2.8.X compilers are known to be safe;
-  whereas, many versions of EGCS have a problem and miscompile.
+  If you say Y here, the model and firmware revision of your drive
+  will be compared against a blacklist of buggy drives that claim to
+  be (U)DMA capable but aren't. This is a blanket on/off test with no
+  speed limit options.
+
+  Straight GNU GCC 2.7.3/2.8.X compilers are known to be safe;
+  whereas, many versions of EGCS have a problem and miscompile if you
+  say Y here.
 
   If in doubt, say N.
 
+Winbond SL82c105 support
+CONFIG_BLK_DEV_SL82C105
+  If you have a Winbond SL82c105 IDE controller, say Y here to enable
+  special configuration for this chip. This is common on various CHRP
+  motherboards, but could be used elsewhere. If in doubt, say Y.
+
 Boot off-board chipsets first support
 CONFIG_BLK_DEV_OFFBOARD
   Normally, IDE controllers built into the motherboard (on-board
   controllers) are assigned to ide0 and ide1 while those on add-in PCI
   cards (off-board controllers) are relegated to ide2 and ide3.
-  Answering Y here will reverse the situation, with off-board
-  controllers on ide0/1 and on-board controllers on ide2/3. This can
-  improve the usability of some boot managers such as LILO when
-  booting from a drive on an off-board controller.
+  Answering Y here will allow you to reverse the situation, with
+  off-board controllers on ide0/1 and on-board controllers on ide2/3.
+  This can improve the usability of some boot managers such as LILO
+  when booting from a drive on an off-board controller.
+
+  If you say Y here, and you actually want to reverse the device scan
+  order as explained above, you also need to issue the kernel command
+  line option "pci=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://metalab.unc.edu/mdw/linux.html#howto .)
 
-  Requires that all onboard ide controllers be disabled or calling
-  "pci=reverse" to invert the device scan order.
-
-  Note that, if you say Y here, the order of the hd* devices will be
+  Note that, if you do this, the order of the hd* devices will be
   rearranged which may require modification of fstab and other files.
 
   If in doubt, say N.
 
-AEC6210 chipset support
-CONFIG_BLK_DEV_AEC6210
-  This driver adds up to 4 more eide devices sharing a single interrupt.
-  This add-on card is a bootable PCI UDMA controller.  In order to get this
-  card to initialize correctly in some cases, you should include this driver.
-
-  This prefers CONFIG_IDEDMA_PCI_AUTO to be enabled, regardless.
+Use DMA by default when available
+CONFIG_IDEDMA_PCI_AUTO
+  Prior to kernel version 2.1.112, Linux used to automatically use
+  DMA for IDE drives and chipsets which support it. Due to concerns
+  about a couple of cases where buggy hardware may have caused damage,
+  the default is now to NOT use DMA automatically. To revert to the
+  previous behaviour, say Y to this question.
 
-  Please read the comments at the top of drivers/block/aec6210.c
+  If you suspect your hardware is at all flakey, say N here.
+  Do NOT email the IDE kernel people regarding this issue!
 
-ALI M15x3 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_ALI15X3
-  This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
-  onboard chipsets.  It also tests for Simplex mode and enables
-  normal dual channel support.
+  It is normally safe to answer Y to this question unless your
+  motherboard uses a VIA VP2 chipset, in which case you should say N.
 
-  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
+Other IDE chipset support
+CONFIG_IDE_CHIPSETS
+  Say Y here if you want to include enhanced support for various IDE
+  interface chipsets used on motherboards and add-on cards. You can
+  then pick your particular IDE chip from among the following options.
+  This enhanced support may be necessary for Linux to be able to
+  access the 3rd/4th drives in some systems. It may also enable
+  setting of higher speed I/O rates to improve system performance with
+  these chipsets. Most of these also require special kernel boot
+  parameters to actually turn on the support at runtime; you can find
+  a list of these in the file Documentation/ide.txt.
+  
+  People with SCSI-only systems can say N here. 
 
-  Please read the comments at the top of drivers/block/alim15x3.c
+Generic 4 drives/port support
+CONFIG_BLK_DEV_4DRIVES
+  Certain older chipsets, including the Tekram 690CD, use a single set
+  of I/O ports at 0x1f0 to control up to four drives, instead of the
+  customary two drives per port. Support for this can be enabled at
+  runtime using the "ide0=four" kernel boot parameter if you say Y
+  here.
 
-  If unsure, say N.
+DTC-2278 support
+CONFIG_BLK_DEV_DTC2278
+  This driver is enabled at runtime using the "ide0=dtc2278" kernel
+  boot parameter. It enables support for the secondary IDE interface
+  of the DTC-2278 card, and permits faster I/O speeds to be set as
+  well. See the Documentation/ide.txt and drivers/block/dtc2278.c
+  files for more info.
 
-CMD646 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_CMD646
-  Say Y here if you have an IDE controller like this.
+Holtek HT6560B support
+CONFIG_BLK_DEV_HT6560B
+  This driver is enabled at runtime using the "ide0=ht6560b" kernel
+  boot parameter. It enables support for the secondary IDE interface
+  of the Holtek card, and permits faster I/O speeds to be set as well.
+  See the Documentation/ide.txt and drivers/block/ht6560b.c files for
+  more info.
 
-CY82C693 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_CY82C693
+PROMISE DC4030 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_PDC4030
+  This driver provides support for the secondary IDE interface and
+  cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver
+  is known to incur timeouts/retries during heavy I/O to drives
+  attached to the secondary interface. CDROM and TAPE devices are not
+  supported yet. This driver is enabled at runtime using the
+  "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt
+  and drivers/block/pdc4030.c files for more info.
 
-  This driver adds detection and support for the CY82C693 chipset
-  used on Digital's PC-Alpha 164SX boards.
+PS/2 ESDI hard disk support
+CONFIG_BLK_DEV_PS2
+  Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
+  hard disk.
+  
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called ps2esdi.o.
 
-  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
+Tekram TRM290 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_TRM290
+  This driver adds support for bus master DMA transfers
+  using the Tekram TRM290 PCI IDE chip. Volunteers are
+  needed for further tweaking and development.
+  Please read the comments at the top of drivers/block/trm290.c.
 
-  Please read the comments at the top of drivers/block/cy82c693.c
+OPTi 82C621 enhanced support (EXPERIMENTAL)
+CONFIG_BLK_DEV_OPTI621
+  This is a driver for the OPTi 82C621 EIDE controller.
+  Please read the comments at the top of drivers/block/opti621.c.
 
-HPT34X chipset support
-CONFIG_BLK_DEV_HPT34X
-  This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. The HPT343 chipset in its current form is a non-bootable or
-  HPT345/HPT363 chipset is bootable (needs BIOS FIX) PCI UDMA controllers.
-  This driver requires dynamic tuning of the chipset during the ide-probe
-  at boot. It is reported to support DVD II drives, by the manufacturer.
+NS87415 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_NS87415
+  This driver adds detection and support for the NS87415 chip
+  (used in SPARC64, among others).
 
-  Please read the comments at the top of drivers/block/hpt34x.c
+  Please read the comments at the top of drivers/block/ns87415.c.
 
-HPT34X DMA support (DANGEROUS)
-CONFIG_BLK_DEV_HPT34X_DMA
-  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
+CY82C693 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_CY82C693
+  This driver adds detection and support for the CY82C693 chipset
+  used on Digital's PC-Alpha 164SX boards.
 
-  Please read the comments at the top of drivers/block/hpt34x.c
+  If you say Y here, you need to say Y to "Use DMA by default
+  when available" as well.
 
-HPT366 chipset support
-CONFIG_BLK_DEV_HPT366
-  This 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.
-  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.
+VIA82C586 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_VIA82C586
+  Saying Y here adds initial timing settings for VIA (U)DMA onboard
+  IDE controllers that are ATA3 compliant. May work with ATA4 systems,
+  but not tested to date. To use some features of this chipset, you
+  will have to issue a kernel command line as described in the file
+  drivers/block/via82c586.c. Furthermore, if you also say Y to "/proc
+  filesystem support" and set DISPLAY_APOLLO_TIMINGS in via82c586.c,
+  you will be able to read information about the IDE controller from
+  the virtual file /proc/ide/via.
 
-  Please read the comments at the top of drivers/block/hpt366.c
+  If you say Y here, you also need to say Y to "Use DMA by default
+  when available", above.
 
-Intel PIIXn chipsets support
-CONFIG_BLK_DEV_PIIX
-  This driver adds PIO mode setting and tuning for all PIIX IDE
-  controllers by Intel.  Since the BIOS can sometimes improperly tune
-  PIO 0-4 mode settings, this allows dynamic tuning of the chipset
-  via the standard end-user tool 'hdparm'.
+  If unsure, say N.
 
-  Please read the comments at the top of drivers/block/piix.c
+CMD646 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_CMD646
+  Say Y here if you have an IDE controller which uses this chipset.
 
-  If unsure, say N.
+ALI M15x3 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_ALI15X3
+  This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
+  onboard chipsets.  It also tests for Simplex mode and enables
+  normal dual channel support.
 
-PIIXn Tuning support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PIIX_TUNING
-  This driver extension adds DMA mode setting and tuning for all PIIX IDE
-  controllers by Intel.  Since the BIOS can sometimes improperly setup
-  the device/adapter combination and speed limits, It has become a necessity
-  to back/forward speed devices as needed.
+  If you say Y here, you also need to say Y to "Use DMA by default
+  when available", above.
 
-  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode 2
-  if the BIOS can to perform this task at INIT.
+  Please read the comments at the top of drivers/block/alim15x3.c
 
   If unsure, say N.
 
-NS87415 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_NS87415
-  This driver adds detection and support for the NS87415 chip
-  (used in SPARC64, among others).
+PROMISE PDC20246/PDC20262 support
+CONFIG_BLK_DEV_PDC202XX
+  Promise Ultra33 or PDC20246
 
-  Please read the comments at the top of drivers/block/ns87415.c.
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. This add-on card is a bootable PCI UDMA controller. Since
+  multiple cards can be installed and there are BIOS ROM problems that
+  happen if the BIOS revisions of all installed cards (three-max) do
+  not match, the driver attempts to do dynamic tuning of the chipset at
+  boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required for
+  more than one card. This card may require that you say Y to "Special
+  UDMA Feature (EXPERIMENTAL)".
 
-OPTi 82C621 enhanced support (EXPERIMENTAL)
-CONFIG_BLK_DEV_OPTI621
-  This is a driver for the OPTi 82C621 EIDE controller.
-  Please read the comments at the top of drivers/block/opti621.c.
+  Promise Ultra66 or PDC20262
 
-PROMISE PDC20246/PDC20262 support
-CONFIG_BLK_DEV_PDC202XX
-  Promise Ultra33 or PDC20246.
-  This driver adds up to 4 more eide devices sharing a single interrupt.
-  This add-on card is a bootable PCI UDMA controller.
-  Since multiple cards can be installed and there are BIOS ROM problems
-  that happen if the BIOS revisions of all installed cards (three-max)
-  do not match.  Should you be unable to make new BIOS chips with a burner,
-  the driver attempts to dynamic tuning of the chipset at boot-time
-  for max-speed.  Ultra33 BIOS 1.25 or new required for more than one card.
-  This card may require "PDC202XX Special UDMA Feature (EXPERIMENTAL)".
-
-  Promise Ultra66 or PDC20262.
-  This driver adds up to 4 more eide devices sharing a single interrupt.
-  This add-on card is a bootable PCI UDMA ATA-66 controller.
-  The driver attempts to dynamic tuning of the chipset at boot-time
-  for max-speed.  Note tested limits are UDMA-2.
-  Ultra66 BIOS 1.11 or newer required.
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. This add-on card is a bootable PCI UDMA ATA-66
+  controller. The driver attempts to dynamic tuning of the chipset at
+  boot-time for max-speed. Note tested limits are UDMA-2. Ultra66 BIOS
+  1.11 or newer required.
 
-  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
+  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/pdc202xx.c
 
@@ -716,9 +765,9 @@
 
 Special UDMA Feature (EXPERIMENTAL)
 PDC202XX_FORCE_BURST_BIT
-  For PDC20246 and PDC20262 Ultra DMA chipsets.
-  Designed originally for PDC20246/Ultra33 that has BIOS setup failures
-  when using 3 or more cards.
+  For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally
+  for PDC20246/Ultra33 that has BIOS setup failures when using 3 or
+  more cards.
 
   Please read the comments at the top of drivers/block/pdc202xx.c
 
@@ -726,132 +775,69 @@
 
 Special Mode Feature (DANGEROUS)
 PDC202XX_FORCE_MASTER_MODE
-  For PDC20246 and PDC20262 Ultra DMA chipsets.
-  This is reserved for possible Hardware RAID 0,1 for the FastTrak Series.
+  For PDC20246 and PDC20262 Ultra DMA chipsets. This is reserved for
+  possible Hardware RAID 0,1 for the FastTrak Series.
 
   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.
-
-  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
-
-  Please read the comments at the top of drivers/block/sis5513.c
-
-Winbond SL82c105 support
-CONFIG_BLK_DEV_SL82C105
-  If you have a Winbond SL82c105 IDE controller, say Y here to enable
-  special configuration for this chip. This is common on various CHRP
-  motherboards, but could be used elsewhere. If in doubt, say Y.
+AEC6210 chipset support
+CONFIG_BLK_DEV_AEC6210
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. This add-on card is a bootable PCI UDMA controller. In
+  order to get this card to initialize correctly in some cases, you
+  should say Y here, and preferably also to "Use DMA by default when
+  available".
 
-Tekram TRM290 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_TRM290
-  This driver adds support for bus master DMA transfers
-  using the Tekram TRM290 PCI IDE chip. Volunteers are
-  needed for further tweaking and development.
-  Please read the comments at the top of drivers/block/trm290.c.
+  Please read the comments at the top of drivers/block/aec6210.c
 
-VIA82C586 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_VIA82C586
-  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 and
-  set DISPLAY_APOLLO_TIMINGS in via82c586.c
+HPT366 chipset support
+CONFIG_BLK_DEV_HPT366
+  This 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.
+  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.
+ 
+Intel PIIXn chipsets support
+CONFIG_BLK_DEV_PIIX
+  This driver adds PIO mode setting and tuning for all PIIX IDE
+  controllers by Intel.  Since the BIOS can sometimes improperly tune
+  PIO 0-4 mode settings, this allows dynamic tuning of the chipset
+  via the standard end-user tool 'hdparm'.
 
-  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
+  Please read the comments at the top of drivers/block/piix.c
 
   If unsure, say N.
 
-Support for PowerMac IDE devices (must also enable IDE)
-CONFIG_BLK_DEV_IDE_PMAC
-  No help for CONFIG_BLK_DEV_IDE_PMAC
-
-PowerMac IDE DMA support
-CONFIG_BLK_DEV_IDEDMA_PMAC
-  No help for CONFIG_BLK_DEV_IDEDMA_PMAC
-
-Use DMA by default
-CONFIG_IDEDMA_PMAC_AUTO
-  No help for CONFIG_IDEDMA_PMAC_AUTO
-
-ICS IDE interface support
-CONFIG_BLK_DEV_IDE_ICSIDE
-  No help for CONFIG_BLK_DEV_IDE_ICSIDE
-
-ICS DMA support
-CONFIG_BLK_DEV_IDEDMA_ICS
-  No help for CONFIG_BLK_DEV_IDEDMA_ICS
-
-Use ICS DMA by default
-CONFIG_IDEDMA_ICS_AUTO
-  No help for CONFIG_IDEDMA_ICS_AUTO
-
-RapIDE interface support
-CONFIG_BLK_DEV_IDE_RAPIDE
-  No help for CONFIG_BLK_DEV_IDE_RAPIDE
-
-Other IDE chipset support
-CONFIG_IDE_CHIPSETS
-  Say Y here if you want to include enhanced support for various IDE
-  interface chipsets used on motherboards and add-on cards. You can
-  then pick your particular IDE chip from among the following options.
-  This enhanced support may be necessary for Linux to be able to
-  access the 3rd/4th drives in some systems. It may also enable
-  setting of higher speed I/O rates to improve system performance with
-  these chipsets. Most of these also require special kernel boot
-  parameters to actually turn on the support at runtime; you can find
-  a list of these in the file Documentation/ide.txt.
-  
-  People with SCSI-only systems can say N here. 
+PIIXn Tuning support (EXPERIMENTAL)
+CONFIG_BLK_DEV_PIIX_TUNING
+  This driver extension adds DMA mode setting and tuning for all PIIX
+  IDE controllers by Intel. Since the BIOS can sometimes improperly
+  set up the device/adapter combination and speed limits, it has
+  become a necessity to back/forward speed devices as needed.
 
-Generic 4 drives/port support
-CONFIG_BLK_DEV_4DRIVES
-  Certain older chipsets, including the Tekram 690CD, use a single set
-  of I/O ports at 0x1f0 to control up to four drives, instead of the
-  customary two drives per port. Support for this can be enabled at
-  runtime using the "ide0=four" kernel boot parameter if you say Y
-  here.
+  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode
+  2 if the BIOS can not perform this task at initialization.
 
-ALI M14xx support
-CONFIG_BLK_DEV_ALI14XX
-  This driver is enabled at runtime using the "ide0=ali14xx" kernel
-  boot parameter. It enables support for the secondary IDE interface
-  of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
-  I/O speeds to be set as well. See the files Documentation/ide.txt
-  and drivers/block/ali14xx.c for more info.
+  If unsure, say N.
 
-DTC-2278 support
-CONFIG_BLK_DEV_DTC2278
-  This driver is enabled at runtime using the "ide0=dtc2278" kernel
-  boot parameter. It enables support for the secondary IDE interface
-  of the DTC-2278 card, and permits faster I/O speeds to be set as
-  well. See the Documentation/ide.txt and drivers/block/dtc2278.c
-  files for more info.
+HPT34X chipset support
+CONFIG_BLK_DEV_HPT34X
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. The HPT343 chipset in its current form is a non-bootable
+  controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX)
+  PCI UDMA controllers. This driver requires dynamic tuning of the
+  chipset during the ide-probe at boot time. It is reported to support
+  DVD II drives, by the manufacturer.
 
-Holtek HT6560B support
-CONFIG_BLK_DEV_HT6560B
-  This driver is enabled at runtime using the "ide0=ht6560b" kernel
-  boot parameter. It enables support for the secondary IDE interface
-  of the Holtek card, and permits faster I/O speeds to be set as well.
-  See the Documentation/ide.txt and drivers/block/ht6560b.c files for
-  more info.
+HPT34X DMA support (DANGEROUS)
+CONFIG_BLK_DEV_HPT34X_DMA
+  you need to say Y to "Use DMA by default when available" if you say
+  Y here.
 
-PROMISE DC4030 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PDC4030
-  This driver provides support for the secondary IDE interface and
-  cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver
-  is known to incur timeouts/retries during heavy I/O to drives
-  attached to the secondary interface. CDROM and TAPE devices are not
-  supported yet. This driver is enabled at runtime using the
-  "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt
-  and drivers/block/pdc4030.c files for more info.
+  Please read the comments at the top of drivers/block/hpt343.c
 
 QDI QD6580 support
 CONFIG_BLK_DEV_QD6580
@@ -868,61 +854,92 @@
   See the files Documentation/ide.txt and drivers/block/umc8672.c for
   more info.
 
+ALI M14xx support
+CONFIG_BLK_DEV_ALI14XX
+  This driver is enabled at runtime using the "ide0=ali14xx" kernel
+  boot parameter. It enables support for the secondary IDE interface
+  of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
+  I/O speeds to be set as well. See the files Documentation/ide.txt
+  and drivers/block/ali14xx.c for more info.
+
 Amiga builtin Gayle IDE interface support
 CONFIG_BLK_DEV_GAYLE
   This is the IDE driver for the builtin IDE interface on some Amiga
-  models.  It supports both the `A1200 style' (used in A600 and A1200)
-  and `A4000 style' (used in A4000 and A4000T) of the Gayle IDE interface.
-  Say Y if you have such an Amiga model and want to use IDE devices
-  (hard disks, CD-ROM drives, etc.) that are connected to the builtin
-  IDE interface.
-
-Amiga IDE Doubler support (EXPERIMENTAL)
-CONFIG_BLK_DEV_IDEDOUBLER
-  This driver provides support for the so called `IDE doublers' (made by
-  various manufacturers, e.g. Eyetech) that can be connected to the
-  builtin IDE interface of some Amiga models. Using such an IDE doubler,
-  you can connect up to four instead of two IDE devices on the Amiga's
+  models. It supports both the `A1200 style' (used in A600 and A1200)
+  and `A4000 style' (used in A4000 and A4000T) of the Gayle IDE
+  interface. Say Y if you have such an Amiga model and want to use IDE
+  devices (hard disks, CD-ROM drives, etc.) that are connected to the
   builtin IDE interface.
-  Note that the normal Amiga Gayle IDE driver may not work correctly if
-  you have an IDE doubler and don't enable this driver!
-  Say Y if you have an IDE doubler.  The driver is enabled at kernel
-  runtime using the "ide=doubler" kernel boot parameter.
+
+Falcon IDE interface support
+CONFIG_BLK_DEV_FALCON_IDE
+  This is the IDE driver for the builtin IDE interface on the Atari
+  Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
+  disks, CD-ROM drives, etc.) that are connected to the builtin IDE
+  interface.
 
 Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL)
 CONFIG_BLK_DEV_BUDDHA
   This is the IDE driver for the IDE interfaces on the Buddha and
   Catweasel expansion boards.  It supports up to two interfaces on the
   Buddha and three on the Catweasel.
+
   Say Y if you have a Buddha or Catweasel expansion board and want to
   use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
   to one of its IDE interfaces.
 
-Falcon IDE interface support
-CONFIG_BLK_DEV_FALCON_IDE
-  This is the IDE driver for the builtin IDE interface on the Atari Falcon.
-  Say Y if you have a Falcon and want to use IDE devices (hard disks,
-  CD-ROM drives, etc.) that are connected to the builtin IDE interface.
+Amiga IDE Doubler support (EXPERIMENTAL)
+CONFIG_BLK_DEV_IDEDOUBLER
+  This driver provides support for the so called `IDE doublers' (made
+  by various manufacturers, e.g. Eyetech) that can be connected to the
+  builtin IDE interface of some Amiga models. Using such an IDE
+  doubler, you can connect up to four instead of two IDE devices on
+  the Amiga's builtin IDE interface.
+
+  Note that the normal Amiga Gayle IDE driver may not work correctly
+  if you have an IDE doubler and don't enable this driver!
+
+  Say Y if you have an IDE doubler.  The driver is enabled at kernel
+  runtime using the "ide=doubler" kernel boot parameter.
+
+Support for PowerMac IDE devices (must also enable IDE)
+CONFIG_BLK_DEV_IDE_PMAC
+  No help for CONFIG_BLK_DEV_IDE_PMAC
+
+PowerMac IDE DMA support
+CONFIG_BLK_DEV_IDEDMA_PMAC
+  No help for CONFIG_BLK_DEV_IDEDMA_PMAC
+
+Use DMA by default
+CONFIG_IDEDMA_PMAC_AUTO
+  No help for CONFIG_IDEDMA_PMAC_AUTO
 
 Macintosh Quadra/Powerbook IDE interface support
 CONFIG_BLK_DEV_MAC_IDE
-  This is the IDE driver for the builtin IDE interface on the some m68k
-  Macintosh models. It supports both the `Quadra style' (used in Quadra/
-  Centris 630 and Performa 588 models) and `Powerbook style' (used in the
-  Powerbook 150 and 190 models) IDE interface.
-  Say Y if you have such an Macintosh model and want to use IDE devices
-  (hard disks, CD-ROM drives, etc.) that are connected to the builtin
-  IDE interface.
+  This is the IDE driver for the builtin IDE interface on some m68k
+  Macintosh models. It supports both the `Quadra style' (used in
+  Quadra/ Centris 630 and Performa 588 models) and `Powerbook style'
+  (used in the Powerbook 150 and 190 models) IDE interface.
 
-PS/2 ESDI hard disk support
-CONFIG_BLK_DEV_PS2
-  Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
-  hard disk.
-  
-  If you want to compile the driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called ps2esdi.o.
+  Say Y if you have such an Macintosh model and want to use IDE
+  devices (hard disks, CD-ROM drives, etc.) that are connected to the
+  builtin IDE interface.
+
+ICS IDE interface support
+CONFIG_BLK_DEV_IDE_ICSIDE
+  No help for CONFIG_BLK_DEV_IDE_ICSIDE
+
+ICS DMA support
+CONFIG_BLK_DEV_IDEDMA_ICS
+  No help for CONFIG_BLK_DEV_IDEDMA_ICS
+
+Use ICS DMA by default
+CONFIG_IDEDMA_ICS_AUTO
+  No help for CONFIG_IDEDMA_ICS_AUTO
+
+RapIDE interface support
+CONFIG_BLK_DEV_IDE_RAPIDE
+  No help for CONFIG_BLK_DEV_IDE_RAPIDE
 
 XT hard disk support
 CONFIG_BLK_DEV_XD
@@ -939,8 +956,9 @@
 Mylex DAC960/DAC1100 PCI RAID Controller support
 CONFIG_BLK_DEV_DAC960
   This driver adds support for the Mylex DAC960, AcceleRAID, and
-  eXtremeRAID PCI RAID controllers.  See README.DAC960 for further
-  information about this driver.
+  eXtremeRAID PCI RAID controllers. See the file
+  Documentation/README.DAC960 for further information about this
+  driver.
 
   If you want to compile the driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -1198,8 +1216,8 @@
   have such a controller, you do not need to say Y here.
 
   More information about Software RAID on Linux is contained in the
-  Software-RAID mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
+  Software-RAID mini-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . There you will also
   learn where to get the supporting user space utilities raidtools.
 
   If unsure, say N.
@@ -1226,8 +1244,8 @@
   the throughput rate if the partitions reside on distinct disks. 
 
   Information about Software RAID on Linux is contained in the
-  Software-RAID mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
+  Software-RAID mini-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . There you will also
   learn where to get the supporting user space utilities raidtools.
 
   If you want to compile this as a module ( = code which can be
@@ -1248,8 +1266,8 @@
   drives. 
 
   Information about Software RAID on Linux is contained in the
-  Software-RAID mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
+  Software-RAID mini-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . There you will also
   learn where to get the supporting user space utilities raidtools.
 
   If you want to use such a RAID-1 set, say Y. This code is also
@@ -1271,8 +1289,8 @@
   of the available parity distribution methods.
 
   Information about Software RAID on Linux is contained in the
-  Software-RAID mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
+  Software-RAID mini-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . There you will also
   learn where to get the supporting user space utilities raidtools.
 
   If you want to use such a RAID-4/RAID-5 set, say Y. This code is
@@ -1294,32 +1312,29 @@
   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://lena.fnet.fr/ (To browse the WWW, you need to
-  have access to a machine on the Internet that has a program like
-  lynx or netscape).
+  http://lena.fnet.fr/ .
 
 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://lena.fnet.fr/ (To browse the WWW, you need to have access to
-  a machine on the Internet that has a program like lynx or netscape).
+  http://lena.fnet.fr/ .
 
 Support for Algorithmics P4032
 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 .
 
 IDE card support
 CONFIG_BLK_DEV_IDE_CARDS
-  On Acorn systems, enable this if you wish to use an IDE interface
+  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, enable this if you wish to use the ICS IDE
+  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.
 
@@ -1328,23 +1343,21 @@
   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 enable it.
+  you should say Y here.
 
 Support for Mips Magnum 4000
 CONFIG_MIPS_MAGNUM_4000
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
   kernel that runs on these, say Y here. For details about Linux on
   the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  http://lena.fnet.fr/ (To browse the WWW, you need to have access to
-  a machine on the Internet that has a program like lynx or netscape).
+  http://lena.fnet.fr/ .
 
 Support for Olivetti M700
 CONFIG_OLIVETTI_M700
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
   kernel that runs on these, say Y here. For details about Linux on
   the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  http://lena.fnet.fr/ (To browse the WWW, you need to have access to
-  a machine on the Internet that has a program like lynx or netscape).
+  http://lena.fnet.fr/ .
 
 CPU type
 CONFIG_CPU_R3000
@@ -1382,8 +1395,8 @@
   of which are given in Documentation/Changes.
 
   For a general introduction to Linux networking, it is highly
-  recommended to read the NET-3-HOWTO, available via FTP (user:
-  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  recommended to read the NET-3-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
 Socket filtering
 CONFIG_FILTER
@@ -1397,22 +1410,55 @@
 
 Network packet filtering
 CONFIG_NETFILTER
-  Netfilter is a framework for filtering and mangling packets.
+  Netfilter is a framework for filtering and mangling network packets
+  that pass through your Linux box.
+
+  The most common use of packet filtering is to run your Linux box as
+  a firewall protecting a local network from the Internet. The type of
+  firewall provided by this kernel support is called a "packet
+  filter", which means that it can reject individual network packets
+  based on type, source, destination etc. The other kind of firewall,
+  a "proxy-based" one, is more secure but more intrusive and more
+  bothersome to set up; it inspects the network traffic much more
+  closely, modifies it and has knowledge about the higher level
+  protocols, which a packet filter lacks. Moreover, proxy-based
+  firewalls often require changes to the programs running on the local
+  clients. Proxy-based firewalls don't need support by the kernel, but
+  they are often combined with a packet filter, which only works if
+  you say Y here.
+
+  You should also say Y here if you intend to use your Linux box as
+  the gateway to the Internet for a local network of machines without
+  globally valid IP addresses. This is called "masquerading": if one
+  of the computers on your local network wants to send something to
+  the outside, your box can "masquerade" as that computer, i.e. it
+  forwards the traffic to the intended outside destination, but
+  modifies the packets to make it look like they came from the
+  firewall box itself. It works both ways: if the outside host
+  replies, the Linux box will silently forward the traffic to the
+  correct local computer. This way, the computers on your local net
+  are completely invisible to the outside world, even though they can
+  reach the outside and can receive replies. It is even possible to
+  run globally visible servers from within a masqueraded local network
+  using a mechanism called portforwarding. Masquerading is also often
+  called NAT (Network Address Translation).
+
+  Another use of Netfilter is in transparent proxying: if a machine on
+  the local network tries to connect to an outside host, your Linux
+  box can transparently forward the traffic to a local server,
+  typically a caching proxy server.
+
   Various modules exist for netfilter which replace the previous
   masquerading (ipmasqadm), packet filtering (ipchains), transparent
-  proxying, and portforwarding mechanisms.  Enabling this option
-  makes minor alterations to allow these modules to hook into the
-  packet stream.  More information is available from 
-  http://netfilter.kernelnotes.org (to browse the WWW, you need
-  to have access to a machine on the Internet that has a program like
-  lynx or netscape).
-
+  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
   here, as Fast switching currently bypasses netfilter.
-
-  Chances are that you should say Y here for every machine which is
-  run as a router and N for every regular host. If unsure, say N.
-
+ 
+  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
   Say Y to make sure packets aren't leaking.
@@ -1432,7 +1478,7 @@
   is no need for the legitimate users to change their TCP/IP software;
   SYN cookies work transparently to them. For technical information
   about SYN cookies, check out
-  ftp://koobera.math.uic.edu/pub/docs/syncookies-archive.
+  ftp://koobera.math.uic.edu/pub/docs/syncookies-archive .
 
   If you are SYN flooded, the source address reported by the kernel is
   likely to have been forged by the attacker; it is only reported as
@@ -1466,9 +1512,7 @@
 
   To find out what type of Alpha system you have, you may want to
   check out the Linux/Alpha FAQ, accessible on the WWW from
-  http://www.alphalinux.org (To browse the WWW, you need to
-  have access to a machine on the Internet that has a program like
-  lynx or netscape).  In summary:
+  http://www.alphalinux.org . In summary:
 
   Alcor/Alpha-XLT     AS 600
   Alpha-XL            XL-233, XL-266
@@ -1511,9 +1555,7 @@
   which is command line driven, and ARC, which uses menus and arrow
   keys. Details about the Linux/Alpha booting process are contained in
   the Linux/Alpha FAQ, accessible on the WWW from
-  http://www.alphalinux.org (To browse the WWW, you need to
-  have access to a machine on the Internet that has a program like
-  lynx or netscape).
+  http://www.alphalinux.org .
 
   The usual way to load Linux on an Alpha machine is to use MILO
   (a bootloader that lets you pass command line parameters to the
@@ -1565,8 +1607,7 @@
   Say Y here if you have dumb serial boards other than the four
   standard COM 1/2/3/4 ports. This may happen if you have an AST
   FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
-  via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini), or other custom
+  from http://metalab.unc.edu/mdw/linux.html#howto ), or other custom
   serial port hardware which acts similar to standard serial port
   hardware. If you only use the standard COM 1/2/3/4 ports, you can
   say N here to save some memory. You can also say Y if you have an
@@ -1619,8 +1660,8 @@
   your box. Other bus systems are ISA, EISA, Microchannel (MCA) or
   VESA. If you have PCI, say Y, otherwise N. 
 
-  The PCI-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, contains valuable
+  The PCI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , contains valuable
   information about which PCI hardware does work under Linux and which
   doesn't.
 
@@ -1660,58 +1701,139 @@
 
 I2O support
 CONFIG_I2O
-  The Intelligent Input/Output (I2O) architecture allows
-  hardware drivers to be split into two parts: an operating system
-  specific module called the OSM and an hardware specific module
-  called the HDM. The OSM can talk to a whole range of HDM's, and
-  ideally the HDM's are not OS dependent. This allows for the same
-  driver to be used under different operating systems if the relevant
-  OSM is in place. If you say Y here, you will get a choice of OSM's
-  with the following questions.
+  The Intelligent Input/Output (I2O) architecture allows hardware
+  drivers to be split into two parts: an operating system specific
+  module called the OSM and an hardware specific module called the
+  HDM. The OSM can talk to a whole range of HDM's, and ideally the
+  HDM's are not OS dependent. This allows for the same HDM driver to
+  be used under different operating systems if the relevant OSM is in
+  place. In order for this to work, you need to have an I2O interface
+  adapter card in your computer. This card contains a special I/O
+  processor (IOP), thus allowing high speeds since the CPU does not
+  have to deal with I/O.
+
+  If you say Y here, you will get a choice of interface adapter
+  drivers and OSM's with the following questions.
 
   This support is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   If you want to compile it as a module, say M here and read
-  Documentation/modules.txt.
+  Documentation/modules.txt. You will get modules called i2o_core.o
+  and i20_config.o. 
 
   If unsure, say N.
 
 I2O PCI support
 CONFIG_I2O_PCI
-  Build in support for PCI bus I2O interface adapters. Currently this
-  is the only variety supported.
+  Say Y for support of PCI bus I2O interface adapters. Currently this
+  is the only variety supported, so you should say Y.
+
+  This support is also available as a module called i2o_pci.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
 
 I2O Block OSM
 CONFIG_I2O_BLOCK
-  Include support for the I2O Block OSM. The Block OSM presents disk and
-  other structured block devices to the operating system.
+  Include support for the I2O Block OSM. The Block OSM presents disk
+  and other structured block devices to the operating system.
+
+  This support is also available as a module called i2o_block.o ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
 
 I2O LAN OSM
 CONFIG_I2O_LAN
-  Include support for the LAN OSM. You will also need to include support
-  for token ring or fddi if you wish to use token ring or FDDI I2O cards
-  with this driver.
+  Include support for the LAN OSM. You will also need to include
+  support for token ring or FDDI if you wish to use token ring or FDDI
+  I2O cards with this driver.
+
+  This support is also available as a module called i2o_lan.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
 
 I2O SCSI OSM
 CONFIG_I2O_SCSI
-  Allow direct scsi access to scsi devices on a SCSI or FibreChannel I2O 
-  controller. You can use both the SCSI and Block OSM together if you wish.
+  Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
+  I2O controller. You can use both the SCSI and Block OSM together if
+  you wish.
+
+  This support is also available as a module called i2o_scsi.o ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+I2O /proc support
+CONFIG_I2O_PROC
+  If you say Y here and to "/proc filesystem support", you will be
+  able to read I2O related information from the virtual directory
+  /proc/i2o.
+
+  This support is also available as a module called i2o_proc.o ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+Plug and Play support
+CONFIG_PNP
+  Plug and Play (PnP) is a standard for peripherals which allows those
+  peripherals to be configured by software, e.g. assign IRQ's or other
+  parameters. No jumpers on the cards are needed, instead the values
+  are provided to the cards from the BIOS, from the operating system,
+  or using a user-space utility.
+
+  Say Y here if you would like Linux to configure your Plug and Play
+  devices. You should then also say Y to "ISA Plug and Play support",
+  below. Alternatively, you can configure your PnP devices using the
+  user space utilities contained in the isapnptools package.
+  
+  This support is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
+
+ISA Plug and Play support
+CONFIG_ISAPNP
+  Say Y here if you would like support for ISA Plug and Play devices.
+  
+  This support is also available as a module called isapnp.o ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+  If unsure, say Y.
+
+PCMCIA/Cardbus support
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA's (PC-cards) to your Linux
+  computer. These are credit-card size devices such as network cards,
+  modems or hard drives popular with laptops.
+
+  You will also need David Hinds' pcmcia-cs package (see the file
+  Documentation/Changes for location).
+
+CardBus support
+CONFIG_CARDBUS
+  CardBus is a bus mastering architecture for PC-cards (it allows
+  PC-cards to talk to the rest of the stuff inside your computer). If
+  unsure, say Y.
 
 System V IPC
 CONFIG_SYSVIPC
   Inter Process Communication is a suite of library functions and
-  system calls which let processes (running programs) synchronize
-  and exchange information. It is generally considered to be a good
-  thing, and some programs won't run unless you say Y here. In
-  particular, if you want to run the DOS emulator dosemu under Linux
-  (read the DOSEMU-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO), you'll need to say Y
+  system calls which let processes (running programs) synchronize and
+  exchange information. It is generally considered to be a good thing,
+  and some programs won't run unless you say Y here. In particular, if
+  you want to run the DOS emulator dosemu under Linux (read the
+  DOSEMU-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto ), you'll need to say Y
   here.
   
   You can find documentation about IPC with "info ipc" and also in
-  section 6.4 of the Linux Programmer's Guide, available via FTP
-  (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/LDP/programmers-guide.
+  section 6.4 of the Linux Programmer's Guide, available from
+  http://metalab.unc.edu/mdw/linux.html#guide .
 
   Saying Y here enlarges your kernel by about 7 KB. Just say Y.
 
@@ -1732,11 +1854,11 @@
   The sysctl interface provides a means of dynamically changing
   certain kernel parameters and variables on the fly without requiring
   a recompile of the kernel or reboot of the system. The primary
-  interface consists of a system call, but if the /proc filesystem is
-  enabled, a tree of modifiable sysctl entries will be generated
-  beneath the /proc/sys directory. They are explained in the files in
-  Documentation/sysctl/. Note that enabling this option will enlarge
-  the kernel by at least 8 KB. 
+  interface consists of a system call, but if you say Y to "/proc
+  filesystem support", a tree of modifiable sysctl entries will be
+  generated beneath the /proc/sys directory. They are explained in the
+  files in Documentation/sysctl/. Note that enabling this option will
+  enlarge the kernel by at least 8 KB.
 
   As it is generally a good thing, you should say Y here unless
   building a kernel for install/rescue disks or your system is very
@@ -1755,8 +1877,8 @@
   executables are distributed solely in ELF format. You definitely
   want to say Y here.
 
-  Information about ELF is contained in the ELF HOWTO available via
-  FTP (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  Information about ELF is contained in the ELF HOWTO available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   If you find that after upgrading from Linux kernel 1.2 and saying Y
   here, you still can't run any ELF binaries (they just crash), then
@@ -1796,6 +1918,10 @@
   Say Y here if you want to be able to execute Linux/Intel ELF
   binaries just like native Alpha binaries on your Alpha machine. For
   this to work, you need to have the emulator /usr/bin/em86 in place.
+
+  You can get the same functionality by saying N here and saying Y to
+  "Kernel support for MISC binaries". 
+
   You may answer M to compile the emulation support as a module and
   later load the module when you want to use a Linux/Intel binary. The
   module will be called binfmt_em86.o. If unsure, say Y.
@@ -1806,17 +1932,13 @@
   formats into the kernel. You will like this especially when you use
   programs that need an interpreter to run like Java, Python or
   Emacs-Lisp. It's also useful if you often run DOS executables under
-  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO). Once you have
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto ). Once you have
   registered such a binary class with the kernel, you can start one of
   those programs simply by typing in its name at a shell prompt; Linux
   will automatically feed it to the correct interpreter.
 
-  If you say Y here, you won't need "Kernel support for JAVA binaries"
-  (CONFIG_BINFMT_JAVA) or "Kernel support for Linux/Intel ELF
-  binaries" (CONFIG_BINFMT_EM86), as this is a more general solution.
-
-  You can do other nice things, too. Read
+  You can do other nice things, too. Read the file
   Documentation/binfmt_misc.txt to learn how to use this feature, and
   Documentation/java.txt for information about how to include Java
   support.
@@ -1872,8 +1994,8 @@
   everyone wants that. 
 
   The program SVGATextMode can be used to utilize SVGA video cards to
-  their full potential in text mode. Download it via FTP (user:
-  anonymous) from ftp://metalab.unc.edu/pub/Linux/utils/console.
+  their full potential in text mode. Download it from
+  ftp://metalab.unc.edu/pub/Linux/utils/console .
 
   Say Y.
 
@@ -1884,13 +2006,14 @@
   card's BIOS offers, but the traditional Linux utilities like
   SVGATextMode don't, you can say Y here and set the mode using the
   "vga=" option from your boot loader (lilo or loadlin) or set
-  "vga=ask" which brings up a video mode menu on kernel startup. Try
+  "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 via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Read
-  Documentation/svga.txt for more information about the Video mode
-  selection support. If unsure, say N.
+  explained in the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .)
+
+  Read the file Documentation/svga.txt for more information about the
+  Video mode selection support. If unsure, say N.
 
 Support for frame buffer devices (EXPERIMENTAL)
 CONFIG_FB
@@ -1984,15 +2107,23 @@
   you have a Retina Z3 or plan to get one before you next recompile
   the kernel.
 
-Cirrus Logic generic driver (EXPERIMENTAL)
+Cirrus Logic support (EXPERIMENTAL)
 CONFIG_FB_CLGEN
   This enables support for Cirrus Logic GD542x/543x based boards on
   Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.
-  If you have a PCI-based system, this enables support for these chips:
-  GD-543x, GD-544x, GD-5480.
+
+  If you have a PCI-based system, this enables support for these
+  chips: GD-543x, GD-544x, GD-5480.
+
+  Please read the file Documentation/fb/clgenfb.txt.
+
   Say N unless you have such a graphics board or plan to get one
   before you next recompile the kernel.
 
+Permedia2 support (experimental)
+CONFIG_FB_PM2
+  Say Y here if this is your graphics board.
+
 Apollo support
 CONFIG_APOLLO
   Say Y here if you want to run Linux on an MC680x0-based Apollo
@@ -2022,7 +2153,13 @@
 ATI Mach64 display support
 CONFIG_FB_ATY
   This driver supports graphics boards with the ATI Mach64 chips.
+  Say Y if you have such a graphics board.
 
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called atyfb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+  
 PowerMac "control" frame buffer device support
 CONFIG_FB_CONTROL
   This driver supports a frame buffer for the graphics adapter in the
@@ -2070,6 +2207,11 @@
   This is the frame buffer device driver for VGA 16 color graphic
   cards. Say Y if you have such a card.
 
+  This code is also available as a module. If you want to compile it
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called vga16fb.o.
+
 Backward compatibility mode for Xpmac
 CONFIG_FB_COMPAT_XPMAC
   If you use the Xpmac X server (common with mklinux), you'll need to
@@ -2112,7 +2254,7 @@
   packed pixel and 32 bpp packed pixel. You can also use font widths
   different from 8.
 
-Matrox G100/G200 support
+Matrox G100/G200/G400 support
 CONFIG_FB_MATROX_G100
   Say Y here if you have a Matrox Productiva G100, Matrox Mystique
   G200, Matrox Marvel G200 or Matrox Millennium G200 video card. If
@@ -2285,10 +2427,17 @@
   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;
-  it is used by frame buffer device drivers that support VGA text mode.
+  it is used by frame buffer device drivers that support VGA text
+  mode.
 
 Parallel-port support
 CONFIG_PARPORT
@@ -2301,8 +2450,7 @@
 
   For extensive information about drivers for many devices attaching
   to the parallel port see http://www.torque.net/linux-pp.html on the
-  WWW (to browse the WWW, you need to have access to a machine on the
-  Internet that has a program like lynx or netscape).
+  WWW.
 
   It is possible to share a single parallel port among several devices
   and it is safe to compile all the corresponding drivers into the
@@ -2340,6 +2488,11 @@
   FIFO. See Documentation/parport.txt to find out how to specify
   which IRQ/DMA to use.
 
+Support for PCMCIA management for PC-style ports
+CONFIG_PARPORT_PC_PCMCIA
+  Say Y here if you need PCMCIA support for your PC-style parallel
+  ports. If unsure, say N.
+
 Support foreign hardware
 CONFIG_PARPORT_OTHER
   Say Y here if you want to be able to load driver modules to support
@@ -2359,7 +2512,7 @@
   such as EPP and ECP, say Y here to enable advanced IEEE 1284
   transfer modes. Also say Y if you want device ID information to
   appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
-
+ 
 Enable loadable module support
 CONFIG_MODULES
   Kernel modules are small pieces of compiled code which can be
@@ -2416,10 +2569,10 @@
   daemon arpd. Arpd then answers the address resolution request either
   from its own cache or by asking the net.
 
-  This code is experimental. If you do say Y here, you should obtain a
-  copy of arpd from http://www.loran.com/~layes/arpd/index.html, and
-  you should also say Y to "Kernel/User network link driver", below.
-  If unsure, say N.
+  This code is experimental and also obsolete. If you want to use it,
+  you need to find a version of the daemon arpd on the net somewhere,
+  and you should also say Y to "Kernel/User network link driver",
+  below. If unsure, say N.
 
 TCP/IP networking
 CONFIG_INET
@@ -2431,14 +2584,14 @@
   allows you to ping yourself (great fun, that!).
 
   For an excellent introduction to Linux networking, please read the
-  NET-3-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  NET-3-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   This option is also necessary if you want to use the full power of
   term (term is a program which gives you almost full Internet
   connectivity if you have a regular dial up shell account on some
   Internet connected Unix computer; for more information, read
-  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html).
+  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ).
   
   If you say Y here and also to "/proc filesystem support" and "Sysctl
   support" below, you can change various aspects of the behavior of
@@ -2455,9 +2608,7 @@
   intend to participate in the MBONE, a high bandwidth network on top
   of the Internet which carries audio and video broadcasts. More
   information about the MBONE is on the WWW at
-  http://www.best.com/~prince/techinfo/mbone.html (to browse the WWW,
-  you need to have access to a machine on the Internet that has a
-  program like lynx or netscape). Information about the multicast
+  http://www-itg.lbl.gov/mbone/ . Information about the multicast
   capabilities of the various network cards is contained in
   Documentation/networking/multicast.txt. For most people, it's safe
   to say N.
@@ -2512,7 +2663,7 @@
 
   If you are interested in this, please see the preliminary
   documentation at http://www.compendium.com.ar/policy-routing.txt and
-  ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex. You
+  ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex . You
   will need supporting software from ftp://ftp.inr.ac.ru/ip-routing/
   
   If unsure, say N.
@@ -2628,7 +2779,7 @@
   appear on a different network than it physically is, or to use
   mobile-IP facilities (allowing laptops to seamlessly move between
   networks without changing their IP addresses; check out
-  http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html). 
+  http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html ). 
 
   Saying Y to this option will produce two modules ( = code which can
   be inserted in and removed from the running kernel whenever you
@@ -2657,15 +2808,12 @@
 CONFIG_IP_ALIAS
   Sometimes it is useful to give several IP addresses to a single
   physical network interface (serial port or Ethernet card). The most
-  common case is that you want to serve different WWW or ftp documents
+  common case is that you want to serve different WWW or FTP documents
   to the outside depending on which of your host names was used to
   connect to you. This is called "multihosting" or "virtual domains"
-  or "virtual hosting services" and is explained in detail on the WWW
-  at http://www.thesphere.com/~dlp/TwoServers/ (to browse the WWW, you
-  need to have access to a machine on the Internet that has a program
-  like lynx or netscape) and also in the Virtual-Services-HOWTO,
-  available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  or "virtual hosting services" and is explained in the
+  Virtual-Services-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   Another scenario would be that there are two logical networks living
   on your local Ethernet and you want to access them both with the
@@ -2693,9 +2841,7 @@
   Multicast) version 1. This multicast routing protocol is used widely
   because Cisco supports it. You need special software to use it
   (pimd-v1). Please see http://netweb.usc.edu/pim/ for more
-  information about PIM (to browse the WWW, you need to have access to
-  a machine on the Internet that has a program like lynx or
-  netscape). 
+  information about PIM.
 
   Say Y if you want to use PIM-SM v1. Note that you can say N here if
   you just want to use Dense Mode PIM.
@@ -2717,38 +2863,6 @@
   People having problems with NCSA telnet should see the file
   linux/Documentation/networking/ncsa-telnet.
 
-Reverse ARP server
-CONFIG_INET_RARP
-  If there are (usually diskless or portable) machines on your local
-  network that know their hardware Ethernet addresses but don't know
-  their IP addresses upon startup, they can send out a Reverse Address
-  Resolution Protocol (RARP) request to find out their own IP
-  addresses. Diskless Sun 3 machines use this procedure at boot time,
-  and diskless Linux boxes can be configured to do it as well.
-  
-  If you want your Linux box to be able to *answer* such requests,
-  answer Y here; you'll then have to run the program rarp ("man rarp")
-  on your box.
-
-  If you actually want to use a diskless Sun 3 machine as an X
-  terminal to Linux, say Y here and fetch Linux-Xkernel from
-  ftp://metalab.unc.edu/pub/Linux/system/network/boot.net/.
-
-  Superior solutions to the problem of booting and configuring
-  machines over a net connection are given by the protocol BOOTP and
-  its successor DHCP. See the DHCP FAQ
-  http://web.syr.edu/~jmwobus/comfaqs/dhcp.faq.html for details (to
-  browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape).
-
-  If you want to compile RARP 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 rarp.o. 
-
-  If you don't understand a word of the above, say N and rest in
-  peace.
-
 Assume subnets are local
 CONFIG_INET_SNARL
   Say Y if you are on a subnetted network with all machines connected
@@ -2822,15 +2936,14 @@
 The IPv6 protocol
 CONFIG_IPV6
   This is experimental support for the next version of the Internet
-  Protocol: IP version 6 (also called IPng "IP next generation"). 
+  Protocol: IP version 6 (also called IPng "IP next generation").
   Features of this new protocol include: expanded address space,
   authentication and privacy, and seamless interoperability with the
   current version of IP (IP version 4). For general information about
-  IPv6, see http://playground.sun.com/pub/ipng/html/ipng-main.html (to
-  browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape); for specific information
-  about IPv6 under Linux read http://www.bieringer.de/linux/IPv6/ and 
-  the file net/ipv6/README in the kernel source. 
+  IPv6, see http://playground.sun.com/pub/ipng/html/ipng-main.html ;
+  for specific information about IPv6 under Linux read the HOWTO at
+  http://www.bieringer.de/linux/IPv6/ and the file net/ipv6/README in
+  the kernel source.
 
   If you want to use IPv6, please upgrade to the newest net-tools as
   given in Documentation/Changes. You will still be able to do regular
@@ -2871,10 +2984,10 @@
   This is support for the Novell networking protocol, IPX, commonly
   used for local networks of Windows machines. You need it if you want
   to access Novell NetWare file or print servers using the Linux
-  Novell client ncpfs (available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/system/filesystems/) or from within
-  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO). In order to do the
+  Novell client ncpfs (available from
+  ftp://metalab.unc.edu/pub/Linux/system/filesystems/ ) or from within
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto ). In order to do the
   former, you'll also have to say Y to "NCP filesystem support",
   below.
 
@@ -2885,13 +2998,12 @@
   To turn your Linux box into a fully featured NetWare file server and
   IPX router, say Y here and fetch either lwared from
   ftp://metalab.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe
-  from ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information,
-  read the IPX-HOWTO in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  from ftp://ftp.gwdg.de/pub/linux/misc/ncpfs . For more information,
+  read the IPX-HOWTO available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   General information about how to connect Linux, Windows machines and
-  Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
-  browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape). 
+  Macs is on the WWW at http://www.eats.com/linux_mac_win.html .
 
   The IPX driver would enlarge your kernel by about 5 kB. This driver
   is also available as a module ( = code which can be inserted in and
@@ -2909,7 +3021,7 @@
   same address). The way this is done is to create a virtual internal
   "network" inside your box and to assign an IPX address to this
   network. Say Y here if you want to do this; read the IPX-HOWTO at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO for details.
+  http://metalab.unc.edu/mdw/linux.html#howto for details.
 
   The full internal IPX network enables you to allocate sockets on
   different virtual nodes of the internal network. This is done by
@@ -2922,7 +3034,7 @@
   'special' sockets to sockets listening on the primary network is
   disabled. This might break existing applications, especially RIP/SAP
   daemons. A RIP/SAP daemon that works well with the full internal net
-  can be found on ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. 
+  can be found on ftp://ftp.gwdg.de/pub/linux/misc/ncpfs . 
 
   If you don't know what you are doing, say N.
 
@@ -2939,7 +3051,7 @@
   space programs lwared or mars_nwe for the server side).
 
   Say Y here if you have use for SPX; read the IPX-HOWTO at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO for details.
+  http://metalab.unc.edu/mdw/linux.html#howto for details.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -2960,9 +3072,13 @@
   More detailed documentation is available in the
   Documentation/networking/decnet.txt file.
 
-  Be sure to turn on the CONFIG_PROCFS and CONFIG_SYSCTL options
-  when using DECnet, since you will need sysctl support to aid in
-  configuration at run time.
+  Be sure to say Y to "/proc filesystem support" and "Sysctl support"
+  below when using DECnet, since you will need sysctl support to aid
+  in configuration at run time.
+
+  The DECnet code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called decnet.o.
 
 DECnet SIOCFIGCONF support
 CONFIG_DECNET_SIOCGIFCONF
@@ -2970,19 +3086,23 @@
    you know what you are doing. It can break other applications which
    use this system call and the proper way to get the information
    provided by this call is to use rtnetlink.
+   
+   If unsure, say N.
 
 DECnet Router Support
 CONFIG_DECNET_ROUTER
    Add support for turning your DECnet Endnode into a level 1 or 2
-   router. This is an unfinished option for developers only. If you
-   do turn it on, then make sure you also have rtnetlink configured
-   in, since thats the only current method of configuration.
+   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" and "Routing messages", since rtnetlink is the
+   only current method of configuration.
 
 DECnet Raw Socket Support
 CONFIG_DECNET_RAW
    Add support for the SOCK_RAW type under DECnet. Used by userland
    routing programs to receive routing messages from the kernel and
-   also as a general debugging aid to see whats going on "under the hood".
+   also as a general debugging aid to see what's going on "under the
+   hood".
 
 AppleTalk DDP
 CONFIG_ATALK
@@ -2992,16 +3112,15 @@
   netatalk package so that your Linux box can act as a print and file
   server for Macs as well as access AppleTalk printers. Check out
   http://threepio.hitchcock.org/cgi-bin/faq/netatalk/faq.pl on the WWW
-  for details (to browse the WWW, you need to have access to a machine
-  on the Internet that has a program like lynx or netscape). EtherTalk
-  is the name used for AppleTalk over Ethernet and the cheaper and
-  slower LocalTalk is AppleTalk over a proprietary Apple network using
-  serial links. EtherTalk and LocalTalk are fully supported by Linux.
+  for details. EtherTalk is the name used for AppleTalk over Ethernet
+  and the cheaper and slower LocalTalk is AppleTalk over a proprietary
+  Apple network using serial links. EtherTalk and LocalTalk are fully
+  supported by Linux.
 
   General information about how to connect Linux, Windows machines and
-  Macs is on the WWW at http://www.eats.com/linux_mac_win.html
-  The NET-3-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO contains valuable
+  Macs is on the WWW at http://www.eats.com/linux_mac_win.html The
+  NET-3-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , contains valuable
   information as well.
 
   This driver is also available as a module ( = code which can be
@@ -3088,10 +3207,8 @@
 CONFIG_HAMRADIO
   If you want to connect your Linux box to an amateur radio, answer Y
   here. You want to read http://www.tapr.org/tapr/html/pkthome.html
-  (to browse the WWW, you need to have access to a machine on the
-  Internet that has a program like lynx or netscape) and the HAM-HOWTO
-  and the AX25-HOWTO, both available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  and the HAM-HOWTO and the AX25-HOWTO, both available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   Note that the answer to this question won't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -3114,13 +3231,11 @@
 
   Information about where to get supporting software for Linux amateur
   radio as well as information about how to configure an AX.25 port is
-  contained in the AX25-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You might also want to
+  contained in the AX25-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . You might also want to
   check out the file Documentation/networking/ax25.txt in the kernel
   source. More information about digital amateur radio in general is
-  on the WWW at http://www.tapr.org/tapr/html/pkthome.html. (To browse
-  the WWW, you need to have access to a machine on the Internet that
-  has a program like lynx or netscape).
+  on the WWW at http://www.tapr.org/tapr/html/pkthome.html .
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -3152,13 +3267,11 @@
 
   A comprehensive listing of all the software for Linux amateur radio
   users as well as information about how to configure an AX.25 port is
-  contained in the AX25-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You also might want to
+  contained in the AX25-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . You also might want to
   check out the file Documentation/networking/ax25.txt. More
   information about digital amateur radio in general is on the WWW at
-  http://www.tapr.org/tapr/html/pkthome.html (to browse the WWW, you
-  need to have access to a machine on the Internet that has a program
-  like lynx or netscape).
+  http://www.tapr.org/tapr/html/pkthome.html .
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -3173,13 +3286,11 @@
 
   A comprehensive listing of all the software for Linux amateur radio
   users as well as information about how to configure an AX.25 port is
-  contained in the AX25-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You also might want to
+  contained in the AX25-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . You also might want to
   check out the file Documentation/networking/ax25.txt. More
   information about digital amateur radio in general is on the WWW at
-  http://www.tapr.org/tapr/html/pkthome.html (to browse the WWW, you
-  need to have access to a machine on the Internet that has a program
-  like lynx or netscape).
+  http://www.tapr.org/tapr/html/pkthome.html .
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -3238,11 +3349,11 @@
   traffic.
 
   Currently, this driver supports Ottawa PI/PI2
-  (http://hydra.carleton.ca/info/pi2.html) and Gracilis PackeTwin
-  (http://www.paccomm.com/gracilis.html) boards. They are detected
+  (http://hydra.carleton.ca/info/pi2.html ) and Gracilis PackeTwin
+  (http://www.paccomm.com/gracilis.html ) boards. They are detected
   automatically. If you have one of these cards, say Y here and read
-  the AX25-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/.
+  the AX25-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   This driver can operate multiple boards simultaneously. If you
   compile it as a module (by saying M instead of Y), it will be called
@@ -3258,18 +3369,15 @@
   certain parameters, such as channel access timing, clock mode, and
   DMA channel. This is accomplished with a small utility program,
   dmascc_cfg, available at
-  http://www.nt.tuwien.ac.at/~kkudielk/Linux/. (To browse the WWW, you
-  need to have access to a machine on the Internet that has a program
-  like lynx or netscape).
+  http://www.nt.tuwien.ac.at/~kkudielk/Linux/ .
 
 Z8530 SCC driver for AX.25
 CONFIG_SCC
   These cards are used to connect your Linux box to an amateur radio
   in order to communicate with other computers. If you want to use
-  this, read Documentation/networking/z8530drv.txt and the
-  AX25-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Also make sure to say Y
-  to "Amateur Radio AX.25 Level 2" support.
+  this, read Documentation/networking/z8530drv.txt and the AX25-HOWTO,
+  available from http://metalab.unc.edu/mdw/linux.html#howto . Also
+  make sure to say Y to "Amateur Radio AX.25 Level 2" support.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3288,12 +3396,16 @@
 ### Don't know what's going on here.
 ###
 #
+
 YAM driver for AX.25
 CONFIG_YAM
-  Support for the YAM modem on serial port. 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 YAM is a modem for packet radio which connects to the serial
+  port and includes some of the functions of a Terminal Node
+  Controller. If you have one of those, say Y here.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt.
 
 BAYCOM picpar and par96 driver for AX.25
 CONFIG_BAYCOM_PAR
@@ -3301,9 +3413,8 @@
   connect to a parallel interface. The driver supports the picpar and
   par96 designs. To configure the driver, use the sethdlc utility
   available in the standard ax25 utilities package. For information on
-  the modems, see http://www.baycom.de (to browse the WWW, you need to
-  have access to a machine on the Internet that has a program like
-  lynx or netscape) and Documentation/networking/baycom.txt. 
+  the modems, see http://www.baycom.de and the file
+  Documentation/networking/baycom.txt.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3316,9 +3427,8 @@
   connect to a parallel interface. The driver supports the EPP
   designs. To configure the driver, use the sethdlc utility available
   in the standard ax25 utilities package. For information on the
-  modems, see http://www.baycom.de (to browse the WWW, you need to
-  have access to a machine on the Internet that has a program like
-  lynx or netscape) and Documentation/networking/baycom.txt.
+  modems, see http://www.baycom.de and the file
+  Documentation/networking/baycom.txt.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3336,10 +3446,8 @@
   driver and still provided in case this driver does not work with
   your serial interface chip. To configure the driver, use the sethdlc
   utility available in the standard ax25 utilities package. For
-  information on the modems, see http://www.baycom.de (to browse the
-  WWW, you need to have access to a machine on the Internet that has a
-  program like lynx or netscape) and
-  Documentation/networking/baycom.txt. 
+  information on the modems, see http://www.baycom.de and
+  Documentation/networking/baycom.txt.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3352,12 +3460,10 @@
   modems that connect to a serial interface. The driver supports the
   ser12 design in full duplex mode. This is the old driver. It is
   still provided in case your serial interface chip does not work with
-  the full duplex driver. This driver is depreciated. To configure
-  the driver, use the sethdlc utility available in the standard ax25
+  the full duplex driver. This driver is depreciated. To configure the
+  driver, use the sethdlc utility available in the standard ax25
   utilities package. For information on the modems, see
-  http://www.baycom.de (to browse the WWW, you need to have access to
-  a machine on the Internet that has a program like lynx or netscape)
-  and Documentation/networking/baycom.txt. 
+  http://www.baycom.de and Documentation/networking/baycom.txt.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3374,10 +3480,8 @@
   To configure the driver, use the sethdlc, smdiag and smmixer
   utilities available in the standard ax25 utilities package. For
   information on how to key the transmitter, see
-  http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html (to browse
-  the WWW, you need to have access to a machine on the Internet that
-  has a program like lynx or netscape) and
-  Documentation/networking/soundmodem.txt. 
+  http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html and
+  Documentation/networking/soundmodem.txt.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3473,13 +3577,11 @@
   if you want that) and the lower level data link layer protocol LAPB
   (say Y to "LAPB Data Link Driver" below if you want that). 
 
-  You can read more about X.25 at http://www.sangoma.com/x25.html and
-  http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm
-  (to browse the WWW, you need to have access to a machine on the
-  Internet that has a program like lynx or netscape). Information
-  about X.25 for Linux is contained in the files
+  You can read more about X.25 at http://www.sangoma.com/x25.htm and
+  http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm .
+  Information about X.25 for Linux is contained in the files
   Documentation/networking/x25.txt and
-  Documentation/networking/x25-iface.txt. 
+  Documentation/networking/x25-iface.txt.
 
   One connects to an X.25 network either with a dedicated network card
   using the X.21 protocol (not yet supported by Linux) or one can do
@@ -3528,39 +3630,59 @@
   other third party bridge products. 
 
   In order to use this, you'll need the bridge configuration tools
-  available via FTP (user: anonymous) from
-  ftp://shadow.cabi.net/pub/Linux. 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 via FTP (user: anonymous)
-  in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. The Bridging code is
-  still in test. If unsure, say N.
+  available from ftp://shadow.cabi.net/pub/Linux . 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
+  http://metalab.unc.edu/mdw/linux.html#howto .
+
+  The Bridging code is still in test. If unsure, say N.
 
 Packet socket
 CONFIG_PACKET
   The Packet protocol is used by applications which communicate
   directly with network devices without an intermediate network
   protocol implemented in the kernel, e.g. tcpdump. If you want them
-  to work, choose Y. This driver is also available as a module called
-  af_packet.o ( = code which can be inserted in and removed from the
-  running kernel whenever you want). If you want to compile it as a
-  module, say M here and read Documentation/modules.txt. If unsure,
-  say Y.
+  to work, choose Y. 
+
+  This driver is also available as a module called af_packet.o ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt; if you use modprobe or
+  kmod, you may also want to add "alias net-pf-17 af_packet" to 
+  /etc/conf.modules. 
+
+  If unsure, say Y.
+
+Packet socket: mmapped IO
+CONFIG_PACKET_MMAP
+  If you say Y here, the Packet protocol driver will use an IO
+  mechanism that results in faster communication.
+
+  If unsure, say N.
 
 Kernel/User network link driver
 CONFIG_NETLINK
-  This driver allows for two-way communication between certain parts
-  of the kernel or modules and user processes; the user processes are
-  able to read from and write to character special files in the /dev
-  directory having major mode 36. So far, the kernel uses it to
-  publish some network related information if you say Y to "Routing
-  messages", below.  You also need to say Y here if you want to use
-  arpd, a daemon that helps keep the internal ARP cache (a mapping
-  between IP addresses and hardware addresses on the local network)
-  small. The ethertap device, which lets user space programs read and
-  write raw Ethernet frames, also needs the network link driver. If
-  unsure, say Y.
+  This driver allows for two-way communication between the kernel and
+  user processes; the user processes communicate with the kernel by
+  reading from and writing to character special files in the /dev
+  directory having major mode 36.
+
+  So far, the kernel uses this feature to publish some network related
+  information if you say Y to "Routing messages", below. You also need
+  to say Y here if you want to use arpd, a daemon that helps keep the
+  internal ARP cache (a mapping between IP addresses and hardware
+  addresses on the local network) small. The ethertap device, which
+  lets user space programs read and write raw Ethernet frames, also
+  needs the network link driver.
+  
+  This driver is also available as a module called netlink_dev.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.
+
+  If unsure, say Y.
 
 Routing messages
 CONFIG_RTNETLINK
@@ -3577,30 +3699,38 @@
 
 Asynchronous Transfer Mode (ATM)
 CONFIG_ATM
-  Kernel support for ATM. Note that you need a set of user-space programs
-  to actually make use of ATM. See Documentation/atm.txt for further
-  details.
+  ATM is a high-speed networking technology for Local Area Networks
+  and Wide Area Networks. It uses a fixed packet size and is
+  connection oriented, allowing for the negotiation of minimum
+  bandwidth requirements.
+  
+  In order to participate in an ATM network, your Linux box needs an
+  ATM networking card. If you have that, say Y here and to the driver
+  of your ATM card below.
+
+  Note that you need a set of user-space programs to actually make use
+  of ATM. See the file Documentation/atm.txt for further details.
 
 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.
+  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.
 
 Do NOT send ICMP if no neighbour
 CONFIG_ATM_CLIP_NO_ICMP
-  Normally, an ICMP host unreachable message is sent if a neighbour cannot
-  be reached because there is no VC to it in the kernel's ATMARP table.
-  This may cause problems when ATMARP table entries are briefly removed
-  during revalidation. If this configuration option is set to "yes",
-  packets to such neighbours are silently discarded instead.
+  Normally, an "ICMP host unreachable" message is sent if a neighbour
+  cannot be reached because there is no VC to it in the kernel's
+  ATMARP table. This may cause problems when ATMARP table entries are
+  briefly removed during revalidation. If you say Y here, packets to
+  such neighbours are silently discarded instead.
 
 LAN Emulation (LANE) support
 CONFIG_ATM_LANE
-  LAN Emulation emulates services of existing LANs across an ATM network.
-  Besides operating as a normal ATM end station client, Linux LANE client
-  can also act as an proxy client bridging packets between ELAN and
-  Ethernet segments. You need LANE if you want to try MPOA.
+  LAN Emulation emulates services of existing LANs across an ATM
+  network. Besides operating as a normal ATM end station client, Linux
+  LANE client can also act as an proxy client bridging packets between
+  ELAN and Ethernet segments. You need LANE if you want to try MPOA.
 
 Multi-Protocol Over ATM (MPOA) support
 CONFIG_ATM_MPOA
@@ -3611,50 +3741,52 @@
 
 ATM over TCP
 CONFIG_ATM_TCP
-  ATM over TCP driver. Useful mainly for development and for experiments.
+  ATM over TCP driver. Useful mainly for development and for
+  experiments. If unsure, say N.
 
 Efficient Networks ENI155P
 CONFIG_ATM_ENI
-  Driver for the Efficient Networks ENI155p series and SMC ATM Power155
-  155 Mbps ATM adapters. Both, the versions with 512kB and 2MB on-board
-  RAM (Efficient calls them "C" and "S", respectively), and the FPGA and
-  the ASIC Tonga versions of the board are supported. The driver works
-  with MMF (-MF or ...F) and UTP-5 (-U5 or ...D) adapters.
+  Driver for the Efficient Networks ENI155p series and SMC ATM
+  Power155 155 Mbps ATM adapters. Both, the versions with 512kB and
+  2MB on-board RAM (Efficient calls them "C" and "S", respectively),
+  and the FPGA and the ASIC Tonga versions of the board are supported.
+  The driver works with MMF (-MF or ...F) and UTP-5 (-U5 or ...D)
+  adapters.
 
 Enable extended debugging
 CONFIG_ATM_ENI_DEBUG
-  Extended debugging records various events and displays that list when
-  an inconsistency is detected. This mechanism is faster than generally
-  using printks, but still has some impact on performance. Note that
-  extended debugging may create certain race conditions itself. Enable
-  this ONLY if you suspect problems with the driver.
+  Extended debugging records various events and displays that list
+  when an inconsistency is detected. This mechanism is faster than
+  generally using printks, but still has some impact on performance.
+  Note that extended debugging may create certain race conditions
+  itself. Enable this ONLY if you suspect problems with the driver.
 
 Fine-tune burst settings
 CONFIG_ATM_ENI_TUNE_BURST
-  In order to obtain good throughput, the ENI NIC can transfer multiple
-  words of data per PCI bus access cycle. Such a multi-word transfer is
-  called a burst.
+  In order to obtain good throughput, the ENI NIC can transfer
+  multiple words of data per PCI bus access cycle. Such a multi-word
+  transfer is called a burst.
 
   The default settings for the burst sizes are suitable for most PCI
-  chipsets. However, in some cases, large bursts may overrun buffers in
-  the PCI chipset and cause data corruption. In such cases, large bursts
-  must be disabled and only (slower) small bursts can be used. The burst
-  sizes can be set independently in the send (TX) and receive (RX)
-  direction.
+  chipsets. However, in some cases, large bursts may overrun buffers
+  in the PCI chipset and cause data corruption. In such cases, large
+  bursts must be disabled and only (slower) small bursts can be used.
+  The burst sizes can be set independently in the send (TX) and
+  receive (RX) direction.
 
   Note that enabling many different burst sizes in the same direction
-  may increase the cost of setting up a transfer such that the resulting
-  throughput is lower than when using only the largest available burst
-  size.
+  may increase the cost of setting up a transfer such that the
+  resulting throughput is lower than when using only the largest
+  available burst size.
 
   Also, sometimes larger bursts lead to lower throughput, e.g. on an
-  Intel 440FX board, a drop from 135 Mbps to 103 Mbps was observed when
-  going from 8W to 16W bursts.
+  Intel 440FX board, a drop from 135 Mbps to 103 Mbps was observed
+  when going from 8W to 16W bursts.
 
 Enable 16W TX bursts (discouraged)
 CONFIG_ATM_ENI_BURST_TX_16W
-  Burst sixteed words at once in the send direction. This may work with
-  recent PCI chipsets, but is known to fail with older chipsets.
+  Burst sixteen words at once in the send direction. This may work
+  with recent PCI chipsets, but is known to fail with older chipsets.
 
 Enable 8W TX bursts (recommended)
 CONFIG_ATM_ENI_BURST_TX_8W
@@ -3663,37 +3795,38 @@
 
 Enable 4W TX bursts (optional)
 CONFIG_ATM_ENI_BURST_TX_4W
-  Burst four words at once in the send direction. You may want to try this
-  if you have disabled 8W bursts. Enabling 4W if 8W is also set may or may
-  not improve throughput.
+  Burst four words at once in the send direction. You may want to try
+  this if you have disabled 8W bursts. Enabling 4W if 8W is also set
+  may or may not improve throughput.
   
 Enable 2W TX bursts (optional)
 CONFIG_ATM_ENI_BURST_TX_2W
-  Burst two words at once in the send direction. You may want to try this
-  if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W are also
-  set may or may not improve throughput.
+  Burst two words at once in the send direction. You may want to try
+  this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W
+  are also set may or may not improve throughput.
 
 Enable 16W RX bursts (discouraged)
 CONFIG_ATM_ENI_BURST_RX_16W
-  Burst sixteen words at once in the receive direction. This may work with
-  recent PCI chipsets, but is known to fail with older chipsets.
+  Burst sixteen words at once in the receive direction. This may work
+  with recent PCI chipsets, but is known to fail with older chipsets.
 
 Enable 8W RX bursts (discouraged)
 CONFIG_ATM_ENI_BURST_RX_8W
-  Burst eight words at once in the receive direction. This may work with
-  recent PCI chipsets, but is known to fail with older chipsets, such as
-  the Intel Neptune series.
+  Burst eight words at once in the receive direction. This may work
+  with recent PCI chipsets, but is known to fail with older chipsets,
+  such as the Intel Neptune series.
 
 Enable 4W RX bursts (recommended)
 CONFIG_ATM_ENI_BURST_RX_4W
-  Burst four words at once in the receive direction. This is the default
-  setting. Enabling 4W if 8W is also set may or may not improve throughput.
+  Burst four words at once in the receive direction. This is the
+  default setting. Enabling 4W if 8W is also set may or may not
+  improve throughput.
 
 Enable 2W RX bursts (optional)
 CONFIG_ATM_ENI_BURST_RX_2W
-  Burst two words at once in the receive direction. You may want to try
-  this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W are
-  also set may or may not improve throughput.
+  Burst two words at once in the receive direction. You may want to
+  try this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or
+  8W are also set may or may not improve throughput.
 
 ZeitNet ZN1221/ZN1225
 CONFIG_ATM_ZATM
@@ -3702,20 +3835,21 @@
 
 Enable extended debugging
 CONFIG_ATM_ZATM_DEBUG
-  Extended debugging records various events and displays that list when
-  an inconsistency is detected. This mechanism is faster than generally
-  using printks, but still has some impact on performance. Note that
-  extended debugging may create certain race conditions itself. Enable
-  this ONLY if you suspect problems with the driver.
+  Extended debugging records various events and displays that list
+  when an inconsistency is detected. This mechanism is faster than
+  generally using printks, but still has some impact on performance.
+  Note that extended debugging may create certain race conditions
+  itself. Enable this ONLY if you suspect problems with the driver.
 
 Enable usec resolution timestamps
 CONFIG_ATM_ZATM_EXACT_TS
-  The uPD98401 SAR chip supports a high-resolution timer (approx. 30 MHz)
-  that is used for very accurate reception timestamps. Because that timer
-  overflows after 140 seconds, and also to avoid timer drift, time
-  measurements need to be periodically synchronized with the normal
-  system time. Enabling this feature will add some general overhead for
-  timer synchronization and also per-packet overhead for time conversion.
+  The uPD98401 SAR chip supports a high-resolution timer (approx. 30
+  MHz) that is used for very accurate reception timestamps. Because
+  that timer overflows after 140 seconds, and also to avoid timer
+  drift, time measurements need to be periodically synchronized with
+  the normal system time. Enabling this feature will add some general
+  overhead for timer synchronization and also per-packet overhead for
+  time conversion.
 
 IDT 77201 (NICStAR)
 CONFIG_ATM_NICSTAR
@@ -3772,8 +3906,8 @@
   You also need to say Y here if you want support for the parallel
   port version of the 100 MB IOMEGA ZIP drive.
 
-  Please read the SCSI-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. The
+  Please read the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . The
   SCSI-Programming-HOWTO contains information about how to add or
   remove an SCSI device from a running Linux machine without
   rebooting.
@@ -3790,9 +3924,9 @@
 CONFIG_BLK_DEV_SD
   If you want to use a SCSI hard disk or the SCSI or parallel port
   version of the IOMEGA ZIP drive under Linux, say Y and read the
-  SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available via
-  FTP (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
-  This is NOT for SCSI CDROMs.
+  SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . This is NOT for SCSI
+  CDROMs.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -3806,8 +3940,8 @@
 SCSI tape support
 CONFIG_CHR_DEV_ST
   If you want to use a SCSI tape drive under Linux, say Y and read the
-  SCSI-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and
+  SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , and
   drivers/scsi/README.st in the kernel source. This is NOT for SCSI
   CDROMs.
 
@@ -3820,8 +3954,8 @@
 SCSI CDROM support
 CONFIG_BLK_DEV_SR
   If you want to use a SCSI CDROM under Linux, say Y and read the
-  SCSI-HOWTO and the CDROM-HOWTO from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Also make sure to say Y
+  SCSI-HOWTO and the CDROM-HOWTO at
+  http://metalab.unc.edu/mdw/linux.html#howto . Also make sure to say Y
   or M to "ISO 9660 CDROM filesystem support" later.
 
   This driver is also available as a module ( = code which can be
@@ -3844,12 +3978,12 @@
   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 via FTP (user: anonymous)
-  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 via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Please read the file
+  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://metalab.unc.edu/mdw/linux.html#howto . Please read the file
   Documentation/scsi-generic.txt for more information.
 
   If you want to compile this as a module ( = code which can be
@@ -3914,10 +4048,9 @@
   SCSI host adapters. It also works for the AVA-1505, but the IRQ etc.
   must be manually specified in this case.
 
-  It is explained in section 3.3 of the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You
-  might also want to read the comments at the top of
-  drivers/scsi/aha152x.c.
+  It is explained in section 3.3 of the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . You might also want to
+  read the comments at the top of drivers/scsi/aha152x.c.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -3927,11 +4060,11 @@
 Adaptec AHA1542 support
 CONFIG_SCSI_AHA1542
   This is support for a SCSI host adapter. It is explained in section
-  3.4 of the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that Trantor was
-  recently purchased by Adaptec, and some former Trantor products are
-  being sold under the Adaptec name. If it doesn't work out of the
-  box, you may have to change some settings in drivers/scsi/aha1542.h.
+  3.4 of the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Note that Trantor was
+  purchased by Adaptec, and some former Trantor products are being
+  sold under the Adaptec name. If it doesn't work out of the box, you
+  may have to change some settings in drivers/scsi/aha1542.h.
   
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3941,8 +4074,8 @@
 Adaptec AHA1740 support
 CONFIG_SCSI_AHA1740
   This is support for a SCSI host adapter. It is explained in section
-  3.5 of the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
+  3.5 of the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out
   of the box, you may have to change some settings in
   drivers/scsi/aha1740.h.
 
@@ -3975,9 +4108,9 @@
   Information on the configuration options for this controller can be
   found by checking the help file for each of the available
   configuration options. You should read drivers/scsi/README.aic7xxx
-  at a minimum before contacting the maintainer with any questions.  
-  The SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO can also be of great
+  at a minimum before contacting the maintainer with any questions.
+  The SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , can also be of great
   help.
 
   If you want to compile this driver as a module ( = code which can be
@@ -3987,26 +4120,37 @@
 
 Enable or Disable Tagged Command Queueing by default
 CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
-  This option causes the aic7xxx driver to attempt to use tagged command
-  queueing on any devices that claim to support it.  If this is set to yes,
-  you can still turn off TCQ on troublesome devices with the use of the
-  tag_info boot parameter.  See /usr/src/linux/drivers/scsi/README.aic7xxx
-  for more information on that and other aic7xxx setup commands.  If this
-  option is turned off, you may still enable TCQ on known good devices by
-  use of the tag_info boot parameter.
-  
-  If you are unsure about your devices then it is safest to say N here.
+  This option causes the aic7xxx driver to attempt to use Tagged
+  Command Queueing (TCQ) on all devices that claim to support it. 
+
+  TCQ is a feature of SCSI-2 which improves performance: the host
+  adapter can send several SCSI commands to a device's queue even if
+  previous commands haven't finished yet. Because the device is
+  intelligent, it can optimize its operations (like head positioning)
+  based on its own request queue. Not all devices implement this
+  correctly. 
+
+  If you say Y here, you can still turn off TCQ on troublesome devices
+  with the use of the tag_info boot parameter. See the file
+  drivers/scsi/README.aic7xxx for more information on that and other
+  aic7xxx setup commands. If this option is turned off, you may still
+  enable TCQ on known good devices by use of the tag_info boot
+  parameter.
+
+  If you are unsure about your devices then it is safest to say N
+  here.
   
   However, TCQ can increase performance on some hard drives by as much
-  as 50% or more, so I would recommend that if you say N here, that you
-  at least read the README.aic7xxx file so you will know how to enable
-  this option manually should your drives prove to be safe in regards
-  to TCQ.
-
-  Conversely, certain drives are known to lock up or cause bus resets when
-  TCQ is enabled on them.  If you have a Western Digital Enterprise SCSI
-  drive for instance, then don't even bother to enable TCQ on it as the
-  drive will become unreliable, and it will actually reduce performance.
+  as 50% or more, so it is recommended that if you say N here, you
+  should at least read the README.aic7xxx file so you will know how to
+  enable this option manually should your drives prove to be safe in
+  regards to TCQ.
+
+  Conversely, certain drives are known to lock up or cause bus resets
+  when TCQ is enabled on them. If you have a Western Digital
+  Enterprise SCSI drive for instance, then don't even bother to enable
+  TCQ on it as the drive will become unreliable, and it will actually
+  reduce performance.
 
 Default number of TCQ commands per device
 CONFIG_AIC7XXX_CMDS_PER_DEVICE
@@ -4018,14 +4162,14 @@
   figure. If the number is too high for any particular device, the
   driver will automatically compensate usually after only 10 minutes
   of uptime. It will not hinder performance if some of your devices
-  eventually have their command depth reduced, but is a waste of memory
-  if all of your devices end up reducing this number down to a more
-  reasonable figure.
-  
-  NOTE: Certain very broken drives are known to lock up when given more
-  commands than they like to deal with.  Quantum Fireball drives are the
-  most common in this category.  For the Quantum Fireball drives I would
-  suggest no more than 8 commands per device.
+  eventually have their command depth reduced, but is a waste of
+  memory if all of your devices end up reducing this number down to a
+  more reasonable figure.
+  
+  NOTE: Certain very broken drives are known to lock up when given
+  more commands than they like to deal with. Quantum Fireball drives
+  are the most common in this category. For the Quantum Fireball
+  drives it is suggested to use no more than 8 commands per device.
 
   Default: 8
 
@@ -4069,12 +4213,12 @@
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
   This is support for BusLogic MultiMaster and FlashPoint SCSI Host
-  Adapters. Consult the SCSI-HOWTO, available via anonymous FTP from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, and the files
+  Adapters. Consult the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , and the files
   README.BusLogic and README.FlashPoint in drivers/scsi for more
   information. If this driver does not work correctly without
   modification, please contact the author, Leonard N. Zubkoff, by
-  email to lnz@dandelion.com. 
+  email to lnz@dandelion.com.
 
   You can also build this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -4092,9 +4236,9 @@
 DTC3180/3280 SCSI support
 CONFIG_SCSI_DTC3280
   This is support for DTC 3180/3280 SCSI Host Adapters. Please read
-  the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and the file
-  drivers/scsi/README.dtc3x80. 
+  the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , and the file
+  drivers/scsi/README.dtc3x80.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -4110,8 +4254,7 @@
   Note that this driver is obsolete; if you have one of the above SCSI
   Host Adapters, you should normally say N here and Y to "EATA
   ISA/EISA/PCI support", below. Please read the SCSI-HOWTO, available
-  via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  from http://metalab.unc.edu/mdw/linux.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).
@@ -4125,8 +4268,7 @@
   host adapters could also use this driver but are discouraged from
   doing so, since this driver only supports hard disks and lacks
   numerous features. You might want to have a look at the SCSI-HOWTO,
-  available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  available from http://metalab.unc.edu/mdw/linux.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),
@@ -4139,11 +4281,11 @@
   The source at drivers/scsi/u14-34f.c contains some information about
   this hardware. If the driver doesn't work out of the box, you may
   have to change some settings in drivers/scsi/u14-34f.c. Read the
-  SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that there is also
+  SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Note that there is also
   another driver for the same hardware: "UltraStor SCSI support",
   below. You should say Y to both only if you want 24F support as
-  well. 
+  well.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -4174,8 +4316,8 @@
   (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and
   other adapters based on the Future Domain chipsets (Quantum
   ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board).
-  It is explained in section 3.7 of the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  It is explained in section 3.7 of the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip
   and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI
@@ -4189,19 +4331,24 @@
 
 Future Domain MCS-600/700 SCSI support
 CONFIG_SCSI_FD_MCS
- This is support for Future Domain MCS 600/700 MCA SCSI adapters. Some
- PS/2 computers are equipped with IBM Fast SCSI Adapter/A which is
- identical to the MCS 700 and hence also supported by this driver.
- This driver also supports the Reply SB16/SCSI card (the SCSI part).
- It supports multiple adapters in the same system.
+  This is support for Future Domain MCS 600/700 MCA SCSI adapters.
+  Some PS/2 computers are equipped with IBM Fast SCSI Adapter/A which
+  is identical to the MCS 700 and hence also supported by this driver.
+  This driver also supports the Reply SB16/SCSI card (the SCSI part).
+  It supports multiple adapters in the same system.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called fd_mcs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Generic NCR5380/53c400 SCSI support
 CONFIG_SCSI_GENERIC_NCR5380
   This is the generic NCR family of SCSI controllers, not to be
   confused with the NCR 53c7 or 8xx controllers. It is explained in
-  section 3.8 of the SCSI-HOWTO, available via FTP (user: anonymous)
-  at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work
-  out of the box, you may have to change some settings in
+  section 3.8 of the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out
+  of the box, you may have to change some settings in
   drivers/scsi/g_NCR5380.h.
 
   This driver is also available as a module ( = code which can be
@@ -4228,9 +4375,9 @@
 CONFIG_SCSI_NCR53C7xx
   This is a driver for the 53c7 and 8xx NCR family of SCSI
   controllers, not to be confused with the NCR 5380 controllers. It is
-  explained in section 3.8 of the SCSI-HOWTO, available via FTP (user:
-  anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it
-  doesn't work out of the box, you may have to change some settings in
+  explained in section 3.8 of the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out
+  of the box, you may have to change some settings in
   drivers/scsi/53c7,8xx.h. Please read drivers/scsi/README.ncr53c7xx
   for the available boot time command line options.
 
@@ -4279,11 +4426,11 @@
   Recent versions of the 53C8XX chips are better supported by the
   option "SYM53C8XX SCSI support", below.
 
-  Note: there is yet another driver for the 53c8xx family of controllers
-  ("NCR53c7,8xx SCSI support" above). If you want to use them both,
-  you need to say M to both and build them as modules, but only one
-  may be active at a time. If you have a 53c8xx board, you probably do
-  not want to use the "NCR53c7,8xx SCSI support".
+  Note: there is yet another driver for the 53c8xx family of
+  controllers ("NCR53c7,8xx SCSI support" above). If you want to use
+  them both, you need to say M to both and build them as modules, but
+  only one may be active at a time. If you have a 53c8xx board, you
+  probably do not want to use the "NCR53c7,8xx SCSI support".
 
   Please read drivers/scsi/README.ncr53c8xx for more information.
 
@@ -4300,14 +4447,14 @@
   NCR53C8XX and this SYM53C8XX drivers either as module or linked to
   the kernel image.
 
-  When both drivers are linked to the kernel, the SYM53C8XX driver is 
-  called first at initialization and you can use the 'excl=ioaddr' 
-  driver boot option to exclude attachment of adapters by the SYM53C8XX 
-  driver. For instance, entering 'sym53c8xx=excl:0xb400,excl=0xc000' at 
-  lilo prompt prevents adapters at io address 0xb400 and 0xc000 from 
-  being attached by the SYM53C8XX driver, thus allowing the NCR53C8XX 
-  driver to attach them. The 'excl' option is also supported by the 
-  NCR53C8XX driver.
+  When both drivers are linked into the kernel, the SYM53C8XX driver
+  is called first at initialization and you can use the 'excl=ioaddr'
+  driver boot option to exclude attachment of adapters by the
+  SYM53C8XX driver. For example, entering
+  'sym53c8xx=excl:0xb400,excl=0xc000' at the lilo prompt prevents
+  adapters at io address 0xb400 and 0xc000 from being attached by the
+  SYM53C8XX driver, thus allowing the NCR53C8XX driver to attach them.
+  The 'excl' option is also supported by the NCR53C8XX driver.
   
   Please read drivers/scsi/README.ncr53c8xx for more information.
 
@@ -4365,9 +4512,11 @@
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS
   "Tagged command queuing" is a feature of SCSI-2 which improves
   performance: the host adapter can send several SCSI commands to a
-  device's queue even if previous commands haven't finished yet. Some
-  SCSI devices don't implement this properly; if you want to disable
-  this feature, enter 0 or 1 here (it doesn't matter which).
+  device's queue even if previous commands haven't finished yet.
+  Because the device is intelligent, it can optimize its operations
+  (like head positioning) based on its own request queue. Some SCSI
+  devices don't implement this properly; if you want to disable this
+  feature, enter 0 or 1 here (it doesn't matter which).
 
   The default value is 8 and should be supported by most hard disks.
   This value can be overridden from the boot command line using the 
@@ -4448,8 +4597,8 @@
   '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 via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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),
@@ -4525,9 +4674,9 @@
 
 Initio 91XXU(W) SCSI support
 CONFIG_SCSI_INITIO
-  This is support for the Initio 91XXU(W) SCSI host adapter.
-  Please read the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  This is support for the Initio 91XXU(W) SCSI host adapter. Please
+  read the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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),
@@ -4537,8 +4686,8 @@
 PAS16 SCSI support
 CONFIG_SCSI_PAS16
   This is support for a SCSI host adapter. It is explained in section
-  3.10 of the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
+  3.10 of the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out
   of the box, you may have to change some settings in
   drivers/scsi/pas16.h.
   
@@ -4549,9 +4698,9 @@
 
 Initio INI-A100U2W SCSI support
 CONFIG_SCSI_INIA100
-  This is support for the Initio INI-A100U2W SCSI host adapter.
-  Please read the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  This is support for the Initio INI-A100U2W SCSI host adapter. Please
+  read the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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),
@@ -4561,8 +4710,8 @@
 PCI2000 support
 CONFIG_SCSI_PCI2000
   This is support for the PCI2000I EIDE interface card which acts as a
-  SCSI host adapter. Please read the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  SCSI host adapter. Please read the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   This driver is also available as a module called pci2000.o ( = code
   which can be inserted in and removed from the running kernel
@@ -4572,8 +4721,8 @@
 PCI2220i support
 CONFIG_SCSI_PCI2220I
   This is support for the PCI2220i EIDE interface card which acts as a
-  SCSI host adapter. Please read the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  SCSI host adapter. Please read the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   This driver is also available as a module called pci2220i.o ( = code
   which can be inserted in and removed from the running kernel
@@ -4583,8 +4732,8 @@
 PSI240i support
 CONFIG_SCSI_PSI240I
   This is support for the PSI240i EIDE interface card which acts as a
-  SCSI host adapter. Please read the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  SCSI host adapter. Please read the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   This driver is also available as a module called psi240i.o ( = code
   which can be inserted in and removed from the running kernel
@@ -4603,8 +4752,7 @@
 
   Information about this driver is contained in
   drivers/scsi/README.qlogicfas. You should also read the SCSI-HOWTO,
-  available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  available from http://metalab.unc.edu/mdw/linux.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).
@@ -4621,8 +4769,8 @@
   access mode".
 
   Please read the file drivers/scsi/README.qlogicisp. You should also
-  read the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  read the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -4642,9 +4790,8 @@
 CONFIG_SCSI_SEAGATE
   These are 8-bit SCSI controllers; the ST-01 is also supported by
   this driver. It is explained in section 3.9 of the SCSI-HOWTO,
-  available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
-  of the box, you may have to change some settings in
+  available from http://metalab.unc.edu/mdw/linux.html#howto . If it
+  doesn't work out of the box, you may have to change some settings in
   drivers/scsi/seagate.h.
 
   This driver is also available as a module ( = code which can be
@@ -4655,8 +4802,8 @@
 Trantor T128/T128F/T228 SCSI support
 CONFIG_SCSI_T128
   This is support for a SCSI host adapter. It is explained in section
-  3.11 of the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
+  3.11 of the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out
   of the box, you may have to change some settings in
   drivers/scsi/t128.h. Note that Trantor was purchased by Adaptec, and
   some former Trantor products are being sold under the Adaptec name.
@@ -4670,8 +4817,8 @@
 CONFIG_SCSI_ULTRASTOR
   This is support for the UltraStor 14F, 24F and 34F SCSI-2 host
   adapter family. This driver is explained in section 3.12 of the
-  SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
+  SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out
   of the box, you may have to change some settings in
   drivers/scsi/ultrastor.h.
   
@@ -4711,8 +4858,8 @@
   subsystem are probed as well.
 
   You want to read the start of drivers/scsi/eata.c and the
-  SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   Note that there is also another driver for the same hardware
   available: "EATA-DMA support". You should say Y to only one of them.
@@ -4751,8 +4898,8 @@
 CONFIG_SCSI_NCR53C406A
   This is support for the NCR53c406a SCSI host adapter. For user
   configurable parameters, check out drivers/scsi/NCR53c406.c in the
-  kernel source. Also read the SCSI-HOWTO, available via FTP (user:
-  anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  kernel source. Also read the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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),
@@ -4815,8 +4962,8 @@
 CONFIG_SCSI_AM53C974
   This is support for the AM53/79C974 SCSI host adapters. Please read
   drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO,
-  available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, is for you.
+  available from http://metalab.unc.edu/mdw/linux.html#howto , is for
+  you.
 
   Note that there is another driver for AM53C974 based adapters:
   "Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support", above. You
@@ -4837,12 +4984,6 @@
   say M here and read Documentation/modules.txt. The module will be
   called megaraid.o.
 
-###
-### What is this?
-###
-#Concurrent IO commands on MegaRAID
-#CONFIG_MEGARAID_MULTI_IO
-
 GDT SCSI Disk Array Controller support
 CONFIG_SCSI_GDTH
   This is a driver for all SCSI Disk Array Controllers (EISA/ISA/PCI) 
@@ -4870,8 +5011,8 @@
 
   For more information about this driver and how to use it you should
   read the file drivers/scsi/README.ppa. You should also read the
-  SCSI-HOWTO, which is available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If you use this driver,
+  SCSI-HOWTO, which is available from
+  http://metalab.unc.edu/mdw/linux.html#howto . If you use this driver,
   you will still be able to use the parallel port for other tasks,
   such as a printer; it is safe to compile both drivers into the
   kernel.
@@ -4897,8 +5038,8 @@
 
   For more information about this driver and how to use it you should
   read the file drivers/scsi/README.ppa. You should also read the
-  SCSI-HOWTO, which is available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If you use this driver,
+  SCSI-HOWTO, which is available from
+  http://metalab.unc.edu/mdw/linux.html#howto . If you use this driver,
   you will still be able to use the parallel port for other tasks,
   such as a printer; it is safe to compile both drivers into the
   kernel.
@@ -5022,31 +5163,28 @@
   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 via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO) or dialing up a shell
+  the UUCP-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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 (to browse
-  the WWW, you need to have access to a machine on the Internet that
-  has a program like lynx or netscape)).
+  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), available from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini) 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).
+  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 ftp://metalab.unc.edu/pub/Linux/docs/LDP. If
+  Guide", to be found in ftp://metalab.unc.edu/pub/Linux/docs/LDP . If
   unsure, say Y.
 
 Dummy net driver support
@@ -5055,11 +5193,11 @@
   this device is consigned into oblivion) with a configurable IP
   address. It is most commonly used in order to make your currently
   inactive SLIP address seem like a real address for local programs.
-  If you use SLIP or PPP, you might want to say Y here. Read about it
-  in the Network Administrator's Guide, available via FTP (user:
-  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/LDP. Since this
+  If you use SLIP or PPP, you might want to say Y here. Since this
   thing often comes in handy, the default is Y. It won't enlarge your
-  kernel either. What a deal.
+  kernel either. What a deal. Read about it in the Network
+  Administrator's Guide, available from
+  http://metalab.unc.edu/mdw/linux.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),
@@ -5085,16 +5223,14 @@
   ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which
   allows you to use SLIP over a regular dial up shell connection. If
   you plan to use SLiRP, make sure to say Y to CSLIP, below. The
-  NET-3-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, explains how to
+  NET-3-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , explains how to
   configure SLIP. Note that you don't need this option if you just
   want to run term (term is a program which gives you almost full
   Internet connectivity if you have a regular dial up shell account on
   some Internet connected Unix computer. Read
-  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html (to browse
-  the WWW, you need to have access to a machine on the Internet that
-  has a program like lynx or netscape)). SLIP support will enlarge
-  your kernel by about 4 KB. If unsure, say N.
+  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ). SLIP
+  support will enlarge your kernel by about 4 KB. If unsure, say N.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -5108,13 +5244,12 @@
   TCP/IP headers (not on the data itself), but it has to be supported
   on both ends. Ask your access provider if you are not sure and
   answer Y, just in case. You will still be able to use plain SLIP. If
-  you plan to use SLiRP, the SLIP emulator (available via FTP (user:
-  anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/system/network/serial/) which allows
+  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
-  definitely want to say Y here. The NET-3-HOWTO, available via FTP
-  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO,
-  explains how to configure CSLIP. This won't enlarge your kernel.
+  definitely want to say Y here. The NET-3-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , explains how to
+  configure CSLIP. This won't enlarge your kernel.
 
 Keepalive and linefill
 CONFIG_SLIP_SMART
@@ -5136,23 +5271,30 @@
 CONFIG_PPP
   PPP (Point to Point Protocol) is a newer and better SLIP. It serves
   the same purpose: sending Internet traffic over telephone (and other
-  serial) lines.  Most ISPs these days support PPP rather than SLIP.
+  serial) lines. Ask your access provider if they support it, because
+  otherwise you can't use it; most internet access providers these
+  days support PPP rather than SLIP.
 
   To use PPP, you need an additional program called pppd as described
   in Documentation/networking/ppp.txt and in the PPP-HOWTO, available
-  from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If you upgrade
+  at http://metalab.unc.edu/mdw/linux.html#howto . If you upgrade
   from an older kernel, you might need to upgrade pppd as well. The
   PPP option enlarges your kernel by about 16 KB.
 
-  Almost always, if you answer Y or M to this question, you should
-  give the same answer to the next question, about PPP support for
-  async serial ports.
+  There are actually two versions of PPP: the traditional PPP for
+  asynchronous lines, such as regular analog phone lines, and
+  synchronous PPP which can be used over digital ISDN lines for
+  example. If you want to use PPP over phone lines or other
+  asynchronous serial lines, you need to say Y (or M) here and also to
+  the next option, "PPP support for async serial ports". For PPP over
+  synchronous lines, you should say Y (or M) here and to "Support
+  synchronous PPP", below.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   If you said Y to "Version information on all symbols" above, then
   you cannot compile the PPP driver into the kernel; you can then only
-  compile it as a module. The module will be called ppp_generic.o.  If
+  compile it as a module. The module will be called ppp_generic.o. If
   you want to compile it as a module, say M here and read
   Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
@@ -5172,10 +5314,10 @@
 CONFIG_PPP_DEFLATE
   Support for the Deflate compression method for PPP, which uses the
   Deflate algorithm (the same algorithm that gzip uses) to compress
-  each PPP packet before it is sent over the wire.  The peer (the
-  machine at the other end of the PPP link, usually your ISP) has to
-  support the Deflate compression method as well for this to be
-  useful.
+  each PPP packet before it is sent over the wire. The machine at the
+  other end of the PPP link (usually your ISP) has to support the
+  Deflate compression method as well for this to be useful. Even if
+  they don't support it, it is safe to say Y here.
 
   This code is also available as a module (code which can be inserted
   into and removed from the running kernel).  If you want to compile
@@ -5185,15 +5327,19 @@
 CONFIG_PPP_BSDCOMP
   Support for the BSD-Compress compression method for PPP, which uses
   the LZW compression method to compress each PPP packet before it is
-  sent over the wire.  The peer (the other end of the PPP link) has to
-  support the BSD-Compress compression method as well for this to be
-  useful.  The PPP Deflate compression method is preferable to
-  BSD-Compress, because it compresses better and is patent-free.
+  sent over the wire. The machine at the other end of the PPP link
+  (usually your ISP) has to support the BSD-Compress compression
+  method as well for this to be useful. Even if they don't support it,
+  it is safe to say Y here.
+
+  The PPP Deflate compression method ("PPP Deflate compression",
+  above) is preferable to BSD-Compress, because it compresses better
+  and is patent-free.
 
   Note that the BSD compression code will always be compiled as a
   module; it is called bsd_comp.o and will show up in the directory
   modules once you have said "make modules". If unsure, say N.
-
+ 
 Wireless LAN (non-hamradio)
 CONFIG_NET_RADIO
   Support for wireless LANs and everything having to do with radio,
@@ -5203,22 +5349,20 @@
   interfaces. 
 
   Some user-level drivers for scarab devices which don't require
-  special kernel support are available via FTP (user: anonymous) from
-  ftp://shadow.cabi.net/pub/Linux.
+  special kernel support are available from
+  ftp://shadow.cabi.net/pub/Linux .
 
 STRIP (Metricom Starmode radio IP)
 CONFIG_STRIP
   Say Y if you have a Metricom radio and intend to use Starmode Radio
   IP. STRIP is a radio protocol developed for the MosquitoNet project
-  (On the WWW at http://mosquitonet.stanford.edu/; to browse the WWW,
-  you need to have access to a machine on the Internet that has a
-  program like lynx or netscape) to send Internet traffic using
-  Metricom radios. Metricom radios are small, battery powered,
-  100kbit/sec packet radio transceivers, about the size and weight of
-  a cellular telephone. (You may also have heard them called
+  (on the WWW at http://mosquitonet.stanford.edu/ ) to send Internet
+  traffic using Metricom radios. Metricom radios are small, battery
+  powered, 100kbit/sec packet radio transceivers, about the size and
+  weight of a cellular telephone. (You may also have heard them called
   "Metricom modems" but we avoid the term "modem" because it misleads
   many people into thinking that you can plug a Metricom modem into a
-  phone line and use it as a modem.)  
+  phone line and use it as a modem.)
 
   You can use STRIP on any Linux machine with a serial port, although
   it is obviously most useful for people with laptop computers. If you
@@ -5243,14 +5387,14 @@
   location).
 
   If you want to use an ISA WaveLAN card under Linux, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Some more specific
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Some more specific
   information is contained in Documentation/networking/wavelan.txt and
   in the source code drivers/net/wavelan.p.h.
 
   You will also need the wireless tools package available from
-  ftp://ftp.inka.de/pub/comp/Linux/networking/NetTools/contrib/.
-  Please read the man pages contained therein.
+  ftp://hyper.stanford.edu/pub/pcmcia/contrib/ . 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).
@@ -5260,14 +5404,16 @@
 
 Aironet Arlan 655 & IC2200 DS support
 CONFIG_ARLAN
-  Aironet makes Arlan. www.aironet.com. Uses www.Telxon.com chip, which is
-  used on several similar cards. Driver is tested on 655 and IC2200 series. 
-  Look for http://www.ylenurme.ee/~elmer/655/ for latest information. 
-  Driver is build as two modules, arlan and arlan-proc. The later is /proc
-  interface and not needed most of time.
+  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.
+  
+  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.
-   
 
 LAPB over Ethernet driver
 CONFIG_LAPBETHER
@@ -5295,6 +5441,39 @@
   say M here and read Documentation/modules.txt. The module will be
   called x25_asy.o. If unsure, say N.
 
+PCMCIA ethernet cards (NE2000 compatibles: DE-650, ...)
+CONFIG_PCMCIA_PCNET
+  Say Y here if you intend to attach an NE2000 compatible PCMCIA
+  (PC-card) 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 pcnet_cs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
+
+3Com 3c589 PCMCIA card
+CONFIG_PCMCIA_3C589
+  Say Y here if you intend to attach a 3Com 3c589 PCMCIA
+  (PC-card) 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 3c589_cs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
+
+Aviator/Raytheon 2.4MHz wireless
+CONFIG_PCMCIA_RAYCS
+  Say Y here if you intend to attach an Aviator/Raytheon 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 ray_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
 CONFIG_PLIP
   PLIP (Parallel Line Internet Protocol) is used to create a
@@ -5314,17 +5493,15 @@
   Documentation/networking/PLIP.txt. The cables can be up to 15m long.
   Mode 0 works also if one of the machines runs DOS/Windows and has
   some PLIP software installed, e.g. the Crynwr PLIP packet driver
-  (http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html; to browse
-  the WWW, you need to have access to a machine on the Internet that
-  has a program like lynx or netscape) and winsock or NCSA's telnet.
-
-  If you want to use PLIP, say Y and read the PLIP mini-HOWTO,
-  available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini as well as the
-  NET-3-HOWTO in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that
-  the PLIP protocol was changed and this PLIP driver won't work
-  together with the PLIP support in Linux versions 1.0.x. This option
-  enlarges your kernel by about 8 KB.
+  (http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html ) and
+  winsock or NCSA's telnet.
+
+  If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well
+  as the NET-3-HOWTO, both available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Note that the PLIP
+  protocol has been changed and this PLIP driver won't work together
+  with the PLIP support in Linux versions 1.0.x. This option enlarges
+  your kernel by about 8 KB.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -5344,8 +5521,7 @@
 
   Say Y if you want this and read Documentation/networking/eql.txt.
   You may also want to read section 6.2 of the NET-3-HOWTO, available
-  via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  from http://metalab.unc.edu/mdw/linux.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).
@@ -5372,8 +5548,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 ethertap.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt. If you don't
-  know what to use this for, you don't need it.
+  module, say M here and read Documentation/modules.txt. 
+
+  If you don't know what to use this for, you don't need it.
 
 Sealevel Systems 4021 support
 CONFIG_SEALEVEL_4021
@@ -5393,11 +5570,10 @@
   network, usually at the phone company) can carry several logical
   point-to-point connections to other computers connected to the frame
   relay network. For a general explanation of the protocol, check out
-  http://www.frforum.com/ on the WWW. (To browse the WWW, you need to
-  have access to a machine on the Internet that has a program like
-  lynx or netscape.) To use frame relay, you need supporting hardware
-  (called FRAD) and certain programs from the net-tools package as
-  explained in Documentation/networking/framerelay.txt.
+  http://www.frforum.com/ on the WWW. To use frame relay, you need
+  supporting hardware (called FRAD) and certain programs from the
+  net-tools package as explained in
+  Documentation/networking/framerelay.txt.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5473,9 +5649,8 @@
   the price of an external router. If you have one of those cards and
   wish to use your Linux box as a WAN router, say Y here and also to
   the WAN driver for your card, below. You will then need the
-  wan-tools package which is available via FTP (user: anonymous) from
-  ftp://ftp.sangoma.com. Read Documentation/networking/wan-router.txt
-  for more information.
+  wan-tools package which is available from ftp://ftp.sangoma.com .
+  Read Documentation/networking/wan-router.txt for more information.
 
   The WAN routing support is also available as a module called
   wanrouter.o ( = code which can be inserted in and removed from the
@@ -5487,17 +5662,18 @@
 Fast switching (read help!)
 CONFIG_NET_FASTROUTE
   Saying Y here enables direct NIC-to-NIC (NIC = Network Interface
-  Card) data transfers, which is fast.
+  Card) data transfers on the local network, which is fast.
 
-    *** This option is NOT COMPATIBLE with several important ***
-    *** networking options: especially CONFIG_NETFILTER.     ***
-    *** Say N here if you intend to use Linux as a firewall. ***
+  IMPORTANT NOTE: This option is NOT COMPATIBLE with "Network packet
+  filtering" (CONFIG_NETFILTER). Say N here if you say Y there.
+
+  However, it will work with all options in the "IP: advanced router"
+  section (except for "IP: use TOS value as routing key" and
+  "IP: use FWMARK value as routing key").
 
-  However, it will work with all options in CONFIG_IP_ADVANCED_ROUTER
-  section (except for CONFIG_IP_ROUTE_TOS and CONFIG_IP_ROUTE_FWMARK).
   At the moment, few devices support fast switching (tulip is one of
-  them, modified 8390 can be found at
-  ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz).
+  them, a modified 8390 driver can be found at
+  ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz ).
 
   If unsure, say N.
 
@@ -5505,40 +5681,41 @@
 CONFIG_NET_HW_FLOWCONTROL
   This option enables NIC (Network Interface Card) hardware throttling
   during periods of extremal congestion. At the moment only a couple
-  of device drivers support it (really only one -- tulip, modified
-  8390 can be found at
-  ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz).
-  Really, this option is applicable to any machine attached to a fast enough
-  network, and even a 10 Mb NIC is able to kill a not very slow box,
-  such as a 120MHz Pentium.
+  of device drivers support it (really only one -- tulip, a modified
+  8390 driver can be found at
+  ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz ). 
+
+  Really, this option is applicable to any machine attached to a fast
+  enough network, and even a 10 Mb NIC is able to kill a not very slow
+  box, such as a 120MHz Pentium.
 
   However, do not say Y here if you did not experience any serious
   problems.
 
-CPU is too slow to handle full bandwidth
-CONFIG_CPU_IS_SLOW
-  If you suspect that your CPU is not fast enough to handle the
-  full bandwidth of your network connection, try saying Y here. If
-  unsure, say N.
-
 QoS and/or fair queueing
 CONFIG_NET_SCHED
-  When the kernel has several packets to send out over the network
-  devices, it has to make a decision which one to send first. This is
-  especially important if some of the network devices are real time
-  devices that need a certain minimum data flow rate. There are
-  several different algorithms for how to do this "fairly"; they are
-  called packet schedulers. If you want to stick to the default
-  scheduling algorithm, say N here. If you want to experiment with a
-  couple of different algorithms, say Y. You can then attach different
-  schedulers to different network devices. Currently, this is only
-  recommended for experts.
+  When the kernel has several packets to send out over a network
+  device, it has to decide which ones to send first, which ones to
+  delay, and which ones to drop. This is the job of the packet
+  scheduler, and several different algorithms for how to do this
+  "fairly" have been proposed.
+
+  If you say N here, you will get the standard packet scheduler, which
+  is a FIFO (first come, first served). If you say Y here, you will be
+  able to choose from among several alternative algorithms which can
+  then be attached to different network devices. This is useful for
+  example if some of your network devices are real time devices that
+  need a certain minimum data flow rate, or if you need to limit the
+  maximum data flow rate for traffic which matches specified criteria.
+  This code is considered to be experimental.
 
   To administer these schedulers, you'll need the user-level utilities
-  from the package iproute2+tc at ftp://ftp.inr.ac.ru/ip-routing/
+  from the package iproute2+tc at ftp://ftp.inr.ac.ru/ip-routing/ .
+  That package also contains some documentation; for more, check out
+  http://snafu.freedom.org/linux2.2/iproute-notes.html .
 
   If you say Y here and to "/proc filesystem" below, you will be able
-  to read status information about priority schedulers from the file
+  to read status information about packet schedulers from the file
   /proc/net/psched.
   
   The available schedulers are listed in the following questions; you
@@ -5550,9 +5727,17 @@
   scheduling algorithm for some of your network devices. This
   algorithm classifies the waiting packets into a tree-like hierarchy
   of classes; the leaves of this tree are in turn scheduled by
-  separate algorithms (called "disciplines" in this context) which you
-  can choose below from among the various queueing algorithms. See the
-  top of net/sched/sch_cbq.c for references about the CBQ algorithm.
+  separate algorithms (called "disciplines" in this context).
+
+  See the top of net/sched/sch_cbq.c for references about the CBQ
+  algorithm.
+  
+  CBQ is a commonly used scheduler, so if you're unsure, you should
+  say Y here. Then say Y to all the queueing algorithms below that you
+  want to use as CBQ disciplines. Then say Y to "Packet classifier
+  API" and say Y to all the classifiers you want to use; a classifier
+  is a routine that allows you to sort your outgoing traffic into
+  classes based on a certain criterion.
 
   This code is also available as a module called sch_cbq.o ( = code
   which can be inserted in and removed from the running kernel
@@ -5574,11 +5759,17 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
+#ATM pseudo-scheduler
+#CONFIG_NET_SCH_ATM
+#
+# ???
+#
+  
 The simplest PRIO pseudo scheduler
 CONFIG_NET_SCH_PRIO
   Say Y here if you want to use an n-band priority queue packet
   "scheduler" for some of your network devices or as a leaf discipline
-  for the CBQ scheduling algorithm. 
+  for the CBQ scheduling algorithm. If unsure, say Y.
 
   This code is also available as a module called sch_prio.o ( = code
   which can be inserted in and removed from the running kernel
@@ -5590,7 +5781,7 @@
   Say Y here if you want to use the Random Early Detection (RED)
   packet scheduling algorithm for some of your network devices (see
   the top of net/sched/sch_red.c for details and references about the
-  algorithm). 
+  algorithm).
 
   This code is also available as a module called sch_red.o ( = code
   which can be inserted in and removed from the running kernel
@@ -5640,7 +5831,7 @@
 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 net devices.
+  rate-of-flow limits for your network devices.
 
   Note that the answer to this question won't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -5655,24 +5846,70 @@
 Packet classifier API
 CONFIG_NET_CLS
   The CBQ scheduling algorithm requires that network packets which are
-  scheduled to be sent out over a network device be classified in some
-  way. If you say Y here, you will get a choice of several different
-  packet classifiers with the following questions. 
-#
-# Routing tables based classifier
-# CONFIG_NET_CLS_ROUTE
-#
-# Firewall based classifier
-# CONFIG_NET_CLS_FW
-#
-# U32 classifier
-# CONFIG_NET_CLS_U32
-#
-# Special RSVP classifier
-# CONFIG_NET_CLS_RSVP
-#
-# Special RSVP classifier for IPv6
-# CONFIG_NET_CLS_RSVP6
+  scheduled to be sent out over a network device be classified
+  according to some criterion. If you say Y here, you will get a
+  choice of several different packet classifiers with the following
+  questions.
+
+Routing tables based classifier
+CONFIG_NET_CLS_ROUTE
+  If you say Y here, you will be able to classify outgoing packets
+  according to the route table entry they matched. If unsure, say Y.
+
+  This code is also available as a module called cls_route.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+Firewall based classifier
+CONFIG_NET_CLS_FW
+  If you say Y here, you will be able to classify outgoing packets
+  according to firewall criteria you specified.
+
+  This code is also available as a module called cls_fw.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+U32 classifier
+CONFIG_NET_CLS_U32
+  If you say Y here, you will be able to classify outgoing packets
+  according to their destination address. If unsure, say Y.
+
+  This code is also available as a module called cls_u32.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt
+
+Special RSVP classifier
+CONFIG_NET_CLS_RSVP
+  The Resource Reservation Protocol (RSVP) permits end systems to
+  request a minimum and maximum data flow rate for a connection; this
+  is important for real time data such as streaming sound or video.
+
+  Say Y here if you want to be able to classify outgoing packets based
+  on their RSVP requests.
+
+  This code is also available as a module called cls_rsvp.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt
+
+Special RSVP classifier for IPv6
+CONFIG_NET_CLS_RSVP6
+  The Resource Reservation Protocol (RSVP) permits end systems to
+  request a minimum and maximum data flow rate for a connection; this
+  is important for real time data such as streaming sound or video.
+
+  Say Y here if you want to be able to classify outgoing packets based
+  on their RSVP requests and you are using the new Internet Protocol
+  IPv6 as opposed to the older and more common IPv4.
+
+  This code is also available as a module called cls_rsvp6.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt
+
 #
 # Ingres traffic policing
 # CONFIG_NET_CLS_POLICE
@@ -5716,6 +5953,12 @@
   The module will be called cosa.o. For general information about
   modules read Documentation/modules.txt.
 
+# Fibre Channel driver support
+# CONFIG_NET_FC
+
+# Interphase 5526 Tachyon chipset based adaptor support
+# CONFIG_IPHASE5526
+
 Red Creek Hardware VPN (EXPERIMENTAL)
 CONFIG_RCPCI
   This is a driver for hardware which provides a Virtual Private
@@ -5742,16 +5985,15 @@
 
 Sangoma WANPIPE(tm) multiprotocol cards
 CONFIG_VENDOR_SANGOMA
-  WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com; to
-  browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape) 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).
@@ -5793,23 +6035,22 @@
 Cyclom 2X(tm) multiprotocol cards
 CONFIG_CYCLADES_SYNC
   Cyclom 2X from Cyclades Corporation (http://www.cyclades.com and
-  http://www.cyclades.com.br; to browse the WWW, you need to have
-  access to a machine on the Internet that has a program like lynx or
-  netscape) is an intelligent multiprotocol WAN adapter with data
-  transfer rates up to 512 Kbps). These cards support the X.25 and SNA
-  related protocols. If you have one or more of these cards, say Y to
-  this option. The next questions will ask you about the protocols you
-  want the driver to support (for now only X.25 is supported).
+  http://www.cyclades.com.br ) is an intelligent multiprotocol WAN
+  adapter with data transfer rates up to 512 Kbps. These cards support
+  the X.25 and SNA related protocols. If you have one or more of these
+  cards, say Y to this option. The next questions will ask you about
+  the protocols you want the driver to support (for now only X.25 is
+  supported).
 
   While no documentation is available at this time please grab the
   wanconfig tarball in http://www.conectiva.com.br/~acme/cycsyn-devel
   (with minor changes to make it compile with the current wanrouter
   include files; efforts are being made to use the original package
-  available at ftp://ftp.sangoma.com).
+  available at ftp://ftp.sangoma.com ).
 
   Feel free to contact me or the cycsyn-devel mailing list at
   acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for
-  aditional details, I hope to have documentation available as soon
+  additional details, I hope to have documentation available as soon
   as possible.
 
   The driver will be compiled as a module ( = code which can be
@@ -5821,6 +6062,7 @@
 CONFIG_CYCLOMX_X25
   Say Y to this option if you are planning to connect a Cyclom 2X card
   to an X.25 network. 
+
   If you say N, the X.25 support will not be included in the driver
   (saves about 11 KB of kernel memory).
 
@@ -5841,9 +6083,9 @@
 
   If your Linux machine will be connected to an Ethernet and you have
   an Ethernet network interface card (NIC) installed in your computer,
-  say Y here and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You will
-  then also have to say Y to the driver for your particular NIC.
+  say Y here and read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . You will then also have
+  to say Y to the driver for your particular NIC.
 
   Note that the answer to this question won't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -5868,8 +6110,8 @@
 Western Digital/SMC cards
 CONFIG_NET_VENDOR_SMC
   If you have a network (Ethernet) card belonging to this class, say Y
-  and read the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  and read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -5879,8 +6121,8 @@
 WD80*3 support
 CONFIG_WD80x3
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -5891,9 +6133,8 @@
 SMC Ultra MCA support
 CONFIG_ULTRAMCA
   If you have a network (Ethernet) card of this type and are running
-  an MCA based system (PS/2), say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  an MCA based system (PS/2), say Y and read the Ethernet-HOWTO,
+  available from http://metalab.unc.edu/mdw/linux.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).
@@ -5904,8 +6145,8 @@
 SMC Ultra support
 CONFIG_ULTRA
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
   
   Important: There have been many reports that, with some motherboards
   mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible,
@@ -5923,8 +6164,8 @@
 SMC Ultra32 EISA support
 CONFIG_ULTRA32
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -5939,8 +6180,7 @@
   another SMC9192/9194 based chipset. Say Y if you want it compiled
   into the kernel, and read the file
   Documentation/networking/smc9.txt and the Ethernet-HOWTO, available
-  via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  from http://metalab.unc.edu/mdw/linux.html#howto .
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you
@@ -5953,8 +6193,8 @@
   This driver is for NE2000 compatible PCI cards. It will not work
   with ISA NE2000 cards (they have their own driver, "NE2000/NE1000
   support" below). If you have a PCI NE2000 network (Ethernet) card,
-  say Y and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  say Y and read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -5966,8 +6206,7 @@
 CONFIG_NET_VENDOR_RACAL
   If you have a network (Ethernet) card belonging to this class, such
   as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
-  available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  available from http://metalab.unc.edu/mdw/linux.html#howto .
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -5977,9 +6216,9 @@
 NI5010 support
 CONFIG_NI5010
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that this is still
-  experimental code. 
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Note that this is still
+  experimental code.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5990,8 +6229,8 @@
 NI5210 support
 CONFIG_NI52
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6002,8 +6241,8 @@
 NI6510 support
 CONFIG_NI65
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6015,22 +6254,33 @@
 CONFIG_RTL8139
   This is a driver for the Fast Ethernet PCI network cards based on
   the RTL8129 and RTL8139 chips. 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.
+  read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called rtl8139.o.
 
+SiS 900 PCI Fast Ethernet Adapter support
+CONFIG_SIS900
+  This is a driver for the Silicon Integrated System Corporation 900
+  Fast Ethernet PCI network card. If you have one of those, say Y and
+  read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called sis900.o.
+
 Packet Engines Yellowfin Gigabit-NIC support
 CONFIG_YELLOWFIN
   Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
   adapter. This adapter is used by the Beowulf Linux cluster project.
   See http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html for
   more information about this driver in particular and Beowulf in
-  general (to browse the WWW, you need to have access to a machine on
-  the Internet that has a program like lynx or netscape).
+  general.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -6039,16 +6289,19 @@
 
 General Instruments Surfboard 1000
 CONFIG_NET_SB1000
-  This is a driver for the General Instrument SURFboard 1000 internal cable
-  modem.  This is an ISA card which is used by a number of cable TV companies
-  to provide cable modem access.  It's a one-way downstream-only cable modem,
-  meaning that your upstream net link is provided by your regular phone modem.
-
-  At present this driver only compiles as a module, so say M here if you
-  have this card.  Then read Documentation/networking/README.sb1000 for
-  information on how to use this module, as it needs special ppp scripts for
-  establishing a connection.  Further documentation and the necessary scripts
-  can be found at:
+  This is a driver for the General Instrument (also known as
+  NextLevel) SURFboard 1000 internal
+  cable modem. This is an ISA card which is used by a number of cable
+  TV companies to provide cable modem access. It's a one-way
+  downstream-only cable modem, meaning that your upstream net link is
+  provided by your regular phone modem.
+
+  At present this driver only compiles as a module, so say M here if
+  you have this card. The module will be called sb1000.o. Then read
+  Documentation/networking/README.sb1000 for information on how to use
+  this module, as it needs special ppp scripts for establishing a
+  connection. Further documentation and the necessary scripts can be
+  found at:
 
   http://www.jacksonville.net/~fventuri/
   http://home.adelphia.net/~siglercm/sb1000.html
@@ -6084,8 +6337,8 @@
 AMD LANCE and PCnet (AT1500 and NE2100) support
 CONFIG_LANCE
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Some LinkSys cards are
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Some LinkSys cards are
   of this type.
 
   If you want to compile this driver as a module ( = code which can be
@@ -6096,8 +6349,8 @@
 3COM cards
 CONFIG_NET_VENDOR_3COM
   If you have a network (Ethernet) card belonging to this class, say Y
-  and read the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  and read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -6107,8 +6360,8 @@
 3c501 support
 CONFIG_EL1
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Also, consider buying a
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Also, consider buying a
   new card, since the 3c501 is slow, broken, and obsolete: you will
   have problems. Some people suggest to ping ("man ping") a nearby
   machine every minute ("man cron") when using this card.
@@ -6122,8 +6375,8 @@
 3c503 support
 CONFIG_EL2
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6135,8 +6388,8 @@
 CONFIG_ELPLUS
   Information about this network (Ethernet) card can be found in
   Documentation/networking/3c505.txt. If you have a card of this type,
-  say Y and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  say Y and read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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),
@@ -6147,8 +6400,8 @@
 3c507 support
 CONFIG_EL16
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6159,8 +6412,8 @@
 3c523 support 
 CONFIG_ELMC
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6171,8 +6424,8 @@
 3c527 support
 CONFIG_ELMC_II
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6184,8 +6437,7 @@
 CONFIG_EL3
   If you have a network (Ethernet) card belonging to the 3Com
   EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
-  via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  from http://metalab.unc.edu/mdw/linux.html#howto .
 
   If your card is not working you may need to use the DOS
   setup disk to disable Plug & Play mode, and to select the default
@@ -6201,10 +6453,10 @@
 CONFIG_VORTEX
   If you have a 3Com "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597)
   or "Boomerang" series (EtherLink XL 3c900 or 3c905) network
-  (Ethernet) card, say Y and read the Ethernet-HOWTO, available via
-  FTP (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
-  More specific information is in Documentation/networking/vortex.txt
-  and in the comments at the beginning of drivers/net/3c59x.c.
+  (Ethernet) card, say Y and read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . More specific
+  information is in Documentation/networking/vortex.txt and in the
+  comments at the beginning of drivers/net/3c59x.c.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -6217,8 +6469,9 @@
   bus system (that's the way the cards talks to the other components
   of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y.
   Make sure you know the name of your card. Read the Ethernet-HOWTO,
-  available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If unsure, say Y.
+  available from http://metalab.unc.edu/mdw/linux.html#howto . 
+
+  If unsure, say Y.
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -6236,9 +6489,8 @@
   support" below.
 
   You might also want to have a look at the Ethernet-HOWTO, available
-  via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO (even though ARCnet is
-  not really Ethernet).
+  from http://metalab.unc.edu/mdw/linux.html#howto (even though ARCnet
+  is not really Ethernet).
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -6324,8 +6576,8 @@
 Cabletron E21xx support
 CONFIG_E2100
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6337,8 +6589,8 @@
 CONFIG_CS89x0
   Support for CS89x0 chipset based Ethernet cards. If you have a
   network (Ethernet) card of this type, say Y and read the
-  Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO as well as
+  Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto as well as
   Documentation/networking/cs89x0.txt.
 
   If you want to compile this as a module ( = code which can be
@@ -6350,8 +6602,8 @@
 DEPCA support
 CONFIG_DEPCA
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO as well as
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto as well as
   drivers/net/depca.c.
 
   If you want to compile this as a module ( = code which can be
@@ -6365,8 +6617,8 @@
   This driver supports the DE203, DE204 and DE205 network (Ethernet)
   cards. If this is for you, say Y and read
   Documentation/networking/ewrk3.txt in the kernel source as well as
-  the Ethernet-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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),
@@ -6377,14 +6629,20 @@
 SEEQ8005 support
 CONFIG_SEEQ8005
   This is a driver for the SEEQ 8005 network (Ethernet) card. If this
-  is for you, read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  is for you, read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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
+  ewrk3.o.
 
 AT1700/1720 support
 CONFIG_AT1700
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6396,8 +6654,8 @@
 FMV-181/182/183/184 support
 CONFIG_FMV18X
   If you have a Fujitsu FMV-181/182/183/184 network (Ethernet) card,
-  say Y and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  say Y and read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   If you use an FMV-183 or FMV-184 and it is not working, you may need
   to disable Plug & Play mode of the card.
@@ -6412,8 +6670,8 @@
 CONFIG_EEXPRESS_PRO
   If you have a network (Ethernet) card of this type, say Y. Note
   however that the EtherExpress PRO/100 Ethernet card has its own
-  separate driver. Please read the Ethernet-HOWTO, available via FTP
-  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  separate driver. Please read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6424,8 +6682,8 @@
 EtherExpress support
 CONFIG_EEXPRESS
   If you have an EtherExpress16 network (Ethernet) card, say Y and
-  read the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that the Intel
+  read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Note that the Intel
   EtherExpress16 card used to be regarded as a very poor choice
   because the driver was very unreliable. We now have a new driver
   that should do better.
@@ -6439,8 +6697,8 @@
 HP PCLAN+ (27247B and 27252A) support
 CONFIG_HPLAN_PLUS
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6451,8 +6709,8 @@
 HP PCLAN (27245 and other 27xxx series) support
 CONFIG_HPLAN
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6463,8 +6721,8 @@
 HP 10/100VG PCLAN (ISA, EISA, PCI) support
 CONFIG_HP100
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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),
@@ -6475,9 +6733,9 @@
 NE2000/NE1000 support
 CONFIG_NE2000
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Many Ethernet cards
-  without a specific driver are compatible with NE2000. 
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Many Ethernet cards
+  without a specific driver are compatible with NE2000.
 
   If you have a PCI NE2000 card however, say N here and Y to "PCI
   NE2000 support", above. If you have a NE2000 card and are running on
@@ -6494,14 +6752,14 @@
 SK_G16 support
 CONFIG_SK_G16
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
 NE/2 (ne2000 MCA version) support
 CONFIG_NE2_MCA
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6511,24 +6769,24 @@
 
 SKnet MCA support
 CONFIG_SKMC
-  This are Micro Channel ethernet adapters.  You need to set CONFIG_MCA
-  to use this driver.  It's both available as an in-kernel driver and
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want). If you want to compile it as a module,
-  say M here and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If you plan to use more than
-  one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
-  available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.  Supported
-  cards are the SKnet Junior MC2 and the SKnet MC2(+).  Distinguishing
-  both cards is done automatically.  Note that using multiple boards
-  of different type hasn't been tested with this driver.
+  These are Micro Channel ethernet adapters. You need to say Y to "MCA
+  support" in order to use this driver. Supported cards are the SKnet
+  Junior MC2 and the SKnet MC2(+). The driver automatically
+  distinguishes between the two cards. Note that using multiple boards
+  of different type hasn't been tested with this driver. Say Y if you
+  have one of these ethernet adapters.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called sk_mca.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
 
 EISA, VLB, PCI and on board controllers
 CONFIG_NET_EISA
   This is another class of network cards which attach directly to the
   bus. If you have one of those, say Y and read the Ethernet-HOWTO,
-  available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  available from http://metalab.unc.edu/mdw/linux.html#howto .
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -6539,8 +6797,8 @@
 AMD PCnet32 (VLB and PCI) support
 CONFIG_PCNET32
   If you have a PCnet32 or PCnetPCI based network (Ethernet) card,
-  answer Y here and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  answer Y here and read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6551,8 +6809,8 @@
 Ansel Communications EISA 3200 support
 CONFIG_AC3200
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6563,8 +6821,8 @@
 Mylex EISA LNE390A/LNE390B support
 CONFIG_LNE390
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6575,8 +6833,8 @@
 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 via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that this driver
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Note that this driver
   will NOT WORK for NE3200 cards as they are completely different.
 
   This driver is also available as a module ( = code which can be
@@ -6588,8 +6846,8 @@
 Apricot Xen-II on board Ethernet
 CONFIG_APRICOT
   If you have a network (Ethernet) controller of this type, say Y and
-  read the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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),
@@ -6602,8 +6860,8 @@
   This is support for the DIGITAL series of PCI/EISA Ethernet cards.
   These include the DE425, DE434, DE435, DE450 and DE500 models. If
   you have a network card of this type, say Y and read the
-  Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. More specific
+  Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . More specific
   information is contained in Documentation/networking/de4x5.txt.
 
   This driver is also available as a module ( = code which can be
@@ -6620,10 +6878,9 @@
   of this type. (If your card is NOT SMC EtherPower 10/100 PCI
   (smc9332dst), you can also try the driver for "Generic DECchip"
   cards, above. However, most people with a network card of this type
-  will say Y here.) Do read the Ethernet-HOWTO, available via FTP
-  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
-  More specific information is contained in
-  Documentation/networking/tulip.txt.
+  will say Y here.) Do read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . More specific
+  information is contained in Documentation/networking/tulip.txt.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -6636,8 +6893,8 @@
   This is support for the Digi International RightSwitch series of
   PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
   models. If you have a network card of this type, say Y and read the
-  Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. More specific
+  Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . More specific
   information is contained in Documentation/networking/dgrs.txt.
 
   This driver is also available as a module ( = code which can be
@@ -6649,8 +6906,8 @@
 EtherExpress PRO/100 support
 CONFIG_EEXPRESS_PRO100
   If you have an Intel EtherExpress PRO/100 PCI network (Ethernet)
-  card, say Y and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  card, say Y and read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6661,8 +6918,8 @@
 ICL EtherTeam 16i/32 support
 CONFIG_ETH16I
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6674,8 +6931,8 @@
 CONFIG_TLAN
   If you have a PCI Ethernet network card based on the ThunderLAN chip
   which is supported by this driver, say Y and read the
-  Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   Devices currently supported by this driver are Compaq Netelligent,
   Compaq NetFlex and Olicom cards. Please read the file
@@ -6703,8 +6960,8 @@
 Racal-Interlan EISA ES3210 support
 CONFIG_ES3210
   If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -6716,8 +6973,7 @@
 CONFIG_EPIC100
   If you have an SMC EtherPower II 9432 PCI Ethernet network card
   which is based on the SMC83c170, say Y and read the Ethernet-HOWTO,
-  available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  available from http://metalab.unc.edu/mdw/linux.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).
@@ -6735,15 +6991,27 @@
   The Zenith Z-Note notebook computer has a built-in network
   (Ethernet) card, and this is the Linux driver for it. Note that the
   IBM Thinkpad 300 is compatible with the Z-Note and is also supported
-  by this driver. Read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  by this driver. Read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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://metalab.unc.edu/mdw/linux.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
   port ("pocket adapters"), commonly used with laptops. If you have
-  one of those, say Y and read the Ethernet-HOWTO, available via FTP
-  (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  one of those, say Y and read the Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   If you want to plug a network (or some other) card into the PCMCIA
   (or PC-card) slot of your laptop instead (PCMCIA is the standard for
@@ -6752,9 +7020,7 @@
   Documentation/Changes) and you can say N here.
 
   Laptop users should read the Linux Laptop home page at
-  http://www.cs.utexas.edu/users/kharker/linux-laptop/ (to browse the
-  WWW, you need to have access to a machine on the Internet that has a
-  program like lynx or netscape). 
+  http://www.cs.utexas.edu/users/kharker/linux-laptop/ .
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -6765,20 +7031,20 @@
 CONFIG_ATP
   This is a network (Ethernet) device which attaches to your parallel
   port. Read drivers/net/atp.c as well as the Ethernet-HOWTO,
-  available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO if you want to use this.
-  If you intend to use this driver, you should have said N to the
-  Parallel Printer support, because the two drivers don't like each
-  other.
+  available from http://metalab.unc.edu/mdw/linux.html#howto , if you
+  want to use this. If you intend to use this driver, you should have
+  said N to the Parallel Printer support, because the two drivers
+  don't like each other.
 
 D-Link DE600 pocket adapter support
 CONFIG_DE600
   This is a network (Ethernet) device which attaches to your parallel
   port. Read Documentation/networking/DLINK.txt as well as the
-  Ethernet-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO if you want to use this.
-  It is possible to have several devices share a single parallel port
-  and it is safe to compile the corresponding drivers into the kernel.
+  Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , if you want to use
+  this. It is possible to have several devices share a single parallel
+  port and it is safe to compile the corresponding drivers into the
+  kernel.
 
   If you want to compile this driver as a module however ( = code
   which can be inserted in and removed from the running kernel
@@ -6789,10 +7055,11 @@
 CONFIG_DE620
   This is a network (Ethernet) device which attaches to your parallel
   port. Read Documentation/networking/DLINK.txt as well as the
-  Ethernet-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO if you want to use this.
-  It is possible to have several devices share a single parallel port
-  and it is safe to compile the corresponding drivers into the kernel.
+  Ethernet-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , if you want to use
+  this. It is possible to have several devices share a single parallel
+  port and it is safe to compile the corresponding drivers into the
+  kernel.
 
   If you want to compile this driver as a module however ( = code
   which can be inserted in and removed from the running kernel
@@ -6807,16 +7074,14 @@
   connected to such a Token Ring network and want to use your Token
   Ring card under Linux, say Y here and to the driver for your
   particular card below and read the Token-Ring mini-HOWTO, available
-  via FTP (user:anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Most people can say N
-  here.
+  from http://metalab.unc.edu/mdw/linux.html#howto . Most people can
+  say N here.
 
 IBM Tropic chipset based adapter support
 CONFIG_IBMTR
   This is support for all IBM Token Ring cards that don't use DMA. If
   you have such a beast, say Y and read the Token-Ring mini-HOWTO,
-  available via FTP (user:anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  available from http://metalab.unc.edu/mdw/linux.html#howto .
 
   Warning: this driver will almost definitely fail if more than one
   active Token Ring card is present. 
@@ -6832,16 +7097,16 @@
   Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II
   Wake On Lan, and PCI 100/16/4 adapters.
 
-  If you have such an adapter, say Y and read the Token-Ring mini-HOWTO,
-  available via FTP (user:anonymous) from
-  ftp://metalab.unc/edu/pub/Linux/docs/HOWTO.
+  If you have such an adapter, say Y and read the Token-Ring
+  mini-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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 will be called olympic.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  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 linux/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
 
@@ -6852,21 +7117,28 @@
   (SK-4590), SysKonnect TR4/16 PCI (SK-4591) 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 via FTP (user: anonymous)
-  from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  read the Token-Ring mini-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   Also read the file linux/Documentation/networking/sktr.txt or check
   the Linux-SNA WWW site for the latest information at
-  http://samba.anu.edu.au/linux-sna/documents/drivers/SysKonnect/
+  http://www.linux-sna.org .
 
 Traffic Shaper (EXPERIMENTAL)
 CONFIG_SHAPER
   The traffic shaper is a virtual network device that allows you to
-  limit the rate of outgoing data flow over some other network
-  device. See Documentation/networking/shaper.txt for more
-  information. To set up and configure shaper devices, you need the
-  shapecfg program, available via FTP (user: anonymous) from
-  ftp://shadow.cabi.net/pub/Linux in the shaper package. 
+  limit the rate of outgoing data flow over some other network device.
+  The traffic that you want to slow down can then be routed through
+  these virtual devices. See Documentation/networking/shaper.txt for
+  more information.
+
+  An alternative to this traffic shaper is the experimental
+  Class-Based Queueing (CBQ) scheduling support which you get if you
+  say Y to "QoS and/or fair queueing" above.
+
+  To set up and configure shaper devices, you need the shapecfg
+  program, available from ftp://shadow.cabi.net/pub/Linux in the
+  shaper package.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -6899,16 +7171,6 @@
   under Linux, say Y here (you must also remember to enable the driver
   for your HIPPI card below). Most people will say N here.
   
-CERN HIPPI PCI adapter support
-CONFIG_CERN_HIPPI
-  Say Y here if this is your PCI HIPPI network card.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called cern_hippi.o. If you want to compile it as
-  a module, say M here and read Documentation/modules.txt. If unsure,
-  say N.
-
 Essential RoadRunner HIPPI PCI adapter support
 CONFIG_ROADRUNNER
   Say Y here if this is your PCI HIPPI network card.
@@ -6950,8 +7212,8 @@
 Support CDROM drives that are not SCSI or IDE/ATAPI
 CONFIG_CD_NO_IDESCSI
   If you have a CDROM drive that is neither SCSI nor IDE/ATAPI, say Y
-  here, otherwise N. Read the CDROM-HOWTO, available via FTP (user:
-  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  here, otherwise N. Read the CDROM-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -7009,9 +7271,6 @@
   (PhotoCDs). There is a new driver (next question) which can do
   this. If you want that one, say N here.
 
-  If the driver doesn't work out of the box, you might want to have a
-  look at drivers/cdrom/mcd.h. 
-
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
   filesystem support" below, because that's the filesystem used on
   CDROMs. 
@@ -7215,22 +7474,253 @@
   The module will be called isp16.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-Quota support
-CONFIG_QUOTA
-  If you say Y here, you will be able to set per user limits for disk
-  usage (also called disk quotas). Currently, it works only for the
-  ext2 filesystem. You need additional software in order to use quota
-  support; for details, read the Quota mini-HOWTO, available via FTP
-  (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota
-  support is only useful for multi user systems. If unsure, say N.
+Quota support
+CONFIG_QUOTA
+  If you say Y here, you will be able to set per user limits for disk
+  usage (also called disk quotas). Currently, it works only for the
+  ext2 filesystem. You need additional software in order to use quota
+  support; for details, read the Quota mini-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . Probably the quota
+  support is only useful for multi user systems. If unsure, say N.
+
+Support for USB (EXPERIMENTAL!)
+CONFIG_USB
+  Universal Serial Bus (USB) is a specification for a serial bus
+  system which offers higher speeds and more features than the
+  traditional PC serial port. The bus supplies power to peripherals
+  and allows for hot swapping. Up to 127 USB peripherals can be
+  connected to a single USB port in a tree structure; the USB port is
+  the root of the tree, the peripherals are the leafs and the inner
+  nodes are special USB devices called hubs. Many newer PC's have USB
+  ports and newer peripherals such as scanners, keyboards, mice,
+  modems and printers support the USB protocol and can be connected to
+  the PC via those ports.
+
+  Say Y here if your computer has a USB port and you want to
+  experiment with USB devices. You then need to say Y to at least one
+  of "UHCI support" or "OHCI support" below (the type of interface
+  that the USB hardware in your computer provides) and then choose
+  from among the drivers for USB peripherals.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbcore.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+UHCI (intel PIIX4 and others) support?
+CONFIG_USB_UHCI
+  The Universal Host Controller Interface is a standard by Intel for
+  accessing the USB hardware in the PC (which is also called the USB
+  host controller). If your USB host controller conforms to this
+  standard, say Y. All recent boards with Intel PCI chipsets conform
+  to this standard. If unsure, say Y.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usb-uhci.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+  
+OHCI (compaq and some others) support?
+CONFIG_USB_OHCI
+  The Open Host Controller Interface is a standard by Compaq for
+  accessing the USB PC hardware (also called USB host controller). If
+  your USB host controller conforms to this standard, say Y. The USB
+  host controllers on most non-Intel architectures and on several x86
+  compatibles with non-Intel chipsets conform to this standard.
+
+  There are currently two OHCI drivers in development. You should
+  compile at most one. The other one is "OHCI-HCD (other OHCI opt.
+  Virt. Root Hub) support?", below.
+
+  You may want to read the file drivers/usb/README.ohci.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usb-ohci.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+Enable tons of OHCI debugging output
+CONFIG_USB_OHCI_DEBUG
+  Say Y here in order to have the OHCI code generate verbose debugging
+  output.
+
+OHCI-HCD (other OHCI opt. Virt. Root Hub) support?
+CONFIG_USB_OHCI_HCD
+  This is an alternative driver for USB PC hardware (also called USB
+  host controller) which complies with Compaq's Open Host Controller
+  Interface. You may want to read the file
+  drivers/usb/README.ohci_hcd.
+
+  There are currently two OHCI drivers in development. You should
+  compile at most one. The other one is "OHCI (compaq and some others)
+  support?", above.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usb-ohci-hcd.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
+
+OHCI-HCD Virtual Root Hub
+CONFIG_USB_OHCI_VROOTHUB
+  The virtual root hub support is currently unstable, so you probably
+  want to say N unless you are a hacker. But you aren't a hacker since
+  you are reading help texts.
+
+Enable lots of ISOC debugging output
+CONFIG_USB_DEBUG_ISOC
+  Say Y here if you want to get lots of debugging output related to
+  the USB code.
+
+USB hub support
+CONFIG_USB_HUB
+  Say Y here if you want to connect several USB devices to a single
+  USB port. You will need an USB hub to do this.
+    
+  If unsure, say Y.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called hub.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+USB mouse support
+CONFIG_USB_MOUSE
+  Say Y here if you want to connect a USB mouse to your computer's USB
+  port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called mouse.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+USB HP scanner support
+CONFIG_USB_HP_SCANNER
+  Say Y here if you want to connect a USB HP scanner to your
+  computer's USB port. Please read drivers/usb/README.hp_scanner
+  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
+  a module, say M here and read Documentation/modules.txt.
+
+USB keyboard support
+CONFIG_USB_KBD
+  Say Y here if you want to connect a USB keyboard to your computer's
+  USB port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usb-keyboard.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
+
+USB audio parsing support
+CONFIG_USB_AUDIO
+  Say Y here if you want to connect audio equipment such as USB
+  speakers to your computer's USB port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called audio.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+USB Communications Device Class (ACM) support (Preliminary)
+CONFIG_USB_ACM
+  This driver allows for devices which support the Abstract Control
+  Model, including many USB-based modems, ISDN adapters, and network
+  adapters.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called acm.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+USB Printer support
+CONFIG_USB_PRINTER
+  Say Y here if you want to connect a printer to your computer's USB
+  port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called printer.o. If you want to compile it as a
+  module, say M here and read 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 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 SCSI Support
+CONFIG_USB_SCSI
+  Say Y here if you want to connect SCSI devices to your computer's
+  USB port.
+
+USB SCSI verbose debug
+CONFIG_USB_SCSI_DEBUG
+  Say Y here in order to have the USB SCSI code generate verbose
+  debugging messages.
+
+#EZUSB Firmware downloader
+#CONFIG_USB_EZUSB
+
+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.
+  
+  The chip has two modes: automatic mode and manual mode. In automatic
+  mode, it looks to the computer like a standard USB printer. Only
+  printers may be connected to the USS-720 in this mode. The generic
+  USB printer driver ("USB Printer support", above) may be used in
+  that mode, and you can say N here if you want to use the chip only
+  in this mode.
+
+  Manual mode is not limited to printers, any parallel port
+  device should work. This driver utilizes manual mode.
+  Note however that some operations are three orders of a magnitude
+  slower than on a PCI/ISA Parallel Port, so timing critical
+  applications might not work.
+
+  Say Y here if you own an USS-720 USB->Parport cable and intend to
+  connect anything other than a printer to it.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called uss720.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+  
+USB /proc filesystem entry support (Preliminary)
+CONFIG_USB_PROC
+  This reports USB drivers and devices in the /proc filesystem.
+  Entries are located in /proc/bus/usb. The entries are described in
+  the file Documentation/proc_usb_info.txt.
+
+  Note that you must say Y to "/proc filesystem support" below for
+  this to work.
 
-Acorn's ADFS filesystem support (read only) (EXPERIMENTAL)
-CONFIG_ADFS_FS
-  The Advanced Disk File System is the filesystem used on floppy and
-  hard disks by Acorn Systems.  Currently in development, as a read-
-  only driver for hard disks.  These should be the first partition
-  (eg. /dev/[sh]d?1) on each of your drives.  If unsure, say N.
+Generic 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.
+
+  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 acpi.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+  
+PIIX4 ACPI support
+CONFIG_PIIX4_ACPI
+  If you have a PIIX4 based motherboard (PCI ISA IDE Xcelerator
+  (PIIX4) is a multi-function PCI device) and you want support for
+  Advanced Configuration and Power Interface (ACPI) to support power
+  management of peripherals, say Y here.
 
 Minix fs support
 CONFIG_MINIX_FS
@@ -7269,10 +7759,9 @@
   filesystem support" below). Saying Y here will enlarge your kernel
   by about 44 kB.
 
-  The Ext2fs-Undeletion mini-HOWTO, available via FTP (user:
-  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini,
-  gives information about how to retrieve deleted files on ext2fs
-  filesystems.
+  The Ext2fs-Undeletion mini-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , gives information about
+  how to retrieve deleted files on ext2fs filesystems.
 
   To change the behavior of ext2 filesystems, you can use the tune2fs
   utility ("man tune2fs"). To modify attributes of files and
@@ -7280,12 +7769,12 @@
   
   Ext2fs partitions can be read from within DOS using the ext2tool
   command line tool package (available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2) and from
+  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
+  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.
+  http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm .
 
   If you want to compile this filesystem as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
@@ -7304,9 +7793,8 @@
   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
-  via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO), thereby enlarging your
-  kernel by about 27 kB; otherwise say N.
+  from http://metalab.unc.edu/mdw/linux.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),
@@ -7319,16 +7807,15 @@
   which allows for long filenames in unicode format (unicode is the
   new 16 bit character code, successor to ASCII, which encodes the
   characters of almost all languages of the world; see
-  http://www.unicode.org for more information; to browse the WWW, you
-  need to have access to a machine on the Internet that has a program
-  like lynx or netscape). Say Y here if you want to be able to read
-  Joliet CDROMs under Linux.
+  http://www.unicode.org for more information). Say Y here if you want
+  to be able to read Joliet CDROMs under Linux.
 
 UDF Filesystem support
 CONFIG_UDF_FS
-  This is the new filesystem used by some CDROMS and DVD drivers. 
-  Say Y if you intend to mount DVD discs or CDRWs written in packet mode,
-  or if written to by other UDF utilities, such as DirectCD.
+  This is the new filesystem 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 filesystem support is also available as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
@@ -7384,9 +7871,9 @@
   This allows you to mount MSDOS partitions of your hard drive (unless
   they are compressed; to access compressed MSDOS partitions under
   Linux, you can either use the DOS emulator DOSEMU, described in the
-  DOSEMU-HOWTO, available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, or try dmsdosfs in
-  ftp://metalab.unc.edu/pub/Linux/system/filesystems/dosfs. If you
+  DOSEMU-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , or try dmsdosfs in
+  ftp://metalab.unc.edu/pub/Linux/system/filesystems/dosfs . If you
   intend to use dosemu with a non-compressed MSDOS partition, say Y
   here) and MSDOS floppies. This means that file access becomes
   transparent, i.e. the MSDOS files look and behave just like all
@@ -7468,11 +7955,8 @@
   to use the same IRQ). 
 
   The /proc filesystem is explained in the file
-  Documentation/proc.txt, in the Kernel Hacker's Guide at
-  http://www.redhat.com:8080/HyperNews/get/khg.html on the WWW (to
-  browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape), and also on the proc(8)
-  manpage ("man 8 proc").
+  Documentation/filesystems/proc.txt and on the proc(5) manpage ("man
+  5 proc").
 
   This option will enlarge your kernel by about 67 KB. Several
   programs depend on this, so everyone should say Y here.
@@ -7487,8 +7971,8 @@
   client's hard disk. For this to work, the server must run the
   programs nfsd and mountd (but does not need to have NFS filesystem
   support enabled in its kernel). NFS is explained in the Network
-  Administrator's Guide, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/LDP, on its man page: "man
+  Administrator's Guide, available from
+  http://metalab.unc.edu/mdw/linux.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
@@ -7538,8 +8022,8 @@
   locations are given in the file Documentation/Changes in the NFS
   section.
 
-  Please read the NFS-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  Please read the NFS-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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).
@@ -7550,26 +8034,16 @@
 CONFIG_NFSD_SUN
   If you would like for the server to allow clients to access
   directories that are mount points on the local filesystem (this is
-  how nfsd behaves on Sun systems), say yes here. If unsure, say N.
+  how nfsd behaves on Sun systems), say Y here. If unsure, say N.
 
-OS/2 HPFS filesystem support (read/write)
+OS/2 HPFS filesystem support (read only)
 CONFIG_HPFS_FS
   OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
   is the filesystem used for organizing files on OS/2 hard disk
-  partitions. Say Y if you want to be able to read and write files
-  on 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. 
-  
-  Write support is new and experimental. I don't think it's so
-  "experimental" that it corrupts disks. (but you know: "There's no
-  warranty") There are many checks and filesystem is remounted read-only
-  if any inconsistency found. I use it quite long time and it works.
-
-  This driver may not be able to write to HPFS386 disks on Warp server.
-  HPFS386 on Warp client seems to work ok. If some unknown HPFS386
-  structures are deteced, they are not destroyed and filesystem is
-  remounted read-only.
+  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. 
 
   This filesystem is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -7612,7 +8086,7 @@
   Xenix, Wyse, UnixWare, Dell Unix and System V programs under Linux
   and is often needed to run commercial software that's only available
   for those systems. It's available via FTP (user: anonymous) from
-  ftp://tsx-11.mit.edu/pub/linux/BETA).
+  ftp://tsx-11.mit.edu/pub/linux/BETA ).
 
   If you only intend to mount files from some other Unix over the
   network using NFS, you don't need the System V filesystem support
@@ -7645,11 +8119,9 @@
   fs/affs/Changes. 
 
   With this driver you can also mount disk files used by Bernd
-  Schmidt's Un*X Amiga Emulator (http://www.freiburg.linux.de/~uae/;
-  to browse the WWW, you need to have access to a machine on the
-  Internet that has a program like lynx or netscape). If you want to
-  do this, you will also need to say Y or M to "Loop device support",
-  above.
+  Schmidt's Un*X Amiga Emulator (http://www.freiburg.linux.de/~uae/ ).
+  If you want to do this, you will also need to say Y or M to "Loop
+  device support", above.
 
   This filesystem is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -7709,7 +8181,7 @@
   automounter (amd), which is a pure user space daemon.
 
   To use the automounter you need the user-space tools from
-  ftp://ftp.kernel.org/pub/linux/daemons/autofs; you also want to
+  ftp://ftp.kernel.org/pub/linux/daemons/autofs ; you also want to
   answer Y to "NFS filesystem support", below.
 
   If you want to compile this as a module ( = code which can be
@@ -7720,6 +8192,26 @@
   If you are not a part of a fairly large, distributed network, you
   probably do not need an automounter, and can say N here.
 
+EFS filesystem support (experimental)
+CONFIG_EFS_FS
+  EFS is an older filesystem used for non-ISO9660 CDROMs and hard disk
+  partitions by SGI's IRIX operating system (IRIX 6.0 and newer uses
+  the XFS filesystem for hard disk partitions however).
+
+  This implementation only offers read-only access. If you don't know
+  what all this is about, it's safe to say N. For more information
+  about EFS see its home page at http://aeschi.ch.eu.org/efs/ .
+
+  If you want to compile the UFS filesystem 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 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 filesystem support
 CONFIG_UFS_FS
   BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD,
@@ -7755,29 +8247,30 @@
   Say Y here if you want to try writing to UFS partitions. This is
   experimental, so you should back up your UFS partitions beforehand.
 
-EFS filesystem support (experimental)
-CONFIG_EFS_FS
-  EFS is the filesystem used for CDROMs and filesystems by SGI's IRIX.
-  This implementation only offers read-only access. If you don't know
-  what all this is about, it's safe to say N. For more information
-  about EFS see its homepage at http://aeschi.ch.eu.org/efs/.
+Advanced partition selection
+CONFIG_PARTITION_ADVANCED
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned under an operating system running on a different
+  architecture than your Linux system.
 
-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.
+  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. If unsure, say N.
 
-EFS filesystem support (experimental)
-CONFIG_EFS_FS
-  EFS is the filesystem used for CDROMs and filesystems by SGI's IRIX.
-  This implementation only offers read-only access.  If you don't know
-  what all this is about, it's safe to say N.  For more information
-  about EFS see it's homepage at http://aeschi.ch.eu.org/efs.
+Alpha OSF partition support
+CONFIG_OSF_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned on an Alpha machine.
 
-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.
+Macintosh partition map support
+CONFIG_MAC_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned on a Macintosh.
+
+PC BIOS (MSDOS partition tables) support
+CONFIG_MSDOS_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned on an x86 PC (not necessarily by DOS).
 
 BSD disklabel (FreeBSD partition tables) support
 CONFIG_BSD_DISKLABEL
@@ -7790,11 +8283,11 @@
   filesystem support", above. If you don't know what all this is
   about, say N.
 
-SMD disklabel (Sun partition tables) support
-CONFIG_SMD_DISKLABEL
+Sun partition tables support
+CONFIG_SUN_PARTITION
   Like most systems, SunOS uses its own hard disk partition table
   format, incompatible with all others. Saying Y here allows you to
-  read these partition tables and further mount SunOS disks from
+  read these partition tables and further mount SunOS partitions from
   within Linux if you have also said Y to "UFS filesystem support",
   above. This is mainly used to carry data from a SPARC under SunOS to
   your Linux box via a removable medium like magneto-optical or ZIP
@@ -7807,9 +8300,14 @@
 CONFIG_SOLARIS_X86_PARTITION
   Like most systems, Solaris x86 uses its own hard disk partition
   table format, incompatible with all others. Saying Y here allows you
-  to read these partition tables and further mount Solaris x86 disks
-  from within Linux if you have also said Y to "UFS filesystem
-  support", above.
+  to read these partition tables and further mount Solaris x86
+  partitions from within Linux if you have also said Y to "UFS
+  filesystem support", above.
+
+SGI partition support
+CONFIG_SGI_PARTITION
+  Say Y here if you would like to be able to read the hard disk
+  partition table format used by SGI machines.
 
 ADFS filesystem support (read only) (EXPERIMENTAL)
 CONFIG_ADFS_FS
@@ -7820,7 +8318,8 @@
   and from ADFS-formatted floppy discs.
 
   The ADFS partition should be the first partition (i.e.,
-  /dev/[hs]d?1) on each of your drives.
+  /dev/[hs]d?1) on each of your drives. Please read the file
+  Documentation/filesystems/adfs.txt for further details.
 
   This code is also available as a module called adfs.o ( = code which
   can be inserted in and removed from the running kernel whenever you
@@ -7863,12 +8362,6 @@
 
   If you don't know what all this is about, say N.
 
-Macintosh partition map support
-CONFIG_MAC_PARTITION
-  Say Y here if you want your Linux system to be able to read the
-  partition tables of Macintosh hard drives, and thus use partitions
-  on those drives.
-
 SMB filesystem support (to mount Windows shares etc...)
 CONFIG_SMB_FS
   SMB (Server Message Block) is the protocol Windows for Workgroups
@@ -7878,20 +8371,17 @@
   access them just like any other Unix directory. Currently, this
   works only if the Windows machines use TCP/IP as the underlying
   transport protocol, and not NetBEUI. For details, read
-  Documentation/filesystems/smbfs.txt and the SMB-HOWTO, available via
-  FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  Documentation/filesystems/smbfs.txt and the SMB-HOWTO, available
+  from http://metalab.unc.edu/mdw/linux.html#howto .
 
   Note: if you just want your box to act as an SMB *server* and make
   files and printing services available to Windows clients (which need
   to have a TCP/IP stack), you don't need to say Y here; you can use
   the program samba (available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/system/network/samba) for that.
+  ftp://metalab.unc.edu/pub/Linux/system/network/samba ) for that.
 
   General information about how to connect Linux, Windows machines and
-  Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
-  browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape). 
+  Macs is on the WWW at http://www.eats.com/linux_mac_win.html .
 
   If you want to compile the SMB support as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
@@ -7912,9 +8402,7 @@
   *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 (to browse the
-  WWW, you need to have access to a machine on the Internet that has a
-  program like lynx or netscape).
+  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
@@ -7929,15 +8417,13 @@
   mount NetWare file server volumes and to access them just like any
   other Unix directory. For details, please read the file
   Documentation/filesystems/ncpfs.txt in the kernel source and the
-  IPX-HOWTO on ftp://metalab.unc.edu/pub/Linux/docs/howto.
+  IPX-HOWTO from http://metalab.unc.edu/mdw/linux.html#howto .
 
   You do not have to say Y here if you want your Linux box to act as a
   file *server* for Novell NetWare clients.
 
   General information about how to connect Linux, Windows machines and
-  Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
-  browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape). 
+  Macs is on the WWW at http://www.eats.com/linux_mac_win.html .
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -8300,7 +8786,7 @@
   letters that were missing in Latin 4 to cover the entire Nordic
   area.
 
-nls iso8859-14
+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 filesystem family or from JOLIET CDROMs
@@ -8372,9 +8858,8 @@
   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 via
-  FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.)
+  lilo procedure is also explained in the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .)
 
   If unsure, say Y.
 
@@ -8416,9 +8901,9 @@
   BTW1: If you have a mouseman serial mouse which is not recognized by
   the X window system, try running gpm first. 
   
-  BTW2: If you intend to connect a so-called Winmodem to your
-  machine's serial port, forget it. These modems are crippled and
-  require proprietary drivers which are only available under Windows.
+  BTW2: If you intend to use a software modem (also called Winmodem)
+  under Linux, forget it. These modems are crippled and require
+  proprietary drivers which are only available under Windows.
 
   Most people will say Y or M here, so that they can use serial mice,
   modems and similar devices connecting to the standard serial ports.
@@ -8437,8 +8922,8 @@
   "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 via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.) 
+  SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .)
 
   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
@@ -8501,6 +8986,21 @@
   Also it's possible to say M here and compile this driver as kernel
   loadable module; the module will be called riscom8.o.
 
+Computone IntelliPort Plus serial support
+CONFIG_COMPUTONE
+  This driver supports the entire family of Intelliport II/Plus
+  controllers with the exception of the MicroChannel controllers. 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
+  card like that, say Y here and read Documentation/computone.txt.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. You will get two
+  modules called ip2.o and ip2main.o.
+
 Specialix IO8+ card support
 CONFIG_SPECIALIX
   This is a driver for the Specialix IO8+ multiport card (both the
@@ -8594,15 +9094,23 @@
 
 Synchronous HDLC line discipline support
 CONFIG_N_HDLC
-  Allows synchronous HDLC communications with
-  tty device drivers that support synchronous
-  HDLC such as the Microgate SyncLink adapter.
+  Allows synchronous HDLC communications with tty device drivers that
+  support synchronous HDLC such as the Microgate SyncLink adapter.
 
   This driver can only be built as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called n_hdlc.o. If you want to do that, say M
   here.
 
+Specialix SX (and SI) card support
+CONFIG_SX
+  This is a driver for the SX and SI multiport serial cards.
+  Please read the file Documentation/sx.txt for details.
+
+  This driver can only be built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called sx.o. If you want to do that, say M here.
+
 Hayes ESP serial port support
 CONFIG_ESPSERIAL
   This is a driver which supports Hayes ESP serial ports. Both single
@@ -8665,25 +9173,24 @@
   If you intend to attach a printer to the parallel port of your Linux
   box (as opposed to using a serial printer; if the connector at the
   printer has 9 or 25 holes ["female"], then it's serial), say Y. Also
-  read the Printing-HOWTO, available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  read the Printing-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   It is possible to share one parallel port among several devices
   (e.g. printer and ZIP drive) and it is safe to compile the
   corresponding drivers into the kernel. If you want to compile this
   driver as a module however ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt and Documentation/parport.txt. The
+  read Documentation/modules.txt and Documentation/parport.txt. The 
   module will be called lp.o. 
 
   If you have several parallel ports, you can specify which ports to
   use with the "lp" kernel command line option. (Try "man bootparam"
-  or see the documentation of your boot loader (lilo or loadlin)
-  about how to pass options to the kernel at boot time. The lilo
-  procedure is also explained in the SCSI-HOWTO, available via FTP
-  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.)
-  The syntax of the "lp" command line option can be found in
-  drivers/char/lp.c.
+  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://metalab.unc.edu/mdw/linux.html#howto .) 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.
@@ -8701,15 +9208,38 @@
 
   If unsure, say N.
 
-Mouse Support (not serial mice)
-CONFIG_MOUSE
-  This is for machines with a bus mouse or a PS/2 mouse as opposed to
-  a serial mouse. Most people have a regular serial MouseSystem or
+Bus Mouse Support
+CONFIG_BUSMOUSE
+  Say Y here if your machine has a bus mouse as opposed to a serial
+  mouse. Most people have a regular serial MouseSystem or
   Microsoft mouse (made by Logitech) that plugs into a COM port
   (rectangular with 9 or 25 pins). These people say N here. If you
-  have something else, read the Busmouse-HOWTO, available via FTP
-  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and
-  say Y here.
+  have something else, read the Busmouse-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto , and say Y here.
+
+  If you have a laptop, you either have to check the documentation or
+  experiment a bit to find out whether the trackball is a serial mouse
+  or not; it's best to say Y here for you. 
+
+  This is the generic bus mouse driver code. If you have a bus mouse,
+  you will have to say Y here and also to the specific driver for your
+  mouse below.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called busmouse.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+Mouse Support (not serial and bus mice)
+CONFIG_MOUSE
+  This is for machines with a mouse which is neither a serial nor a
+  bus mouse. Examples are PS/2 mice (such as the track balls on some
+  laptops) and some digitizer pads. Most people have a regular serial
+  MouseSystem or Microsoft mouse (made by Logitech) that plugs into a
+  COM port (rectangular with 9 or 25 pins). These people say N here.
+  If you have something else, read the Busmouse-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto . This HOWTO contains
+  information about all non-serial mice, not just bus mice.
 
   If you have a laptop, you either have to check the documentation or
   experiment a bit to find out whether the trackball is a serial mouse
@@ -8720,13 +9250,12 @@
   the questions about non-serial mice. If unsure, say Y.
 
 Logitech busmouse support
-CONFIG_BUSMOUSE
+CONFIG_LOGIBUSMOUSE
   Logitech mouse connected to a proprietary interface card. It's
   generally a round connector with 9 pins. Note that the newer mice
   made by Logitech don't use the Logitech protocol anymore; for those,
-  you don't need this option. You want to read the Busmouse-HOWTO,
-  available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  you don't need this option. You want to read the Busmouse-HOWTO ,
+  available from http://metalab.unc.edu/mdw/linux.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),
@@ -8745,29 +9274,27 @@
   particular, the C&T 82C710 mouse on TI Travelmates is a PS/2 mouse.
 
   Although PS/2 mice are not technically bus mice, they are explained
-  in detail in the Busmouse-HOWTO, available via FTP (user: anonymous)
-  in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
+  in detail in the Busmouse-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   When using a PS/2 mouse, you can get problems if you want to use the
   mouse both on the Linux console and under X. Using the "-R" option
   of the Linux mouse managing program gpm (available from
-  ftp://metalab.unc.edu/pub/Linux/system/Daemons) solves this
-  problem, or you can get the "mconv" utility also from metalab.
+  ftp://metalab.unc.edu/pub/Linux/system/mouse ) solves this
+  problem, or you can get the "mconv2" utility from the same location.
 
 C&T 82C710 mouse port support (as on TI Travelmate)
 CONFIG_82C710_MOUSE
   This is a certain kind of PS/2 mouse used on the TI Travelmate. If
   you are unsure, try first to say N here and come back if the mouse
-  doesn't work. Read the Busmouse-HOWTO, available via FTP (user:
-  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  doesn't work. Read the Busmouse-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
 PC110 digitizer pad support
 CONFIG_PC110_PAD
   This drives the digitizer pad on the IBM PC110 palmtop (see
-  http://toy.cabi.net; to browse the WWW, you need to have access to a
-  machine on the Internet that has a program like lynx or
-  netscape). It can turn the digitizer pad into a PS/2 mouse emulation
-  with tap gestures or into an absolute pad. 
+  http://toy.cabi.net ). It can turn the digitizer pad into a PS/2
+  mouse emulation with tap gestures or into an absolute pad.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -8778,8 +9305,8 @@
 CONFIG_MS_BUSMOUSE
   These animals (also called Inport mice) are connected to an
   expansion board using a round connector with 9 pins. If this is what
-  you have, say Y and read the Busmouse-HOWTO, available via FTP
-  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  you have, say Y and read the Busmouse-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   If you are unsure, say N and read the HOWTO nevertheless: it will
   tell you what you have. Also be aware that several vendors talk
@@ -8791,12 +9318,25 @@
   say M here and read Documentation/modules.txt. The module will be
   called msbusmouse.o. 
 
+Apple Desktop Bus mouse support
+CONFIG_ADBMOUSE
+  Say Y here if you have this type of bus mouse (4 pin connector) as
+  is common on Macintoshes. You may want to read the Busmouse-HOWTO,
+  available from http://metalab.unc.edu/mdw/linux.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. The module will be
+  called adbmouse.o.
+
 ATIXL busmouse support
 CONFIG_ATIXL_BUSMOUSE
   This is a rare type of busmouse that is connected to the back of an
-  ATI video card. Note that most ATI mice are actually Microsoft
-  busmice. Read the Busmouse-HOWTO, available via FTP (user:
-  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  ATI video card. Say Y if you have one of those. Note however that
+  most mice by ATI are actually Microsoft busmice; you should say Y to
+  "Microsoft busmouse support" above if you have one of those. Read
+  the Busmouse-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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),
@@ -8806,11 +9346,6 @@
   If you are unsure, say N and read the HOWTO nevertheless: it will
   tell you what you have.
 
-Support for PowerMac ADB mouse
-CONFIG_ADBMOUSE
-  If you have an ADB mouse (4 pin connector) as is common on
-  Macintoshes, say Y here.
-
 QIC-02 tape support
 CONFIG_QIC02_TAPE
   If you have a non-SCSI tape drive like that, say Y. Or, if you want
@@ -8860,13 +9395,12 @@
   Note that the Ftape-HOWTO is out of date (sorry) and documents the
   older version 2.08 of this software but still contains useful
   information. There is a web page with more recent documentation at
-  http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/ . This page
+  http://www.math1.rwth-aachen.de/~heine/ftape/ . This page
   always contains the latest release of the ftape driver and useful
   information (backup software, ftape related patches and
-  documentation, FAQ). (To browse the WWW, you need to have access to
-  a machine on the Internet that has a program like lynx or netscape.)
-  Note that the file system interface has changed quite a bit compared
-  to previous versions of ftape. Please read Documentation/ftape.txt.
+  documentation, FAQ). Note that the file system interface has changed
+  quite a bit compared to previous versions of ftape. Please read
+  Documentation/ftape.txt.
 
 The file system interface for ftape
 CONFIG_ZFTAPE
@@ -8897,8 +9431,7 @@
   most important changes in the file system interface compared to
   previous versions of ftape. The ftape home page
   http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/ contains
-  further information (to browse the WWW, you need to have access to a
-  machine on the Internet that has a program like lynx or netscape).
+  further information.
 
   IMPORTANT NOTE: zftape can read archives created by previous
   versions of ftape and provide file mark support (i.e. fast skipping
@@ -9120,6 +9653,17 @@
   speed. If unsure, leave this disabled, i.e. leave it at 2000
   bits/sec.
 
+Direct Rendering Manager (XFree86 DRI support)
+CONFIG_DRM
+  Kernel-level support for the Direct Rendering Infrastructure (DRI)
+  introduced in XFree86 4.x. These modules provide support for
+  synchronization, security, and DMA transfers. Select the module that
+  provides support for your graphics card.
+
+3dlabs GMX 2000 Direct Rendering Driver (XFree86 DRI support)
+CONFIG_DRM_GAMMA
+  Choose M here if you have a 3dlabs GMX 2000 graphics card.
+
 MTRR control and configuration
 CONFIG_MTRR
   On Intel P6 family processors (Pentium Pro, Pentium II and later)
@@ -9136,11 +9680,13 @@
 
   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.
+  these, the ARRs are used to emulate the MTRRs, which means that it
+  makes sense to say Y here for these processors as well.
 
   The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
-  MTRRs. These are supported.
-  
+  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.
 
@@ -9161,13 +9707,13 @@
 
 Zilog serial support
 CONFIG_SUN_ZS
-  If you are asked this question, something is wrong with config scripts.
-  Zilog serial driver is always enabled in sparc architecture.
+  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
-  manufactured by RC Systems (http://www.rcsys.com/).  It is also
+  manufactured by RC Systems (http://www.rcsys.com/ ).  It is also
   called the `internal DoubleTalk'.  If you want to compile this as a
   module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
@@ -9175,7 +9721,7 @@
 
 Siemens R3964 serial protocol support
 CONFIG_R3964
-  This driver allows syncronous communication with devices using the
+  This driver allows synchronous communication with devices using the
   Siemens R3964 packet protocol. Unless you are dealing with special
   hardware like PLCs, you are unlikely to need this.
 
@@ -9188,12 +9734,11 @@
 
 Applicom intelligent fieldbus card support
 CONFIG_APPLICOM
-  This driver provides the kernel-side support for the intelligent 
+  This driver provides the kernel-side support for the intelligent
   fieldbus cards made by Applicom International. More information
   about these cards can be found on the WWW at the address
-  http://www.applicom-int.com/ (to browse the WWW, you need to have
-  access to a machine on the Internet that has a program like lynx
-  or netscape), or by email from David Woodhouse <dwmw2@mvhi.com>.
+  http://www.applicom-int.com/ , or by email from David Woodhouse
+  <dwmw2@mvhi.com>.
 
   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
@@ -9212,8 +9757,8 @@
   receive notification of APM "events" (e.g., battery status change).
 
   Supporting software is available; for more information, read the
-  Battery Powered Linux mini-HOWTO, available via FTP (user:
-  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini.
+  Battery Powered Linux mini-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .
 
   This driver does not spin down disk drives (see the hdparm(8)
   manpage ("man 8 hdparm") for that), and it doesn't turn off
@@ -9228,9 +9773,7 @@
 
   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/ (to browse the
-  WWW, you need to have access to a machine on the Internet that has a
-  program like lynx or netscape). 
+  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
@@ -9257,6 +9800,11 @@
    11) exchange RAM chips 
    12) exchange the motherboard.
 
+  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. The module will be called apm.o.
+
 Ignore USER SUSPEND
 CONFIG_APM_IGNORE_USER_SUSPEND
   This option will ignore USER SUSPEND requests. On machines with a
@@ -9307,11 +9855,10 @@
   is halted. You will need software (e.g., a suitable version of the
   halt(8) command ("man 8 halt")) to cause the computer to power down.
   Recent versions of the sysvinit package available from
-  ftp://metalab.unc.edu/pub/Linux/system/daemons/init/ (user:
-  anonymous) contain support for this ("halt -p" shuts down Linux and
-  powers off the computer, if executed from runlevel 0). As with the
-  other APM options, this option may not work reliably with some APM
-  BIOS implementations.
+  ftp://metalab.unc.edu/pub/Linux/system/daemons/init/ contain support
+  for this ("halt -p" shuts down Linux and powers off the computer, if
+  executed from runlevel 0). As with the other APM options, this
+  option may not work reliably with some APM BIOS implementations.
 
 Ignore multiple suspend/standby events
 CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
@@ -9367,7 +9914,7 @@
 
   The watchdog is usually used together with the watchdog daemon 
   which is available via FTP (user: anonymous) from
-  ftp://tsx-11.mit.edu/pub/linux/sources/sbin/. This daemon can also
+  ftp://tsx-11.mit.edu/pub/linux/sources/sbin/ . This daemon can also
   monitor NFS connections and can reboot the machine when the process
   table is full.
 
@@ -9425,8 +9972,7 @@
   and if it does, it reboots your computer after a certain amount of
   time. This driver is like the WDT501 driver but for different
   hardware. Please read Documentation/pcwd-watchdog.txt. The PC
-  watchdog cards can be ordered from http://www.berkprod.com. Some
-  example rc.local files are available from ftp://ftp.bitgate.com. 
+  watchdog cards can be ordered from http://www.berkprod.com . 
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -9500,17 +10046,6 @@
   The module will be called nvram.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
-  this option.  The driver can handle 1, 2, or 3 port cards.
-  If unsure, say N
-
-The Serial Port Dual Serial Port
-CONFIG_DUALSP_SERIAL
-  If you have the Serial Port's dual serial card for an Acorn system,
-  say Y to this option.  If unsure, say N
-
 Joystick support
 CONFIG_JOYSTICK
   If you have a joystick, you can say Y here to enable generic
@@ -9616,32 +10151,37 @@
 
 NetWinder Button
 CONFIG_NWBUTTON
-  If you enable this driver and create a character device node
-  /dev/nwbutton with major and minor numbers 10 and 158 ("man mknod"),
-  then every time the orange button is pressed a number of times, the
-  number of times the button was pressed will be written to that device.
-  This is most useful for applications, as yet unwritten, which perform
-  actions based on how many times the button is pressed in a row.
-  Do not hold the button down for too long, as the driver does not alter
-  the behaviour of the hardware reset circuitry attached to the button;
-  it will still execute a hard reset if the button is held down for
-  longer than approximately five seconds.
+  If you say Y here and create a character device node /dev/nwbutton
+  with major and minor numbers 10 and 158 ("man mknod"), then every
+  time the orange button is pressed a number of times, the number of
+  times the button was pressed will be written to that device.
+
+  This is most useful for applications, as yet unwritten, which
+  perform actions based on how many times the button is pressed in a
+  row.
+
+  Do not hold the button down for too long, as the driver does not
+  alter the behaviour of the hardware reset circuitry attached to the
+  button; it will still execute a hard reset if the button is held
+  down for longer than approximately five seconds.
+
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt. The module will be called nwbutton.o.
+
   Most people will answer Y to this question and "Reboot Using Button"
   below to be able to initiate a system shutdown from the button.
 
 Reboot Using Button
 CONFIG_NWBUTTON_REBOOT
-  If you enable this option, then you will be able to initiate a system
+  If you say Y here, then you will be able to initiate a system
   shutdown and reboot by pressing the orange button a number of times.
-  The number of presses to initiate the shutdown is two by default, but
-  this can be altered by modifying the value of NUM_PRESSES_REBOOT in
-  nwbutton.h and recompiling the driver or, if you compile the driver as
-  a module, you can specify the number of presses at load time with
-  "insmod button reboot_count=<something>".
+  The number of presses to initiate the shutdown is two by default,
+  but this can be altered by modifying the value of NUM_PRESSES_REBOOT
+  in nwbutton.h and recompiling the driver or, if you compile the
+  driver as a module, you can specify the number of presses at load
+  time with "insmod button reboot_count=<something>".
 
 Sound card support
 CONFIG_SOUND
@@ -9650,29 +10190,27 @@
   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 via FTP (user:
-  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. General
-  information about the modular sound system is contained in the files
+  You want to read the Sound-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.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.
 
   If you have a PnP sound card and you want to configure it at boot
   time using the ISA PnP tools (read
-  http://www.roestock.demon.co.uk/isapnptools/ (to browse the WWW, you
-  need to have access to a machine on the Internet that has a program
-  like lynx or netscape)), then you need to compile the sound card
-  support as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want) and load that module
-  after the PnP configuration is finished. To do this, say M here and
-  read Documentation/modules.txt as well as
+  http://www.roestock.demon.co.uk/isapnptools/ ), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished. To do
+  this, say M here and read Documentation/modules.txt as well as
   Documentation/sound/README.modules; the module will be called
   soundcore.o.
 
   I'm told that even without a sound card, you can make your computer
   say more than an occasional beep, by programming the PC speaker.
   Kernel patches and supporting utilities to do that are in the pcsp
-  package, available at http://www.imladris.demon.co.uk/pcsp/.
+  package, available at http://www.imladris.demon.co.uk/pcsp/ .
 
 OSS sound modules
 CONFIG_SOUND_OSS
@@ -9858,6 +10396,12 @@
   have their own MSS support and saying Y to this option will cause a
   conflict.
 
+SGI Visual Workstation on-board audio
+CONFIG_SOUND_VWSND
+  Say Y or M if you have an SGI Visual Workstation and you want to
+  be able to use its on-board audio.  Read Documentation/sound/visws
+  for more info on this driver's capabilities.
+
 Ensoniq Soundscape support
 CONFIG_SOUND_SSCAPE
   Answer Y if you have a sound card based on the Ensoniq SoundScape
@@ -10058,8 +10602,8 @@
   Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or
   similar sound card. See Documentation/sound/README.awe,
   Documentation/sound/AWE32 and the Soundblaster-AWE mini-HOWTO,
-  available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini for more info.
+  available from http://metalab.unc.edu/mdw/linux.html#howto for more
+  info.
 
 Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600)
 CONFIG_AEDSP16
@@ -10101,9 +10645,9 @@
 
 Audio Excel DSP 16 DMA
 CONFIG_AEDSP16_SB_DMA
-  This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 or 3.
-  If you compiled aedsp16.o as a module you can specify this parameter
-  as 'dma=NN'.
+  This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 or
+  3. If you compiled aedsp16.o as a module you can specify this
+  parameter as 'dma=NN'.
 
 Audio Excel DSP 16 (MSS emulation)
 CONFIG_AEDSP16_MSS
@@ -10157,12 +10701,6 @@
   you compiled aedsp16.o as a module you can specify this parameter as
   'mpu_irq=NN'.
 
-SGI Visual Workstation on-board audio
-CONFIG_SOUND_VWSND
-  Say Y or M if you have an SGI Visual Workstation and you want to
-  be able to use its on-board audio.  Read Documentation/sound/visws
-  for more info on this driver's capabilities.
-
 Ensoniq ES1370 based PCI sound cards
 CONFIG_SOUND_ES1370
   Say Y or M if you have a PCI sound card utilizing the Ensoniq
@@ -10174,10 +10712,6 @@
   This driver differs slightly from OSS/Free, so PLEASE READ
   Documentation/sound/es1370.
 
-Joystick support at boot time
-CONFIG_SOUND_ES1370_JOYPORT_BOOT
-  Say Y here to use the joystick port of your sound card.
-
 Ensoniq ES1371 based PCI sound cards
 CONFIG_SOUND_ES1371
   Say Y or M if you have a PCI sound card utilizing the Ensoniq
@@ -10188,19 +10722,6 @@
   models are either ES1370 or ES1371 based. This driver differs
   slightly from OSS/Free, so PLEASE READ Documentation/sound/es1371.
 
-Joystick support at boot time
-CONFIG_SOUND_ES1371_JOYPORT_BOOT
-  Say Y here to use the joystick port of your sound card.
-
-Gameport I/O-range selection
-CONFIG_SOUND_ES1371_GAMEPORT
-  Select the I/O-range of the gameport on a ES1371 based sound card.
-  The card uses 8 ioports and the gameport is available at all eight
-  ioports. Legal hexadecimal values are 200, 208, 210 and 218.
-  The joystick driver will by default use 0x201. 
-  Leave the default 200 unless you have a joystick not attached
-  to your sound card.
-
 ESS Solo1 based PCI sound cards (eg. SC1938)
 CONFIG_SOUND_ESSSOLO1
   Say Y or M if you have a PCI sound card utilizing the ESS Technology
@@ -10263,9 +10784,7 @@
   conversations while downloading stuff. It only works if your
   computer is equipped with an ISDN card and both you and your service
   provider purchased an ISDN line from the phone company. For details,
-  read http://alumni.caltech.edu/~dank/isdn/ on the WWW. (To browse
-  the WWW, you need to have access to a machine on the Internet that
-  has a program like lynx or netscape.)
+  read http://alumni.caltech.edu/~dank/isdn/ on the WWW.
 
   This driver allows you to use an ISDN-card for networking
   connections and as dialin/out device. The isdn-tty's have a built in
@@ -10325,15 +10844,18 @@
 CONFIG_ISDN_DIVERSION
   This option allows you to use some supplementary diversion
   services in conjunction with the HiSax driver on an EURO/DSS1
-  line. Supported options are CD (call deflection), CFU (Call 
-  forward unconditional), CFB (Call forward when busy) and CFNR 
-  (call forward not reachable).
-  Additionally the actual CFU, CFB and CFNR state may be 
-  interrogated. The use of CFU, CFB, CFNR and interrogation may
-  be limited to some countries. The keypad protocol is still not
-  implemented.
-  CD should work in all countries if this service has been sub-
-  scribed.
+  line. 
+
+  Supported options are CD (call deflection), CFU (Call forward
+  unconditional), CFB (Call forward when busy) and CFNR (call forward
+  not reachable). Additionally the actual CFU, CFB and CFNR state may
+  be interrogated.
+
+  The use of CFU, CFB, CFNR and interrogation may be limited to some
+  countries. The keypad protocol is still not implemented. CD should
+  work in all countries if the service has been subscribed to.
+
+  Please read the file Documentation/isdn/README.diversion.
 
 ICN 2B and 4B support
 CONFIG_ISDN_DRV_ICN
@@ -10557,32 +11079,30 @@
   can be inserted in and removed from the running kernel whenever you
   want, details in Documentation/modules.txt); the module will be
   called sc.o. See Documentation/isdn/README.sc and
-  http://www.spellcast.com for more information (to browse the WWW,
-  you need to have access to a machine on the Internet that has a
-  program like lynx or netscape).
+  http://www.spellcast.com for more information.
 
 Eicon.Diehl active card support
 CONFIG_ISDN_DRV_EICON
   Say Y here if you have an Eicon active ISDN card. In order to use
   this card, additional firmware is necessary, which has to be loaded
-  into the card using the eiconctrl utility which is part of the latest
-  isdn4k-utils package. Please read the file
+  into the card using the eiconctrl utility which is part of the
+  latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
   
 Eicon old-type card support
 CONFIG_ISDN_DRV_EICON_ISA
-  Say Y here if you have an old-type Eicon active ISDN card. In order to
-  use this card, additional firmware is necessary, which has to be loaded
-  into the card using the eiconctrl utility which is part of the latest
-  isdn4k-utils package. Please read the file
+  Say Y here if you have an old-type Eicon active ISDN card. In order
+  to use this card, additional firmware is necessary, which has to be
+  loaded into the card using the eiconctrl utility which is part of
+  the latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
 
 Support AT-Fax Class 2 commands
 CONFIG_ISDN_TTY_FAX
   If you say Y here, the modem-emulator will support a subset of the
   Fax Class 2 commands. Using a getty with fax-support
-  (mgetty+sendfax, hylafax), you will be able to use your Linux box 
-  as an ISDN-fax-machine. This must be supported by the lowlevel driver
+  (mgetty+sendfax, hylafax), you will be able to use your Linux box as
+  an ISDN-fax-machine. This must be supported by the lowlevel driver
   also. See Documentation/isdn/README.fax for more information.
 
 AVM-B1 with CAPI2.0 support
@@ -10590,12 +11110,10 @@
   This enables support for the AVM B1 ISDN networking cards. In
   addition, a CAPI (Common ISDN Application Programming Interface, a
   standard making it easy for programs to access ISDN hardware, see
-  http://www.capi.org/; to browse the WWW, you need to have access to
-  a machine on the Internet that has a program like lynx or netscape)
-  interface for this card is provided. In order to use this card,
-  additional firmware is necessary, which has to be downloaded into
-  the card using a utility which is distributed separately. Please
-  read the file Documentation/isdn/README.avmb1. 
+  http://www.capi.org/ ) interface for this card is provided. In order
+  to use this card, additional firmware is necessary, which has to be
+  downloaded into the card using a utility which is distributed
+  separately. Please read the file Documentation/isdn/README.avmb1.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -10620,9 +11138,8 @@
 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 (to browse the
-  WWW, you need to have access to a machine on the Internet that has a
-  program like lynx or netscape) or mail to hackers@cafe.anu.edu.au
+  machine see http://cap.anu.edu.au/cap/projects/linux or mail to
+  hackers@cafe.anu.edu.au
 
 Support for Sun4 architecture
 CONFIG_SUN4
@@ -10648,12 +11165,11 @@
 Mostek real time clock support
 CONFIG_SUN_MOSTEK_RTC
   The Mostek RTC chip is used on all knows Sun computers except
-  some JavaStation-s. For a JavaStation you need to say Y both here
-  and to CONFIG_RTC.
+  some JavaStations. For a JavaStation you need to say Y both here
+  and to "Enhanced Real Time Clock Support".
 
   Say Y here unless you are building a special purpose kernel.
 
-#
 #Siemens SAB82532 serial support
 #CONFIG_SAB82532
 ###
@@ -10700,13 +11216,13 @@
 
 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 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
+  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
@@ -10793,9 +11309,10 @@
   Note that even if you say N here, you can still use your expansion
   cards. If in doubt, say Y.
 
+Amiga 1200/600 PCMCIA support
 CONFIG_AMIGA_PCMCIA
-  Include support in the kernel for pcmcia on Amiga 1200 and Amiga 600.
-  If you intend to use pcmcia cards say Y; otherwise say N.
+  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
@@ -11177,14 +11694,6 @@
   HP300 machines. If you are using such a system you almost certainly
   want this.
 
-MSDOS partition support
-CONFIG_MSDOS_PARTITION
-  This option enables support for using hard disks that were
-  partitioned on an MS-DOS system. This may be useful if you are
-  sharing a hard disk between i386 and m68k Linux boxes, for example.
-  Say Y if you need this feature; users who are only using their
-  system-native partitioning scheme can say N here.
-
 Processor Type
 CONFIG_6xx
   There are two types of PowerPC chips supported. The more common
@@ -11267,7 +11776,7 @@
   Support for audio/video capture and overlay devices and FM radio
   cards. The exact capabilities of each device vary. User tools for
   this are available from
-  ftp://ftp.uk.linux.org/pub/linux/video4linux.
+  ftp://ftp.uk.linux.org/pub/linux/video4linux .
 
   If you are interested in writing a driver for such an audio/video
   device or user software interacting with such a driver, please read
@@ -11278,17 +11787,6 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-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.
-
-3dlabs GMX 2000 Direct Rendering Driver (XFree86 DRI support)
-CONFIG_DRM_GAMMA
-  Choose M here if you have a 3dlabs GMX 2000 graphics card.
-
 AIMSlab RadioTrack (aka RadioReveal) support
 CONFIG_RADIO_RTRACK
   Choose Y here if you have one of these FM radio cards, and then fill
@@ -11298,13 +11796,16 @@
   and are not supported by this driver. For these cards, use the
   RadioTrack II driver below.
 
+  If you have a GemTeks combined (PnP) sound- and radio card you must
+  use this driver as a module and setup the card with isapnptools. You
+  must also pass the module a suitable io parameter, 0x248 has been
+  reported to be used by these cards.
+
   In order to control your radio card, you will need to use programs
-  that are compatible with the Video for Linux API. Information on 
+  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. More information is contained in the
-  file Documentation/video4linux/radiotrack.txt.
+  http://roadrunner.swansea.uk.linux.org/v4l.shtml . More information
+  is contained in the file Documentation/video4linux/radiotrack.txt.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -11321,17 +11822,10 @@
   Choose Y here if you have this FM radio card, and then fill in the 
   port address below.
 
-  If you have GemTeks combined (PnP) sound- and radio card you must use
-  this driver as a module and setup the card with isapnptools. You must
-  also pass the module a suitable io parameter, 0x248 has been reported
-  to be used by these cards.
-
   In order to control your radio card, you will need to use programs
   that are compatible with the Video for Linux API. Information on 
   this API and pointers to "v4l" programs may be found on the WWW at
-  http://roadrunner.swansea.uk.linux.org/v4l.shtml; 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),
@@ -11351,9 +11845,7 @@
   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),
@@ -11366,6 +11858,28 @@
   haven't changed the setting of jumper JP3 on the card. Removing the
   jumper sets the card to 0x358.
 
+ADS Cadet AM/FM Radio Tuner Card
+CONFIG_RADIO_CADET
+  Choose Y here if you have one of these AM/FM radio cards, and then
+  fill in the port address below.
+  
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video for Linux API. Information on 
+  this API and pointers to "v4l" programs may be found on the WWW at
+  http://roadrunner.swansea.uk.linux.org/v4l.shtml .
+
+  Further documentation on this driver can be found on the WWW at
+  http://linux.blackhawke.net/cadet.html . 
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read 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
@@ -11374,9 +11888,7 @@
   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),
@@ -11395,9 +11907,7 @@
   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),
@@ -11433,9 +11943,7 @@
   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),
@@ -11446,21 +11954,16 @@
 CONFIG_RADIO_ZOLTRIX_PORT
   Enter the I/O port of your Zoltrix radio card.
 
-ADS Cadet AM/FM Tuner
-CONFIG_RADIO_CADET
-  Say Y here if this is your AM/FM radio card.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video for Linux API. Information on 
-  this API and pointers to "v4l" programs may be found on the WWW at
-  http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
-  you need to have access to a machine on the Internet that has a 
-  program like lynx or netscape.
+IIC on parallel port
+CONFIG_I2C_PARPORT
+  I2C is a simple serial bus system used in many micro controller
+  applications. Saying Y here will allow you to use your parallel port
+  as an I2C interface.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt. The module will be
-  called radio-cadet.o
+  called i2c-parport.o.
 
 Miro PCM20 Radio
 CONFIG_RADIO_MIROPCM20
@@ -11471,9 +11974,7 @@
   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),
@@ -11488,9 +11989,7 @@
   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),
@@ -11516,11 +12015,11 @@
   Choose Y here if you have this FM radio card, and then fill in the
   port address below. (TODO)
 
-  Note: This driver is in its early stages. Right now volume and frequency
-  control and muting works at least for me, but unfortunately i have not
-  found anybody who wants to use this card with linux. So if it is this
-  what YOU are trying to do right now, PLEASE DROP ME A NOTE!!
-  Rolf Offermanns (rolf@offermanns.de)
+  Note: This driver is in its early stages. Right now volume and
+  frequency control and muting works at least for me, but
+  unfortunately i have not found anybody who wants to use this card
+  with linux. So if it is this what YOU are trying to do right now,
+  PLEASE DROP ME A NOTE!! Rolf Offermanns (rolf@offermanns.de)
   
   In order to control your radio card, you will need to use programs
   that are compatible with the Video for Linux API. Information on
@@ -11529,12 +12028,16 @@
   you need to have access to a machine on the Internet that has a
   program like lynx or netscape.
 
-
   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.
-  
+
+# Zoran ZR36057/36060 support
+# CONFIG_VIDEO_ZORAN
+
+# Include support for Iomega Buz
+# CONFIG_VIDEO_BUZ
 
 BT848 Video For Linux
 CONFIG_VIDEO_BT848
@@ -11586,10 +12089,10 @@
 CONFIG_BLK_CPQ_DA
    This is the driver for Compaq Smart Array controllers.  
    Everyone using these boards should say Y here.  
-   See "linux/Documentation/cpqarray.txt" for the current list of 
+   See the file Documentation/cpqarray.txt for the current list of 
    boards supported by this driver, and for further information 
    on the use of this driver. 
- 
+
 #
 # ARM options
 #
@@ -11615,24 +12118,36 @@
 
 Include support for Intel EBSA285
 CONFIG_ARCH_EBSA285
-  Say Y here if you intend to run this kernel on an EBSA-285 evaluation
   board.
 
 Include support for the NetWinder
 CONFIG_ARCH_NETWINDER
   Say Y here if you intend to run this kernel on the NetWinder.
 
+Maximum Physical Memory
+CONFIG_1GB
+  Linux can use up to 2 Gigabytes (= 2^31 bytes) of physical memory.
+  If you are compiling a kernel which will never run on a machine with
+  more than 1 Gigabyte, answer "1GB" here. Otherwise, say "2GB".
+
+  The actual amount of physical memory should be specified using a
+  kernel command line option such as "mem=256M". (Try "man bootparam"
+  or see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel at boot time. The lilo procedure
+  is also explained in the SCSI-HOWTO, available from
+  http://metalab.unc.edu/mdw/linux.html#howto .)
+
 Math emulation
 CONFIG_NWFPE
-  Say Y to include the NWFPE floating point emulator in the kernel. This
-  is necessary to run most binaries. Linux does not currently support
-  floating point hardware so you need to say Y here even if your machine
-  has an FPA or floating point co-processor podule.
+  Say Y to include the NWFPE floating point emulator in the kernel.
+  This is necessary to run most binaries. Linux does not currently
+  support floating point hardware so you need to say Y here even if
+  your machine has an FPA or floating point co-processor podule.
 
   It is also possible to say M to build the emulator as a module
   (nwfpe.o) or indeed to leave it out altogether. However, unless you
-  know what you are doing this can easily render your machine unbootable.
-  Saying Y is the safe option.
+  know what you are doing this can easily render your machine
+  unbootable. Saying Y is the safe option.
 
   You may say N here if you are going to load the Acorn FPEmulator
   early in the bootup.
@@ -11656,6 +12171,12 @@
   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
@@ -11664,10 +12185,10 @@
 
 User fault debugging
 CONFIG_DEBUG_USER
-  When a user program crashes due to an exception, the kernel can print
-  a brief message explaining what the problem was. This is sometimes
-  helpful for debugging but serves no purpose on a production system.
-  Most people should say N here.
+  When a user program crashes due to an exception, the kernel can
+  print a brief message explaining what the problem was. This is
+  sometimes helpful for debugging but serves no purpose on a
+  production system. Most people should say N here.
 
 Include gdb debugging information in kernel binary
 CONFIG_DEBUG_INFO
@@ -11675,25 +12196,27 @@
   `vmlinux' binary image. This is handy if you want to use gdb or
   addr2line to debug the kernel. It has no impact on the in-memory
   footprint of the running kernel but it can increase the amount of
-  time and disk space needed for compilation. If in doubt say N.
+  time and disk space needed for compilation of the kernel. If in
+  doubt say N.
 
 Split initialisation functions into discardable section
 CONFIG_TEXT_SECTIONS
-  Normally code that is only used during initialisation is collected
-  into a special area of the kernel so that it can be discarded and
-  the memory reclaimed when 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 enabled. Say Y unless
-  you experience problems that you suspect may be caused by this.
+  If you say Y here, kernel code that is only used during
+  initialisation is collected into a special area of the kernel so
+  that it can be discarded and the memory reclaimed when
+  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
+  enabled. Say Y unless you experience problems that you suspect may
+  be caused by this.
 
 Disable pgtable cache
 CONFIG_NO_PGT_CACHE
-  Normally the kernel maintains a `quicklist' of preallocated pagetable
-  structures in order to increase performance. On machines with very
-  few pages this may however be a loss. Say Y here to disable the pgtable
-  cache.
+  Normally the kernel maintains a `quicklist' of preallocated
+  pagetable structures in order to increase performance. On machines
+  with very few pages this may however be a loss. Say Y here to
+  disable the pgtable cache.
 
 RISC OS personality
 CONFIG_ARTHUR
@@ -11709,16 +12232,17 @@
   for the boot loader to pass arguments to the kernel. For these
   architectures, you should supply some command-line options at build
   time by entering them here. As a minimum, you should specify the
-  memory size and the root device (eg, mem=64M root=/dev/nfs)
+  memory size and the root device (e.g., mem=64M root=/dev/nfs)
 
 Hardware alignment trap
 CONFIG_ALIGNMENT_TRAP
-  ARM processors can not fetch/store information which is not naturally
-  aligned on the bus, ie, a 4 byte fetch must start at an address divisable
-  by 4.  On 32-bit ARM processors, these instructions can be emulated in
-  software with a severe performance impact. This is necessary for correct
-  operation of some network protocols.  With an IP-only configuration
-  it is safe to say N, otherwise say Y.
+  ARM processors can not fetch/store information which is not
+  naturally aligned on the bus, i.e., a 4 byte fetch must start at an
+  address divisible by 4. On 32-bit ARM processors, these non-aligned
+  fetch/store instructions will be emulated in software if you say
+  here, which has a severe performance impact. This is necessary for
+  correct operation of some network protocols. With an IP-only
+  configuration it is safe to say N, otherwise say Y.
 
 21285 serial port support
 CONFIG_SERIAL_21285
@@ -11729,32 +12253,32 @@
 Console on 21285 serial port
 CONFIG_SERIAL_21285_CONSOLE
   If you have enabled the serial port on the 21285 footbridge you can
-  make it the console by answering 'Y' to this option.
+  make it the console by answering Y to this option.
 
 Footbridge Mode
 CONFIG_HOST_FOOTBRIDGE
   The 21285 Footbridge chip can operate in either `host mode' or
   `add-in' mode.  Say Y if your 21285 is in host mode, and therefore
-  is the configuration master, otherwise say N.  This must not be
-  set to 'Y' if the card is used in 'add-in' mode.
+  is the configuration master, otherwise say N. This must not be
+  set to Y if the card is used in 'add-in' mode.
 
-MFM harddisk support
+MFM hard disk support
 CONFIG_BLK_DEV_MFM
   Support the MFM hard drives on the Acorn Archimedes both
   on-board the A4x0 motherboards and via the Acorn MFM podules.
-  Drives upto 64MB are supported. If you haven't got one of these
-  machines or drives just say 'N'.
+  Drives up to 64MB are supported. If you haven't got one of these
+  machines or drives just say N.
 
 Old Archimedes floppy (1772) support
 CONFIG_BLK_DEV_FD1772
   Support the floppy drive on the Acorn Archimedes (A300, A4x0, A540,
   R140 and R260) series of computers; it supports only 720K floppies
   at the moment. If you don't have one of these machines just answer
-  'N'.
+  N.
 
 Autodetect hard drive geometry
 CONFIG_BLK_DEV_MFM_AUTODETECT
-  If you answer 'Y' the MFM code will attempt to automatically detect
+  If you answer Y, the MFM code will attempt to automatically detect
   the cylinders/heads/sectors count on your hard drive. WARNING: This
   sometimes doesn't work and it also does some dodgy stuff which
   potentially might damage your drive.
@@ -11769,12 +12293,10 @@
   some user-space utilities like the irmanager and probably irattach
   as well. For more information, see the file
   Documentation/networking/irda.txt. You also want to read the
-  IR-HOWTO, available from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  IR-HOWTO, available at http://metalab.unc.edu/mdw/linux.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. The
-  module will be called 
+  it as a module, say M here and read Documentation/modules.txt.
 
 IrDA Cache last LSAP
 CONFIG_IRDA_CACHE_LAST_LSAP
@@ -11878,6 +12400,17 @@
 
   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
@@ -11945,15 +12478,6 @@
   by IrTTY. To activate support for Greenwich dongles you will have to
   insert "irattach -d girbil" in the /etc/irda/drivers script.
 
-Adaptec Airport 1000 and 2000 dongle
-CONFIG_AIRPORT_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 Airport dongle attaches to
-  the normal 9-pin serial port connector, and can currently only be
-  used by IrTTY. To activate support for Airport dongles you will have
-  to insert "irattach -d airport" in the /etc/irda/drivers script.
-
 Parallax Litelink dongle
 CONFIG_LITELINK_DONGLE
   Say Y here if you want to build support for the Parallax Litelink
@@ -11963,6 +12487,16 @@
   by IrTTY. To activate support for Parallax dongles you will have to
   insert "irattach -d litelink" in the /etc/irda/drivers script.
 
+Adaptec Airport 1000 and 2000 dongle
+CONFIG_AIRPORT_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
+  airport.o. The Airport dongle attaches to the normal 9-pin serial
+  port connector, and can currently only be used by IrTTY. To activate
+  support for Airport dongles you will have to insert "irattach -d
+  airport" in the /etc/irda/drivers script.
+
 VME (Motorola and BVM) support
 CONFIG_VME
   Say Y here if you want to build a kernel for a 680x0 based VME
@@ -12041,104 +12575,10 @@
   boards from BVM Ltd.  Everyone using one of these boards should say
   Y here.
 
-Universal Serial Bus (USB) Support (Experimental)
-CONFIG_USB
-  This will enable support for the Universal Serial Bus (USB).  USB 
-  allows you to connect up to 127 external devices such as keyboards, 
-  mice, printers and modems to your computer through a USB connector.
-  This code can also be built as a module (i.e. code outside the 
-  kernel that can be added and removed at runtime), consult 
-  Documentation/modules.txt for more information.
-
-UHCI (intel PIIX4 and others) support
-CONFIG_USB_UHCI
-  The UHCI is the USB host controller for many computers, and is built
-  into all recent boards with intel PCI chipsets. This driver is
-  needed for these motherboards to support USB.
-
-OHCI (compaq and some others) support
-CONFIG_USB_OHCI
-  The OHCI (Open Host Controller Interface) is the USB host controller
-  on most non-Intel architectures, several USB-adding PCI cards, and
-  is on several x86 compatibles with non-Intel chipsets. This driver
-  is needed for these motherboards to support USB. There is presently
-  two OHCI drivers in development. Say 'N' here if you would like to
-  compile the other OHCI driver into the linux kernel.
-
-OHCI-HCD (other OHCI opt. Virt. Root Hub) support
-CONFIG_USB_OHCI_HCD
-  The OHCI (Open Host Controller Interface) is the USB host controller
-  on most non-Intel architectures, several USB-adding PCI cards, and
-  is on several x86 compatibles with non-Intel chipsets. This driver
-  is needed for these motherboards to support USB. There is presently
-  two OHCI drivers in development. 
-
-USB hub support
-CONFIG_USB_HUB
-  To expand beyond the USB ports on the computer, a device called a 
-  hub is used. This driver supports hubs, allowing them to be used. 
-  Say 'Y'.
-
-USB mouse support
-CONFIG_USB_MOUSE  
-  This driver allows mice to work under the USB stack. It currently
-  patches into /dev/ps2aux, although it does not require the ps2 
-  mouse code to be included in the kernel as well.
-
-USB keyboard support
-CONFIG_USB_KBD
-  This driver allows USB keyboards to work under the USB stack.
-
-USB audio parsing support (Preliminary)
-CONFIG_USB_AUDIO
-  This driver will eventually handle audio devices, such 
-  as USB speakers.
-
-USB Communications Device Class (ACM) support (Preliminary)
-CONFIG_USB_ACM
-  This driver handles devices which support the Abstract Control Model,
-  a subtype of the USB Communications Device Class. This includes many
-  USB-based modems and ISDN adapters. Add special files with:
-  mknod /dev/ttyACM0 c 166 0 
-  mknod /dev/ttyACM1 c 166 1
-  mknod /dev/ttyACM2 c 166 2
-  mknod /dev/ttyACM3 c 166 3
-
-USB Printer Device Class support (Preliminary)
-CONFIG_USB_PRINTER
-  This is a generic driver for USB printers.
-
-USS720 parport driver
-CONFIG_USB_USS720
-  This driver is for USB parallel port adapters that use the 
-  Lucent Technologies USS-720 chip.
-  
-  The chip has two modes: automatic mode and manual mode.
-  In automatic mode, it looks like a standard USB printer. Only
-  Printers may be connected to the USS-720 in this mode.
-  The generic USB printer driver (CONFIG_USB_PRINTER, above)
-  may be used in that mode.
-
-  Manual mode is not limited to printers, any parallel port
-  device should work. This driver utilizes manual mode.
-  Note however that some operations are three orders of a magnitude
-  slower than on a PCI/ISA Parallel Port, so timing critical
-  applications might not work.
-
-  Say Y or M if you own an USS-720 USB->Parport cable and
-  intend to connect anything other than a printer to it. 
-
-USB /proc filesystem entry support (Preliminary)
-CONFIG_USB_PROC
-  This reports USB drivers and devices in the /proc filesystem.
-  Entries are located in /proc/bus/usb.
-  Note that you must enable support for the proc filesystem
-  for this to work.
-
 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 low-level access to the parallel
+  is needed for programs that want portable access to the parallel
   port, for instance deviceid (which displays Plug-and-Play device
   IDs) and vlp (which makes a Linux computer act as though it's a
   printer).
@@ -12147,10 +12587,16 @@
   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.
+
 Kernel httpd acceleration (experimental)
 CONFIG_KHTTPD
   The kernel httpd acceleration daemon (kHTTPd) is a (limited) 
-  webserver build into the kernel. It is limited since it can only
+  web server build into the kernel. It is limited since it can only
   serve files from the filesystem. 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
@@ -12161,7 +12607,6 @@
   The kHTTPd is experimental. Be careful when using it on a production
   machine. Also note that kHTTPd doesn't support virtual servers yet.
 
-
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, 
@@ -12302,7 +12747,7 @@
 # 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:  hayes TX TMOUT
+# LocalWords:  Sitor Amtor Pactor GTOR hayes TX TMOUT JFdocs BIGMEM DAC IRQ's
 # LocalWords:  IDEPCI IDEDMA idedma PDC pdc TRM trm raidtools luthien nuclecu
 # LocalWords:  unam mx miguel koobera uic EMUL solaris pp ieee lpsg co DMAs TOS
 # LocalWords:  BLDCONFIG preloading jumperless BOOTINIT modutils multipath GRE
@@ -12388,5 +12833,40 @@
 # LocalWords:  BVME BVME WRITETHROUGH copyback writethrough fwmark syncookie tu
 # LocalWords:  alphalinux GOBIOS csn chemnitz nat ACARD AMI MegaRAID megaraid
 # LocalWords:  QNXFS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
-# LocalWords:  IrLPT UIRCC Tecra
-
+# LocalWords:  IrLPT UIRCC Tecra Strebel jstrebel suse Eichwalder ke INI INIA
+# LocalWords:  FCP qlogicfc sym isapnp DTLK DoubleTalk rcsys dtlk DMAP SGIVW ar
+# LocalWords:  dmabuf EcoRadio MUTEFREQ GIrBIL girbil tepkom vol mha diplom PQS
+# LocalWords:  bmac Microgate SyncLink synclink hdlc excl ioaddr Tane tanep TCQ
+# LocalWords:  PDS SMALLDOS charsets bigfoot kernelfr mcs cls fw rsvp SKnet sk
+# LocalWords:  SKMC USB UHCI OHCI intel compaq usb ohci HCD Virt Compaq's hcd
+# LocalWords:  VROOTHUB KBD ARRs MCRs NWBUTTON nwbutton NUM WaveArtist APNE cpu
+# LocalWords:  apne blackhawke PlanB lu mlan planb NWFPE FPA nwfpe unbootable
+# LocalWords:  FPEmulator ds vmlinux initialisation discardable pgtable PGT mdw
+# LocalWords:  quicklist pagetable arthur StrongARM podule podules Autodetect
+# LocalWords:  dodgy IrPORT irport Litelink litelink SuSE rtfm internet hda CY
+# LocalWords:  multmode DriveReady SeekComplete DriveStatusError miscompile AEC
+# LocalWords:  mainboard's Digital's alim FastTrak aec PIIXn piix Gayle Eyetech
+# LocalWords:  Catweasel IDEDOUBLER Powerbook Centris ICSIDE RapIDE OSM HDM IOP
+# LocalWords:  HDM's OSM's lan FibreChannel ECP autoprobe itg lbl ipmasq cjb IC
+# LocalWords:  bieringer Caulfield's dreamtime decnet SIOCFIGCONF SIOCGIFCONF
+# LocalWords:  rtnetlink Endnode Aironet Arlan Telxon ylenurme arlan ACB aeschi
+# LocalWords:  Sealevel sealevel Cyclom br wanconfig tarball conectiva cycsyn
+# LocalWords:  devel bazar cyclomx NetGear GA IBMOL Lanstreamer uhci eu efs CYZ
+# LocalWords:  olympic linuxtr usbcore acm EZUSB downloader EFS XFS INTR op IIC
+# LocalWords:  heine soundcore JavaStations JavaStation GemTeks TerraTec TODO
+# LocalWords:  ActiveRadio Standalone terratec Rolf Offermanns rolf offermanns
+# LocalWords:  Zoran ZR Buz LML CPQ DA cpqarray PPDEV deviceid vlp ppdev atyfb
+# LocalWords:  AcceleRAID eXtremeRAID NETFILTER Netfilter masqueraded netfilter
+# LocalWords:  kernelnotes Cardbus PCMCIA's CardBus clgenfb Permedia YAM MMAP
+# LocalWords:  mmapped ATM atm PVCs SVCs InARP ATMARP neighbour neighbours MPOA
+# LocalWords:  VCs ENI FPGA Tonga MMF MF UTP printks ZeitNet ZN ZATM uPD SAR PN
+# LocalWords:  approx NICStAR NICs ForeRunnerLE Madge Collage ATMizer Dxxxx VCI
+# LocalWords:  ServeRAID IPS ips ipslinux gzip BSDCOMP LZW RAYCS Interphase app
+# LocalWords:  Tachyon IPHASE Surfboard NextLevel SURFboard jacksonville Tigon
+# LocalWords:  fventuri adelphia siglercm linuxpower AceNICs Starfire starfire
+# LocalWords:  ISOC CPiA cpia uss ACPI UDF DirectCD udf CDRW's OSF Manx acpi
+# 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
diff -u --recursive --new-file v2.3.19/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v2.3.19/linux/Documentation/devices.tex	Thu Aug  5 18:48:45 1999
+++ linux/Documentation/devices.tex	Thu Oct  7 10:17:08 1999
@@ -254,11 +254,13 @@
 \major{86}{}{char }{SCSI media changer}
 \major{87}{}{char }{Sony Control-A1 stereo control bus}
 \major{88}{}{char }{COMX synchronous serial card}
-\major{  }{}{block}{Sixth IDE hard disk/CD-ROM interface}
-\major{89}{}{char }{I$^2$C bus interface}
 \major{  }{}{block}{Seventh IDE hard disk/CD-ROM interface}
+\major{89}{}{char }{I$^2$C bus interface}
+\major{  }{}{block}{Eighth IDE hard disk/CD-ROM interface}
 \major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)}
+\major{  }{}{block}{Ninth IDE hard disk/CD-ROM interface}
 \major{91}{}{char }{CAN-Bus controller}
+\major{  }{}{block}{Tenth IDE hard disk/CD-ROM interface}
 \major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card}
 \major{93}{}{char }{IBM Smart Capture Card frame grabber}
 \major{94}{}{char }{miroVIDEO DC10/30 capture/playback device}
@@ -1748,7 +1750,7 @@
 \end{devicelist}
 
 \begin{devicelist}
-\major{  }{}{block}{Sixth IDE hard disk/CD-ROM interface}
+\major{  }{}{block}{Seventh IDE hard disk/CD-ROM interface}
         \minor{0}{/dev/hdm}{Master: whole disk (or CD-ROM)}
         \minor{64}{/dev/hdn}{Slave: whole disk (or CD-ROM)}
 \end{devicelist}
@@ -1765,7 +1767,7 @@
 \end{devicelist}
 
 \begin{devicelist}
-\major{  }{}{block}{Seventh IDE hard disk/CD-ROM interface}
+\major{  }{}{block}{Eighth IDE hard disk/CD-ROM interface}
         \minor{0}{/dev/hdo}{Master: whole disk (or CD-ROM)}
         \minor{64}{/dev/hdp}{Slave: whole disk (or CD-ROM)}
 \end{devicelist}
@@ -1784,7 +1786,7 @@
 \end{devicelist}
 
 \begin{devicelist}
-\major{  }{}{block}{Eighth IDE hard disk/CD-ROM interface}
+\major{  }{}{block}{Ninth IDE hard disk/CD-ROM interface}
 	\minor{0}{/dev/hdq}{Master: whole disk (or CD-ROM)}
 	\minor{64}{/dev/hdr}{Slave: whole disk (or CD-ROM)}
 \end{devicelist}
@@ -1801,7 +1803,7 @@
 \end{devicelist}
 
 \begin{devicelist}
-\major{  }{}{block}{Ninth IDE hard disk/CD-ROM interface}
+\major{  }{}{block}{Tenth IDE hard disk/CD-ROM interface}
 	\minor{0}{/dev/hds}{Master: whole disk (or CD-ROM)}
 	\minor{64}{/dev/hdt}{Slave: whole disk (or CD-ROM)}
 \end{devicelist}
diff -u --recursive --new-file v2.3.19/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v2.3.19/linux/Documentation/devices.txt	Thu Aug  5 18:48:45 1999
+++ linux/Documentation/devices.txt	Thu Oct  7 10:17:08 1999
@@ -1215,7 +1215,7 @@
 		  1 = /dev/comx1	COMX channel 1
 		    ...
 
-    block	Sixth IDE hard disk/CD-ROM interface
+    block	Seventh IDE hard disk/CD-ROM interface
 		  0 = /dev/hdm		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdn		Slave: whole disk (or CD-ROM)
 
@@ -1227,7 +1227,7 @@
 		  1 = /dev/i2c1		Second I2C adapter
 		    ...
 
-    block	Seventh IDE hard disk/CD-ROM interface
+    block	Eighth IDE hard disk/CD-ROM interface
 		  0 = /dev/hdo		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdp		Slave: whole disk (or CD-ROM)
 
@@ -1241,7 +1241,7 @@
 		 30 = /dev/mtd15	16th MTD (rw)
 		 31 = /dev/mtdr15	16th MTD (ro)
 
-    block	Eighth IDE hard disk/CD-ROM interface
+    block	Ninth IDE hard disk/CD-ROM interface
 		  0 = /dev/hdq		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdr		Slave: whole disk (or CD-ROM)
 
@@ -1253,7 +1253,7 @@
 		  1 = /dev/can1		Second CAN-Bus controller
 		    ...
 
-    block	Ninth IDE hard disk/CD-ROM interface
+    block	Tenth IDE hard disk/CD-ROM interface
 		  0 = /dev/hds		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdt		Slave: whole disk (or CD-ROM)
 
diff -u --recursive --new-file v2.3.19/linux/Documentation/kbuild/config-language.txt linux/Documentation/kbuild/config-language.txt
--- v2.3.19/linux/Documentation/kbuild/config-language.txt	Mon Feb  1 12:03:20 1999
+++ linux/Documentation/kbuild/config-language.txt	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 Config Language Specification
-21 January 1999
+28 September 1999
 Michael Elizabeth Chastain, <mailto:mec@shout.net>
 
 
@@ -82,7 +82,10 @@
     double-quoted string.  If the word is unquoted or double quoted,
     then $-substition will be performed on the word.
 
-    A /symbol/ is a single unquoted word.
+    A /symbol/ is a single unquoted word.  A symbol must have a name of
+    the form CONFIG_*.  scripts/mkdep.c relies on this convention in order
+    to generate dependencies on individual CONFIG_* symbols instead of
+    making one massive dependency on include/linux/autoconf.h.
 
     A /dep/ is a dependency.  Syntactically, it is a /word/.  At run
     time, a /dep/ must evaluate to "y", "m", "n", or "".
@@ -355,8 +358,8 @@
 number is a legal value.
 
 Configure:  implemented
-Menuconfig: not implemented
-Xconfig:    not implemented
+Menuconfig: implemented
+Xconfig:    implemented
 mconfig:    implemented
 
 Example:
@@ -377,8 +380,8 @@
 legal value.
 
 Configure:  implemented
-Menuconfig: not implemented
-Xconfig:    not implemented
+Menuconfig: implemented
+Xconfig:    implemented
 mconfig:    implemented
 
 Example:
@@ -394,8 +397,8 @@
 are any ASCII string, except for the characters '"' and '\\'.
 
 Configure:  implemented
-Menuconfig: not implemented
-Xconfig:    not implemented
+Menuconfig: implemented
+Xconfig:    implemented
 mconfig:    implemented
 
 Example
@@ -414,9 +417,9 @@
 instead of define_bool to define tristate values.  This aids in static
 type checking.
 
-Configure:  not implemented
-Menuconfig: not implemented
-Xconfig:    not implemented
+Configure:  implemented
+Menuconfig: implemented
+Xconfig:    implemented
 mconfig:    implemented
 
 Example:
@@ -433,22 +436,27 @@
 
 This verb evaluates all of the dependencies in the dependency list.
 Any dependency which has a value of "y" does not restrict the input
-range.  Any dependency which has a value of "n", or which has some
-other value, restricts the input range to "n".
+range.  Any dependency which has an empty value is ignored.
+Any dependency which has a value of "n", or which has some other value,
+restricts the input range to "n".  Quoting dependencies is not allowed.
+Using dependencies with an empty value possible is not recommended.
 
 If the input range is restricted to the single choice "n", dep_bool
 silently assigns "n" to /symbol/.  If the input range has more than
 one choice, dep_bool displays /prompt/ to the user, accepts a value
 from the user, and assigns that value to /symbol/.
 
-Configure:  not implemented
-Menuconfig: not implemented
-XConfig:    not implemented
+Configure:  implemented
+Menuconfig: implemented
+XConfig:    implemented
 mconfig:    implemented
 
     # not from the corpus
     dep_bool 'RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_PCI
 
+Known bugs:
+- Xconfig does not write "# foo is not set" to .config (as well as
+  "#unset foo" to autoconf.h) if command is disabled by its dependencies.
 
 
 === dep_hex /prompt/ /symbol/ /word/ /dep/ ...
@@ -464,13 +472,15 @@
 
 
 
-=== dep_tristate /prompt/ /symbol /dep/ ...
+=== dep_tristate /prompt/ /symbol/ /dep/ ...
 
 This verb evaluates all of the dependencies in the dependency list.
-Any dependency which as a value of "y" does not restrict the input range.
+Any dependency which has a value of "y" does not restrict the input range.
 Any dependency which has a value of "m" restricts the input range to
-"m" or "n".  Any dependency which has a value of "n", or which has some
-other value, restricts the input range to "n".
+"m" or "n".  Any dependency which has an empty value is ignored.
+Any dependency which has a value of "n", or which has some other value,
+restricts the input range to "n".  Quoting dependencies is not allowed.
+Using dependencies with an empty value possible is not recommended.
 
 If the input range is restricted to the single choice "n", dep_tristate
 silently assigns "n" to /symbol/.  If the input range has more than
@@ -478,10 +488,13 @@
 from the user, and assigns that value to /symbol/.
 
 Configure:  implemented
-Menuconfig: implemented (but silently ignores dependencies after the first)
-Xconfig:    implemented (but silently ignores dependencies after the first)
+Menuconfig: implemented
+Xconfig:    implemented
 mconfig:    implemented
 
+Known bugs:
+- Xconfig does not write "# foo is not set" to .config (as well as
+  "#unset foo" to autoconf.h) if command is disabled by its dependencies.
 
 
 === unset /symbol/ ...
@@ -492,7 +505,7 @@
 
 Configure:  implemented
 Menuconfig: implemented
-Xconfig:    not implemented
+Xconfig:    implemented (with bugs)
 mconfig:    implemented
 
 
@@ -570,14 +583,9 @@
 XConfig:    implemented, with bugs
 mconfig:    implemented
 
-Xconfig has several known bugs, and probably some unknown bugs too:
-
-- In a comparison, if the left-hand atom is a variable and that variable
-  is from a choice list, the right-hand atom must be "y".
+Xconfig has some known bugs, and probably some unknown bugs too:
 
-- In a comparison, if the right-hand atom is a variable and that variable
-  is from a choice list, you lose.  tkparse will throw a segmentation
-  violation, silently generate bizarre TCL code, or something else.
+- literals with an empty "" value are not properly handled.
 
 - tkparse gives the wrong precedence to -o, -a, and !.  Don't use both
   -o and -a in an expression.  Don't use ! at all.
diff -u --recursive --new-file v2.3.19/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- v2.3.19/linux/Documentation/kernel-parameters.txt	Wed Jul 21 12:54:07 1999
+++ linux/Documentation/kernel-parameters.txt	Thu Oct  7 10:17:08 1999
@@ -266,9 +266,11 @@
 				IRQ/DMA settings because of possible
 				conflicts).  You can specify the base
 				address, IRQ, and DMA settings; IRQ
-				and DMA should be numbers or 'auto'
+				and DMA should be numbers, or 'auto'
 				(for using detected settings on that
-				particular port).  Parallel ports are
+				particular port), or 'nofifo' (to
+				avoid using a FIFO even if it is
+				detected).  Parallel ports are
 				assigned in the order they are
 				specified on the command line,
 				starting with parport0.
diff -u --recursive --new-file v2.3.19/linux/Documentation/networking/ray_cs.txt linux/Documentation/networking/ray_cs.txt
--- v2.3.19/linux/Documentation/networking/ray_cs.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/ray_cs.txt	Thu Oct  7 10:17:08 1999
@@ -0,0 +1,151 @@
+September 21, 1999
+
+Copyright (c) 1998  Corey Thomas (corey@world.std.com)
+
+This file is the documentation for the Raylink Wireless LAN card driver for
+Linux.  The Raylink wireless LAN card is a PCMCIA card which provides IEEE
+802.11 compatible wireless network connectivity at 1 and 2 megabits/second.
+See http://www.raytheon.com/micro/raylink/ for more information on the Raylink
+card.  This driver is in early development and does have bugs.  See the known
+bugs and limitations at the end of this document for more information.
+This driver also works with WebGear's Aviator 2.4 and Aviator Pro
+wireless LAN cards.
+
+As of kernel 2.3.18, the ray_cs driver is part of the Linux kernel
+source.  My web page for the development of ray_cs is at
+http://world.std.com/~corey/raylink.html and I can be emailed at
+corey@world.std.com
+
+The kernel driver is based on ray_cs-1.62.tgz
+
+The driver at my web page is intended to be used as an add on to
+David Hinds pcmcia package.  All the command line parameters are
+available when compiled as a module.  When built into the kernel, only
+the essid= string parameter is available via the kernel command line.
+This will change after the method of sorting out parameters for all
+the PCMCIA drivers is agreed upon.  If you must have a built in driver
+with nondefault parameters, they can be edited in
+/usr/src/linux/drivers/net/pcmcia/ray_cs.c.  Searching for MODULE_PARM
+will find them all.
+
+Information on card services is available at:
+	ftp://hyper.stanford.edu/pub/pcmcia/doc
+        http://hyper.stanford.edu/HyperNews/get/pcmcia/home.html
+
+
+Card services user programs are still required for PCMCIA devices.
+pcmcia-cs-3.1.1 or greater is required for the kernel version of
+the driver.
+
+Currently, ray_cs is not part of David Hinds card services package,
+so the following magic is required.
+
+At the end of the /etc/pcmcia/config.opts file, add the line: 
+source ./ray_cs.opts 
+This will make card services read the ray_cs.opts file
+when starting.  Create the file /etc/pcmcia/ray_cs.opts containing the
+following:
+
+#### start of /etc/pcmcia/ray_cs.opts ###################
+# Configuration options for Raylink Wireless LAN PCMCIA card
+device "ray_cs"
+  class "network" module "misc/ray_cs"
+
+card "RayLink PC Card WLAN Adapter"
+  manfid 0x01a6, 0x0000
+  bind "ray_cs"
+
+module "misc/ray_cs" opts ""
+#### end of /etc/pcmcia/ray_cs.opts #####################
+
+
+To join an existing network with
+different parameters, contact the network administrator for the 
+configuration information, and edit /etc/pcmcia/ray_cs.opts.
+Add the parameters below between the empty quotes.
+
+Parameters for ray_cs driver which may be specified in ray_cs.opts:
+
+bc              integer         0 = normal mode (802.11 timing)
+                                1 = slow down inter frame timing to allow
+                                    operation with older breezecom access
+                                    points.
+
+beacon_period	integer         beacon period in Kilo-microseconds
+				legal values = must be integer multiple 
+                                               of hop dwell
+                                default = 256
+
+country         integer         1 = USA (default)
+                                2 = Europe
+                                3 = Japan
+                                4 = Korea
+                                5 = Spain
+                                6 = France
+                                7 = Israel
+                                8 = Australia
+
+essid		string		ESS ID - network name to join
+				string with maximum length of 32 chars
+				default value = "ADHOC_ESSID"
+
+hop_dwell	integer         hop dwell time in Kilo-microseconds 
+				legal values = 16,32,64,128(default),256
+
+irq_mask	integer         linux standard 16 bit value 1bit/IRQ
+				lsb is IRQ 0, bit 1 is IRQ 1 etc.
+				Used to restrict choice of IRQ's to use.
+                                Recommended method for controlling
+                                interrupts is in /etc/pcmcia/config.opts
+
+net_type	integer		0 (default) = adhoc network, 
+				1 = infrastructure
+
+phy_addr	string          string containing new MAC address in
+				hex, must start with x eg
+				x00008f123456
+
+psm		integer         0 = continuously active
+				1 = power save mode (not useful yet)
+
+pc_debug	integer		(0-5) larger values for more verbose
+				logging.  Replaces ray_debug.
+
+ray_debug	integer		Replaced with pc_debug
+
+ray_mem_speed   integer         defaults to 500
+
+sniffer         integer         0 = not sniffer (default)
+                                1 = sniffer which can be used to record all
+                                    network traffic using tcpdump or similar, 
+                                    but no normal network use is allowed.
+
+translate	integer		0 = no translation (encapsulate frames)
+				1 = translation    (RFC1042/802.1)
+
+
+More on sniffer mode:
+
+tcpdump does not understand 802.11 headers, so it can't
+interpret the contents, but it can record to a file.  This is only
+useful for debugging 802.11 lowlevel protocols that are not visible to
+linux.  If you want to watch ftp xfers, or do similar things, you
+don't need to use sniffer mode.  Also, some packet types are never
+sent up by the card, so you will never see them (ack, rts, cts, probe
+etc.)  There is a simple program (showcap) included in the ray_cs
+package which parses the 802.11 headers.
+
+Known Problems and missing features
+
+        Does not work with non x86
+
+	Does not work with SMP
+
+	Support for defragmenting frames is not yet debugged, and in
+	fact is known to not work.  I have never encountered a net set
+	up to fragment, but still, it should be fixed.
+
+	The ioctl support is incomplete.  The hardware address cannot be set
+	using ifconfig yet.  If a different hardware address is needed, it may
+	be set using the phy_addr parameter in ray_cs.opts.  This requires
+	a card insertion to take effect.
diff -u --recursive --new-file v2.3.19/linux/Documentation/nmi_watchdog.txt linux/Documentation/nmi_watchdog.txt
--- v2.3.19/linux/Documentation/nmi_watchdog.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/nmi_watchdog.txt	Thu Oct  7 10:17:08 1999
@@ -0,0 +1,33 @@
+
+Is your SMP system locking up unpredictably? No keyboard activity, just
+a frustrating complete hard lockup? Do you want to help us debugging
+such lockups? If all yes then this document is definitely for you.
+
+on Intel SMP hardware there is a feature that enables us to generate
+'watchdog NMI interrupts'. (NMI: Non Maskable Interrupt - these get
+executed even if the system is otherwise locked up hard) This can be
+used to debug hard kernel lockups. By executing periodic NMI interrupts,
+the kernel can monitor wether any CPU has locked up, and print out
+debugging messages if so.  You can enable/disable the NMI watchdog at boot
+time with the 'nmi_watchdog=1' boot parameter. Eg. the relevant
+lilo.conf entry:
+
+        append="nmi_watchdog=1"
+
+A 'lockup' is the following scenario: if any CPU in the system does not
+execute the period local timer interrupt for more than 5 seconds, then
+the NMI handler generates an oops and kills the process. This
+'controlled crash' (and the resulting kernel messages) can be used to
+debug the lockup. Thus whenever the lockup happens, wait 5 seconds and
+the oops will show up automatically. If the kernel produces no messages
+then the system has crashed so hard (eg. hardware-wise) that either it
+cannot even accept NMI interrupts, or the crash has made the kernel
+unable to print messages.
+
+NOTE: currently the NMI-oopser is enabled unconditionally on x86 SMP
+boxes.
+
+[ feel free to send bug reports, suggestions and patches to
+  Ingo Molnar <mingo@redhat.com> or the Linux SMP mailing
+  list at <linux-smp@vger.rutgers.edu> ]
+
diff -u --recursive --new-file v2.3.19/linux/Documentation/parport.txt linux/Documentation/parport.txt
--- v2.3.19/linux/Documentation/parport.txt	Thu Aug 12 10:19:59 1999
+++ linux/Documentation/parport.txt	Thu Oct  7 10:17:08 1999
@@ -67,7 +67,7 @@
 kernel boot parameters to get the same effect.  Add something like the
 following to your LILO command line:
 
-	parport=0x3bc parport=0x378,7 parport=0x278,auto
+	parport=0x3bc parport=0x378,7 parport=0x278,auto,nofifo
 
 You can have many `parport=...' statements, one for each port you want
 to add.  Adding `parport=0' to the kernel command-line will disable
diff -u --recursive --new-file v2.3.19/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.19/linux/MAINTAINERS	Mon Oct  4 15:49:29 1999
+++ linux/MAINTAINERS	Thu Oct  7 10:17:08 1999
@@ -434,6 +434,11 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT
+P:	Ingo Molnar
+M:	mingo@redhat.com
+S:	Maintained
+
 IP MASQUERADING:
 P:	Juanjo Ciarlante
 M:	jjciarla@raiz.uncu.edu.ar
diff -u --recursive --new-file v2.3.19/linux/Makefile linux/Makefile
--- v2.3.19/linux/Makefile	Mon Oct  4 15:49:29 1999
+++ linux/Makefile	Thu Oct  7 10:17:08 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 19
+SUBLEVEL = 20
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/core_apecs.c linux/arch/alpha/kernel/core_apecs.c
--- v2.3.19/linux/arch/alpha/kernel/core_apecs.c	Tue Sep  7 12:14:05 1999
+++ linux/arch/alpha/kernel/core_apecs.c	Thu Oct  7 12:23:21 1999
@@ -18,7 +18,6 @@
 #include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/smp.h>
-#include <asm/pci.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c
--- v2.3.19/linux/arch/alpha/kernel/core_cia.c	Tue Sep  7 12:14:05 1999
+++ linux/arch/alpha/kernel/core_cia.c	Thu Oct  7 12:23:21 1999
@@ -19,7 +19,6 @@
 
 #include <asm/system.h>
 #include <asm/ptrace.h>
-#include <asm/pci.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/core_lca.c linux/arch/alpha/kernel/core_lca.c
--- v2.3.19/linux/arch/alpha/kernel/core_lca.c	Tue Sep  7 12:14:05 1999
+++ linux/arch/alpha/kernel/core_lca.c	Thu Oct  7 12:23:21 1999
@@ -17,7 +17,6 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/smp.h>
-#include <asm/pci.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c
--- v2.3.19/linux/arch/alpha/kernel/core_mcpcia.c	Tue Sep  7 12:14:05 1999
+++ linux/arch/alpha/kernel/core_mcpcia.c	Thu Oct  7 12:23:21 1999
@@ -15,7 +15,6 @@
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
-#include <asm/pci.h>
 #include <asm/hwrpb.h>
 
 #define __EXTERN_INLINE inline
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/core_polaris.c linux/arch/alpha/kernel/core_polaris.c
--- v2.3.19/linux/arch/alpha/kernel/core_polaris.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/core_polaris.c	Thu Oct  7 12:23:21 1999
@@ -12,7 +12,6 @@
 
 #include <asm/system.h>
 #include <asm/ptrace.h>
-#include <asm/pci.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c
--- v2.3.19/linux/arch/alpha/kernel/core_pyxis.c	Tue Sep  7 12:14:05 1999
+++ linux/arch/alpha/kernel/core_pyxis.c	Thu Oct  7 12:23:21 1999
@@ -14,7 +14,6 @@
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
-#include <asm/pci.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/core_t2.c linux/arch/alpha/kernel/core_t2.c
--- v2.3.19/linux/arch/alpha/kernel/core_t2.c	Tue Sep  7 12:14:05 1999
+++ linux/arch/alpha/kernel/core_t2.c	Thu Oct  7 12:23:21 1999
@@ -17,7 +17,6 @@
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
-#include <asm/pci.h>
 
 #define __EXTERN_INLINE
 #include <asm/io.h>
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c
--- v2.3.19/linux/arch/alpha/kernel/core_tsunami.c	Tue Sep  7 12:14:05 1999
+++ linux/arch/alpha/kernel/core_tsunami.c	Thu Oct  7 12:23:21 1999
@@ -14,7 +14,6 @@
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
-#include <asm/pci.h>
 #include <asm/smp.h>
 
 #define __EXTERN_INLINE inline
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c
--- v2.3.19/linux/arch/alpha/kernel/pci.c	Tue Sep  7 12:14:05 1999
+++ linux/arch/alpha/kernel/pci.c	Thu Oct  7 12:23:21 1999
@@ -10,7 +10,6 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <asm/pci.h>
 #include <asm/machvec.h>
 
 #include "proto.h"
@@ -81,6 +80,13 @@
 	for (dev = pci_devices; dev; dev = dev->next) {
 		if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE)
 			continue;
+		/* Resource 1 of IDE controller is the address of HD_CMD
+		   register which actually occupies a single byte (0x3f6
+		   for ide0) in reported 0x3f4-3f7 range. We have to fix
+		   that to avoid resource conflict with AT-style floppy
+		   controller. */
+		dev->resource[1].start += 2;
+		dev->resource[1].end = dev->resource[1].start;
 	        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 			if (dev->resource[i].flags)
 				pci_claim_resource(dev, i);
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.3.19/linux/arch/alpha/kernel/setup.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/setup.c	Thu Oct  7 12:23:21 1999
@@ -40,7 +40,6 @@
 #include <asm/hwrpb.h>
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/pci.h>
 
 #include "proto.h"
 #include "pci_impl.h"
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c
--- v2.3.19/linux/arch/alpha/kernel/sys_dp264.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/sys_dp264.c	Thu Oct  7 12:23:21 1999
@@ -22,7 +22,6 @@
 #include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
-#include <asm/pci.h>
 #include <asm/pgtable.h>
 #include <asm/core_tsunami.h>
 #include <asm/hwrpb.h>
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c
--- v2.3.19/linux/arch/alpha/kernel/sys_rawhide.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/alpha/kernel/sys_rawhide.c	Thu Oct  7 12:23:21 1999
@@ -19,7 +19,6 @@
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/pci.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.3.19/linux/arch/alpha/kernel/sys_sio.c linux/arch/alpha/kernel/sys_sio.c
--- v2.3.19/linux/arch/alpha/kernel/sys_sio.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/sys_sio.c	Thu Oct  7 12:23:21 1999
@@ -28,7 +28,6 @@
 #include <asm/pgtable.h>
 #include <asm/core_apecs.h>
 #include <asm/core_lca.h>
-#include <asm/pci.h>
 
 #include "proto.h"
 #include "irq_impl.h"
diff -u --recursive --new-file v2.3.19/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.3.19/linux/arch/arm/config.in	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/config.in	Thu Oct  7 10:17:08 1999
@@ -7,6 +7,11 @@
 define_bool CONFIG_ARM y
 
 mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
 comment 'System and processor type'
 
 choice 'ARM system type'	\
@@ -17,24 +22,24 @@
 	 FootBridge-based	CONFIG_FOOTBRIDGE" RiscPC
 
 if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
-  bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE
-  if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
-    define_bool CONFIG_ADDIN_FOOTBRIDGE n
-  else
-    define_bool CONFIG_ADDIN_FOOTBRIDGE y
-  fi
+   bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE
+   if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
+      define_bool CONFIG_ADDIN_FOOTBRIDGE n
+   else
+      define_bool CONFIG_ADDIN_FOOTBRIDGE y
+   fi
 fi
 
 if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
-  bool '  Include support for Intel EBSA285' CONFIG_ARCH_EBSA285
-  bool '  Include support for Chalice CATS boards' CONFIG_CATS
-  bool '  Include support for Corel NetWinder' CONFIG_ARCH_NETWINDER
+   bool '  Include support for Intel EBSA285' CONFIG_ARCH_EBSA285
+   bool '  Include support for Chalice CATS boards' CONFIG_CATS
+   bool '  Include support for Corel NetWinder' CONFIG_ARCH_NETWINDER
 fi
 
 if [ "$CONFIG_ADDIN_FOOTBRIDGE" = "y" ]; then
-  # If we get any other footbridge-based plug-in boards, then
-  # add your architecture options here
-  define_bool CONFIG_ARCH_CO285 y
+   # If we get any other footbridge-based plug-in boards, then
+   # add your architecture options here
+   define_bool CONFIG_ARCH_CO285 y
 fi
 
 #
@@ -44,9 +49,9 @@
 if [ "$CONFIG_ARCH_ARC" = "y" -o \
      "$CONFIG_ARCH_A5K" = "y" -o \
      "$CONFIG_ARCH_RPC" = "y" ]; then
-  define_bool CONFIG_ARCH_ACORN y
+   define_bool CONFIG_ARCH_ACORN y
 else
-  define_bool CONFIG_ARCH_ACORN n
+   define_bool CONFIG_ARCH_ACORN n
 fi
 
 #
@@ -56,33 +61,33 @@
 #
 if [ "$CONFIG_ARCH_ARC" = "y" -o \
      "$CONFIG_ARCH_A5K" = "y" ]; then
-  define_bool CONFIG_CPU_32 n
-  define_bool CONFIG_CPU_26 y
+   define_bool CONFIG_CPU_32 n
+   define_bool CONFIG_CPU_26 y
 
-  #
-  # Select memory size
-  #
-  bool '2MB physical memory' CONFIG_PAGESIZE_16
+   #
+   # Select memory size
+   #
+   bool '2MB physical memory' CONFIG_PAGESIZE_16
 else
-  define_bool CONFIG_CPU_32 y
-  define_bool CONFIG_CPU_26 n
+   define_bool CONFIG_CPU_32 y
+   define_bool CONFIG_CPU_26 n
 
-  #
-  # Select CPU and optimisation dependent on architecture
-  #
-  if [ "$CONFIG_ARCH_EBSA110" = "y" -o \
-       "$CONFIG_FOOTBRIDGE" = "y" -o \
-       "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then
-    define_bool CONFIG_CPU_32v4 y
-    define_bool CONFIG_CPU_SA110 y
-  else
-  if [ "$CONFIG_ARCH_RPC" = "y" ]; then
-    define_bool CONFIG_CPU_32v3 y
-    bool 'Support ARM610' CONFIG_CPU_ARM6
-    bool 'Support ARM710' CONFIG_CPU_ARM7
-    bool 'Support StrongARM110' CONFIG_CPU_SA110
-  fi
-  fi
+   #
+   # Select CPU and optimisation dependent on architecture
+   #
+   if [ "$CONFIG_ARCH_EBSA110" = "y" -o \
+        "$CONFIG_FOOTBRIDGE" = "y" -o \
+        "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then
+      define_bool CONFIG_CPU_32v4 y
+      define_bool CONFIG_CPU_SA110 y
+   else
+      if [ "$CONFIG_ARCH_RPC" = "y" ]; then
+	 define_bool CONFIG_CPU_32v3 y
+	 bool 'Support ARM610' CONFIG_CPU_ARM6
+	 bool 'Support ARM710' CONFIG_CPU_ARM7
+	 bool 'Support StrongARM110' CONFIG_CPU_SA110
+      fi
+   fi
 fi
 
 #
@@ -90,7 +95,7 @@
 #
 if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \
      "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
-  define_bool CONFIG_PCI y
+   define_bool CONFIG_PCI y
 fi
 
 #
@@ -98,18 +103,15 @@
 #
 if [ "$CONFIG_CATS" = "y" -o \
      "$CONFIG_ARCH_NETWINDER" = "y" ]; then
-  define_bool CONFIG_ISA_DMA y
+   define_bool CONFIG_ISA_DMA y
 else
-  define_bool CONFIG_ISA_DMA n
+   define_bool CONFIG_ISA_DMA n
 fi
 
 endmenu
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
-  bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP
+if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" -a "$CONFIG_EXPERIMENTAL" ]; then
+   bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP
 fi
 #bool 'Split text into discardable sections' CONFIG_TEXT_SECTIONS
 endmenu
@@ -118,8 +120,8 @@
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
-  bool 'Kernel module loader' CONFIG_KMOD
+   bool '  Set version information on all symbols for modules' CONFIG_MODVERSIONS
+   bool '  Kernel module loader' CONFIG_KMOD
 fi
 endmenu
 
@@ -134,41 +136,41 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 if [ "$CONFIG_CPU_32" = "y" ]; then
-  tristate 'RISC OS personality' CONFIG_ARTHUR
+   tristate 'RISC OS personality' CONFIG_ARTHUR
 fi
 
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
-  if [ "$CONFIG_ARCH_ARC" = "y" ]; then
-    dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
-  fi
-  dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-# If exactly one hardware type is selected then parport will optimise away
-# support for loading any others.  Defeat this if the user is keen.
-  if [ "$CONFIG_PARPORT_PC" = "n" -o "$CONFIG_PARPORT_ARC" = "n" ]; then
-    if [ "$CONFIG_PARPORT_PC" != "n" -o "$CONFIG_PARPORT_ARC" != "n" ]; then
-      bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
-    fi
-  fi
+   if [ "$CONFIG_ARCH_ARC" = "y" ]; then
+      dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+   fi
+   dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+   # If exactly one hardware type is selected then parport will optimise away
+   # support for loading any others.  Defeat this if the user is keen.
+   if [ "$CONFIG_PARPORT_PC" = "n" -o "$CONFIG_PARPORT_ARC" = "n" ]; then
+      if [ "$CONFIG_PARPORT_PC" != "n" -o "$CONFIG_PARPORT_ARC" != "n" ]; then
+         bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
+      fi
+   fi
 fi
 if [ "$CONFIG_ARCH_EBSA110" = "y" -o \
      "$CONFIG_ARCH_NETWINDER" = "y" -o \
      "$CONFIG_CATS" = "y" ]; then
-  string 'Initial kernel command string' CONFIG_CMDLINE
+   string 'Initial kernel command string' CONFIG_CMDLINE
 fi
 if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \
      "$CONFIG_ARCH_EBSA110" = "y" -o   \
      "$CONFIG_ARCH_EBSA285" = "y" -o   \
      "$CONFIG_ARCH_CO285" = "y" ]; then
-  bool 'Timer and CPU usage LEDs' CONFIG_LEDS
-  if [ "$CONFIG_LEDS" = "y" ]; then
-    if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \
-         "$CONFIG_ARCH_EBSA285" = "y" -o   \
-	 "$CONFIG_ARCH_CO285" = "y" ]; then
-      bool '  Timer LED' CONFIG_LEDS_TIMER
-      bool '  CPU usage LED' CONFIG_LEDS_CPU
-    fi
-  fi
+   bool 'Timer and CPU usage LEDs' CONFIG_LEDS
+   if [ "$CONFIG_LEDS" = "y" ]; then
+      if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \
+           "$CONFIG_ARCH_EBSA285" = "y" -o   \
+	   "$CONFIG_ARCH_CO285" = "y" ]; then
+	 bool '  Timer LED' CONFIG_LEDS_TIMER
+	 bool '  CPU usage LED' CONFIG_LEDS_CPU
+      fi
+   fi
 fi
 endmenu
 
@@ -179,48 +181,48 @@
 source drivers/block/Config.in
 
 if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
-  source drivers/acorn/block/Config.in
+   source drivers/acorn/block/Config.in
 fi
 
 source drivers/char/Config.in
 if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
-  if [ "$CONFIG_MOUSE" = "y" ]; then
-    if [ "$CONFIG_ARCH_RPC" != "y" ]; then
-      define_bool CONFIG_KBDMOUSE y
-    else
-      define_bool CONFIG_RPCMOUSE y
-    fi
-  fi
+   if [ "$CONFIG_MOUSE" = "y" ]; then
+      if [ "$CONFIG_ARCH_RPC" != "y" ]; then
+	 define_bool CONFIG_KBDMOUSE y
+      else
+	 define_bool CONFIG_RPCMOUSE y
+      fi
+   fi
 fi
 
 source drivers/usb/Config.in
 
 if [ "$CONFIG_VT" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'Console drivers'
-  if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
-    bool 'VGA text console' CONFIG_VGA_CONSOLE
-  fi
-  bool 'Support Frame buffer devices' CONFIG_FB
-  source drivers/video/Config.in
-  endmenu
+   mainmenu_option next_comment
+   comment 'Console drivers'
+   if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
+      bool 'VGA text console' CONFIG_VGA_CONSOLE
+   fi
+   bool 'Support Frame buffer devices' CONFIG_FB
+   source drivers/video/Config.in
+   endmenu
 fi
 
 if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
+   source net/Config.in
 
-  source net/ax25/Config.in
+   source net/ax25/Config.in
 
-  source net/irda/Config.in
+   source net/irda/Config.in
 
-  mainmenu_option next_comment
-  comment 'Network device support'
+   mainmenu_option next_comment
+   comment 'Network device support'
 
-  bool 'Network device support?' CONFIG_NETDEVICES
-  if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    source drivers/net/Config.in
-  fi
-  endmenu
+   bool 'Network device support?' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+   fi
+   endmenu
 fi
 
 # mainmenu_option next_comment
@@ -238,19 +240,19 @@
 tristate 'SCSI support?' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
-  source drivers/scsi/Config.in
+   source drivers/scsi/Config.in
 fi
 endmenu
 
 if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_PCI" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'Sound'
+   mainmenu_option next_comment
+   comment 'Sound'
 
-  tristate 'Sound support' CONFIG_SOUND
-  if [ "$CONFIG_SOUND" != "n" ]; then
-    source drivers/sound/Config.in
-  fi
-  endmenu
+   tristate 'Sound support' CONFIG_SOUND
+   if [ "$CONFIG_SOUND" != "n" ]; then
+      source drivers/sound/Config.in
+   fi
+   endmenu
 fi
 
 source fs/Config.in
diff -u --recursive --new-file v2.3.19/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.3.19/linux/arch/i386/boot/setup.S	Mon Oct  4 15:49:29 1999
+++ linux/arch/i386/boot/setup.S	Thu Oct  7 10:17:08 1999
@@ -641,36 +641,9 @@
 	out	#0xf1,al
 	call	delay
 
-! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
-! we put them right after the intel-reserved hardware interrupts, at
-! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
-! messed this up with the original PC, and they haven't been able to
-! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
-! which is used for the internal hardware interrupts as well. We just
-! have to reprogram the 8259's, and it isn't fun.
+! well, that went ok, I hope. Now we mask all interrupts - the rest
+! is done in init_IRQ().
 
-	mov	al,#0x11		! initialization sequence
-	out	#0x20,al		! send it to 8259A-1
-	call	delay
-	out	#0xA0,al		! and to 8259A-2
-	call	delay
-	mov	al,#0x20		! start of hardware int's (0x20)
-	out	#0x21,al
-	call	delay
-	mov	al,#0x28		! start of hardware int's 2 (0x28)
-	out	#0xA1,al
-	call	delay
-	mov	al,#0x04		! 8259-1 is master
-	out	#0x21,al
-	call	delay
-	mov	al,#0x02		! 8259-2 is slave
-	out	#0xA1,al
-	call	delay
-	mov	al,#0x01		! 8086 mode for both
-	out	#0x21,al
-	call	delay
-	out	#0xA1,al
-	call	delay
 	mov	al,#0xFF		! mask off all interrupts for now
 	out	#0xA1,al
 	call	delay
diff -u --recursive --new-file v2.3.19/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.19/linux/arch/i386/config.in	Tue Sep  7 12:14:06 1999
+++ linux/arch/i386/config.in	Fri Oct  8 10:06:21 1999
@@ -59,29 +59,30 @@
 
 bool 'BIGMEM support' CONFIG_BIGMEM
 bool 'Networking support' CONFIG_NET
-bool 'PCI support' CONFIG_PCI
-if [ "$CONFIG_PCI" = "y" ]; then
-  choice 'PCI access mode' \
-	"BIOS		CONFIG_PCI_GOBIOS	\
-	 Direct		CONFIG_PCI_GODIRECT	\
-	 Any		CONFIG_PCI_GOANY"	Any
-  if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
-    define_bool CONFIG_PCI_BIOS y
-  fi
-  if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
-    define_bool CONFIG_PCI_DIRECT y
-  fi
-fi
-bool 'MCA support' CONFIG_MCA
 bool 'SGI Visual Workstation support' CONFIG_VISWS
 if [ "$CONFIG_VISWS" = "y" ]; then
   define_bool CONFIG_X86_VISWS_APIC y
   define_bool CONFIG_X86_LOCAL_APIC y
+  define_bool CONFIG_PCI y
 else
   if [ "$CONFIG_SMP" = "y" ]; then
     define_bool CONFIG_X86_IO_APIC y
     define_bool CONFIG_X86_LOCAL_APIC y
   fi
+  bool 'PCI support' CONFIG_PCI
+  if [ "$CONFIG_PCI" = "y" ]; then
+    choice 'PCI access mode' \
+	"BIOS		CONFIG_PCI_GOBIOS	\
+	 Direct		CONFIG_PCI_GODIRECT	\
+	 Any		CONFIG_PCI_GOANY"	Any
+    if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
+      define_bool CONFIG_PCI_BIOS y
+    fi
+    if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
+      define_bool CONFIG_PCI_DIRECT y
+    fi
+  fi
+  bool 'MCA support' CONFIG_MCA
 fi
 
 source drivers/pcmcia/Config.in
diff -u --recursive --new-file v2.3.19/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.19/linux/arch/i386/defconfig	Mon Oct  4 15:49:29 1999
+++ linux/arch/i386/defconfig	Thu Oct  7 13:05:00 1999
@@ -360,6 +360,7 @@
 #
 # Misc devices
 #
+CONFIG_ACPI=y
 
 #
 # Filesystems
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v2.3.19/linux/arch/i386/kernel/Makefile	Thu Aug 26 13:05:34 1999
+++ linux/arch/i386/kernel/Makefile	Fri Oct  8 10:06:21 1999
@@ -19,7 +19,12 @@
 MX_OBJS  :=
 
 ifdef CONFIG_PCI
-O_OBJS += bios32.o
+O_OBJS += pci-i386.o
+ifdef CONFIG_VISWS
+O_OBJS += pci-visws.o
+else
+O_OBJS += pci-pc.o
+endif
 endif
 
 ifdef CONFIG_MCA
@@ -43,7 +48,7 @@
 endif
 
 ifdef CONFIG_SMP
-O_OBJS += smp.o trampoline.o
+O_OBJS += smp.o smpboot.o trampoline.o
 endif
 
 ifdef CONFIG_X86_IO_APIC
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- v2.3.19/linux/arch/i386/kernel/bios32.c	Fri Sep 10 23:57:27 1999
+++ linux/arch/i386/kernel/bios32.c	Wed Dec 31 16:00:00 1969
@@ -1,1220 +0,0 @@
-/*
- * bios32.c - Low-Level PCI Access
- *
- * $Id: bios32.c,v 1.48 1998/09/26 08:06:55 mj Exp $
- *
- * Copyright 1993, 1994 Drew Eckhardt
- *      Visionary Computing
- *      (Unix and Linux consulting and custom programming)
- *      Drew@Colorado.EDU
- *      +1 (303) 786-7975
- *
- * Drew's work was sponsored by:
- *	iX Multiuser Multitasking Magazine
- *	Hannover, Germany
- *	hm@ix.de
- *
- * Copyright 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
- * For more information, please consult the following manuals (look at
- * http://www.pcisig.com/ for how to get them):
- *
- * PCI BIOS Specification
- * PCI Local Bus Specification
- * PCI to PCI Bridge Specification
- * PCI System Design Guide
- *
- *
- * CHANGELOG :
- * Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
- *	Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
- *
- * Jan 5,  1995 : Modified to probe PCI hardware at boot time by Frederic
- *     Potter, potter@cao-vlsi.ibp.fr
- *
- * Jan 10, 1995 : Modified to store the information about configured pci
- *      devices into a list, which can be accessed via /proc/pci by
- *      Curtis Varner, cvarner@cs.ucr.edu
- *
- * Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
- *	Alpha version. Intel & UMC chipset support only.
- *
- * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
- *	moved to drivers/pci/pci.c.
- *
- * Dec 7, 1996  : Added support for direct configuration access of boards
- *      with Intel compatible access schemes (tsbogend@alpha.franken.de)
- *
- * Feb 3, 1997  : Set internal functions to static, save/restore flags
- *	avoid dead locks reading broken PCI BIOS, werner@suse.de 
- *
- * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
- *	(mj@atrey.karlin.mff.cuni.cz)
- *
- * May 7,  1997 : Added some missing cli()'s. [mj]
- * 
- * Jun 20, 1997 : Corrected problems in "conf1" type accesses.
- *      (paubert@iram.es)
- *
- * Aug 2,  1997 : Split to PCI BIOS handling and direct PCI access parts
- *	and cleaned it up...     Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
- * Feb 6,  1998 : No longer using BIOS to find devices and device classes. [mj]
- *
- * May 1,  1998 : Support for peer host bridges. [mj]
- *
- * Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
- *	can be accessed from interrupts even on SMP systems. [mj]
- *
- * August  1998 : Better support for peer host bridges and more paranoid
- *	checks for direct hardware access. Ugh, this file starts to look as
- *	a large gallery of common hardware bug workarounds (watch the comments)
- *	-- the PCI specs themselves are sane, but most implementors should be
- *	hit hard with \hammer scaled \magstep5. [mj]
- *
- * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
- *
- * Feb 8,  1999 : Added UM8886BF I/O address fixup. [mj]
- *
- * August  1999 : New resource management and configuration access stuff. [mj]
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/smp_lock.h>
-#include <linux/irq.h>
-#include <linux/spinlock.h>
-
-#include <asm/page.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-#define PCI_PROBE_BIOS 1
-#define PCI_PROBE_CONF1 2
-#define PCI_PROBE_CONF2 4
-#define PCI_NO_SORT 0x100
-#define PCI_BIOS_SORT 0x200
-#define PCI_NO_CHECKS 0x400
-#define PCI_NO_PEER_FIXUP 0x800
-#define PCI_ASSIGN_ROMS 0x1000
-
-static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
-
-/*
- * Direct access to PCI hardware...
- */
-
-#ifdef CONFIG_PCI_DIRECT
-
-/*
- * Functions for accessing PCI configuration space with type 1 accesses
- */
-
-#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
-
-static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-    outl(CONFIG_CMD(dev,where), 0xCF8);
-    *value = inb(0xCFC + (where&3));
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-    outl(CONFIG_CMD(dev,where), 0xCF8);    
-    *value = inw(0xCFC + (where&2));
-    return PCIBIOS_SUCCESSFUL;    
-}
-
-static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-    outl(CONFIG_CMD(dev,where), 0xCF8);
-    *value = inl(0xCFC);
-    return PCIBIOS_SUCCESSFUL;    
-}
-
-static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-    outl(CONFIG_CMD(dev,where), 0xCF8);    
-    outb(value, 0xCFC + (where&3));
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-    outl(CONFIG_CMD(dev,where), 0xCF8);
-    outw(value, 0xCFC + (where&2));
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-    outl(CONFIG_CMD(dev,where), 0xCF8);
-    outl(value, 0xCFC);
-    return PCIBIOS_SUCCESSFUL;
-}
-
-#undef CONFIG_CMD
-
-static struct pci_ops pci_direct_conf1 = {
-      pci_conf1_read_config_byte,
-      pci_conf1_read_config_word,
-      pci_conf1_read_config_dword,
-      pci_conf1_write_config_byte,
-      pci_conf1_write_config_word,
-      pci_conf1_write_config_dword
-};
-
-/*
- * Functions for accessing PCI configuration space with type 2 accesses
- */
-
-#define IOADDR(devfn, where)	((0xC000 | ((devfn & 0x78) << 5)) + where)
-#define FUNC(devfn)		(((devfn & 7) << 1) | 0xf0)
-#define SET(dev)		if (dev->devfn) return PCIBIOS_DEVICE_NOT_FOUND;		\
-				outb(FUNC(dev->devfn), 0xCF8);					\
-				outb(dev->bus->number, 0xCFA);
-
-static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-    SET(dev);
-    *value = inb(IOADDR(dev->devfn,where));
-    outb (0, 0xCF8);
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-    SET(dev);
-    *value = inw(IOADDR(dev->devfn,where));
-    outb (0, 0xCF8);
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-    SET(dev);
-    *value = inl (IOADDR(dev->devfn,where));    
-    outb (0, 0xCF8);    
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-    SET(dev);
-    outb (value, IOADDR(dev->devfn,where));
-    outb (0, 0xCF8);    
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-    SET(dev);
-    outw (value, IOADDR(dev->devfn,where));
-    outb (0, 0xCF8);    
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-    SET(dev);
-    outl (value, IOADDR(dev->devfn,where));    
-    outb (0, 0xCF8);    
-    return PCIBIOS_SUCCESSFUL;
-}
-
-#undef SET
-#undef IOADDR
-#undef FUNC
-
-static struct pci_ops pci_direct_conf2 = {
-      pci_conf2_read_config_byte,
-      pci_conf2_read_config_word,
-      pci_conf2_read_config_dword,
-      pci_conf2_write_config_byte,
-      pci_conf2_write_config_word,
-      pci_conf2_write_config_dword
-};
-
-/*
- * Before we decide to use direct hardware access mechanisms, we try to do some
- * trivial checks to ensure it at least _seems_ to be working -- we just test
- * whether bus 00 contains a host bridge (this is similar to checking
- * techniques used in XFree86, but ours should be more reliable since we
- * attempt to make use of direct access hints provided by the PCI BIOS).
- *
- * This should be close to trivial, but it isn't, because there are buggy
- * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
- */
-static int __init pci_sanity_check(struct pci_ops *o)
-{
-	u16 x;
-	struct pci_bus bus;		/* Fake bus and device */
-	struct pci_dev dev;
-
-#ifdef CONFIG_VISWS
-	return 1;       /* Lithium PCI Bridges are non-standard */
-#endif
-
-	if (pci_probe & PCI_NO_CHECKS)
-		return 1;
-	bus.number = 0;
-	dev.bus = &bus;
-	for(dev.devfn=0; dev.devfn < 0x100; dev.devfn++)
-		if ((!o->read_word(&dev, PCI_CLASS_DEVICE, &x) &&
-		     (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
-		    (!o->read_word(&dev, PCI_VENDOR_ID, &x) &&
-		     (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
-			return 1;
-	DBG("PCI: Sanity check failed\n");
-	return 0;
-}
-
-static struct pci_ops * __init pci_check_direct(void)
-{
-	unsigned int tmp;
-	unsigned long flags;
-
-	__save_flags(flags); __cli();
-
-	/*
-	 * Check if configuration type 1 works.
-	 */
-	if (pci_probe & PCI_PROBE_CONF1) {
-		outb (0x01, 0xCFB);
-		tmp = inl (0xCF8);
-		outl (0x80000000, 0xCF8);
-		if (inl (0xCF8) == 0x80000000 &&
-		    pci_sanity_check(&pci_direct_conf1)) {
-			outl (tmp, 0xCF8);
-			__restore_flags(flags);
-			printk("PCI: Using configuration type 1\n");
-			return &pci_direct_conf1;
-		}
-		outl (tmp, 0xCF8);
-	}
-
-	/*
-	 * Check if configuration type 2 works.
-	 */
-	if (pci_probe & PCI_PROBE_CONF2) {
-		outb (0x00, 0xCFB);
-		outb (0x00, 0xCF8);
-		outb (0x00, 0xCFA);
-		if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 &&
-		    pci_sanity_check(&pci_direct_conf2)) {
-			__restore_flags(flags);
-			printk("PCI: Using configuration type 2\n");
-			return &pci_direct_conf2;
-		}
-	}
-
-	__restore_flags(flags);
-	return NULL;
-}
-
-#endif
-
-/*
- * BIOS32 and PCI BIOS handling.
- */
-
-#ifdef CONFIG_PCI_BIOS
-
-#define PCIBIOS_PCI_FUNCTION_ID 	0xb1XX
-#define PCIBIOS_PCI_BIOS_PRESENT 	0xb101
-#define PCIBIOS_FIND_PCI_DEVICE		0xb102
-#define PCIBIOS_FIND_PCI_CLASS_CODE	0xb103
-#define PCIBIOS_GENERATE_SPECIAL_CYCLE	0xb106
-#define PCIBIOS_READ_CONFIG_BYTE	0xb108
-#define PCIBIOS_READ_CONFIG_WORD	0xb109
-#define PCIBIOS_READ_CONFIG_DWORD	0xb10a
-#define PCIBIOS_WRITE_CONFIG_BYTE	0xb10b
-#define PCIBIOS_WRITE_CONFIG_WORD	0xb10c
-#define PCIBIOS_WRITE_CONFIG_DWORD	0xb10d
-
-/* BIOS32 signature: "_32_" */
-#define BIOS32_SIGNATURE	(('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
-
-/* PCI signature: "PCI " */
-#define PCI_SIGNATURE		(('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
-
-/* PCI service signature: "$PCI" */
-#define PCI_SERVICE		(('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
-
-/* PCI BIOS hardware mechanism flags */
-#define PCIBIOS_HW_TYPE1		0x01
-#define PCIBIOS_HW_TYPE2		0x02
-#define PCIBIOS_HW_TYPE1_SPEC		0x10
-#define PCIBIOS_HW_TYPE2_SPEC		0x20
-
-/*
- * This is the standard structure used to identify the entry point
- * to the BIOS32 Service Directory, as documented in
- * 	Standard BIOS 32-bit Service Directory Proposal
- * 	Revision 0.4 May 24, 1993
- * 	Phoenix Technologies Ltd.
- *	Norwood, MA
- * and the PCI BIOS specification.
- */
-
-union bios32 {
-	struct {
-		unsigned long signature;	/* _32_ */
-		unsigned long entry;		/* 32 bit physical address */
-		unsigned char revision;		/* Revision level, 0 */
-		unsigned char length;		/* Length in paragraphs should be 01 */
-		unsigned char checksum;		/* All bytes must add up to zero */
-		unsigned char reserved[5]; 	/* Must be zero */
-	} fields;
-	char chars[16];
-};
-
-/*
- * Physical address of the service directory.  I don't know if we're
- * allowed to have more than one of these or not, so just in case
- * we'll make pcibios_present() take a memory start parameter and store
- * the array there.
- */
-
-static struct {
-	unsigned long address;
-	unsigned short segment;
-} bios32_indirect = { 0, __KERNEL_CS };
-
-/*
- * Returns the entry point for the given service, NULL on error
- */
-
-static unsigned long bios32_service(unsigned long service)
-{
-	unsigned char return_code;	/* %al */
-	unsigned long address;		/* %ebx */
-	unsigned long length;		/* %ecx */
-	unsigned long entry;		/* %edx */
-	unsigned long flags;
-
-	__save_flags(flags); __cli();
-	__asm__("lcall (%%edi)"
-		: "=a" (return_code),
-		  "=b" (address),
-		  "=c" (length),
-		  "=d" (entry)
-		: "0" (service),
-		  "1" (0),
-		  "D" (&bios32_indirect));
-	__restore_flags(flags);
-
-	switch (return_code) {
-		case 0:
-			return address + entry;
-		case 0x80:	/* Not present */
-			printk("bios32_service(0x%lx): not present\n", service);
-			return 0;
-		default: /* Shouldn't happen */
-			printk("bios32_service(0x%lx): returned 0x%x, report to <mj@ucw.cz>.\n",
-				service, return_code);
-			return 0;
-	}
-}
-
-static struct {
-	unsigned long address;
-	unsigned short segment;
-} pci_indirect = { 0, __KERNEL_CS };
-
-static int pci_bios_present;
-
-static int __init check_pcibios(void)
-{
-	u32 signature, eax, ebx, ecx;
-	u8 status, major_ver, minor_ver, hw_mech, last_bus;
-	unsigned long flags, pcibios_entry;
-
-	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
-		pci_indirect.address = pcibios_entry + PAGE_OFFSET;
-
-		__save_flags(flags); __cli();
-		__asm__(
-			"lcall (%%edi)\n\t"
-			"jc 1f\n\t"
-			"xor %%ah, %%ah\n"
-			"1:"
-			: "=d" (signature),
-			  "=a" (eax),
-			  "=b" (ebx),
-			  "=c" (ecx)
-			: "1" (PCIBIOS_PCI_BIOS_PRESENT),
-			  "D" (&pci_indirect)
-			: "memory");
-		__restore_flags(flags);
-
-		status = (eax >> 8) & 0xff;
-		hw_mech = eax & 0xff;
-		major_ver = (ebx >> 8) & 0xff;
-		minor_ver = ebx & 0xff;
-		last_bus = ecx & 0xff;
-		DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
-			status, hw_mech, major_ver, minor_ver, last_bus);
-		if (status || signature != PCI_SIGNATURE) {
-			printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found, report to <mj@ucw.cz>\n",
-				status, signature);
-			return 0;
-		}
-		printk("PCI: PCI BIOS revision %x.%02x entry at 0x%lx\n",
-			major_ver, minor_ver, pcibios_entry);
-#ifdef CONFIG_PCI_DIRECT
-		if (!(hw_mech & PCIBIOS_HW_TYPE1))
-			pci_probe &= ~PCI_PROBE_CONF1;
-		if (!(hw_mech & PCIBIOS_HW_TYPE2))
-			pci_probe &= ~PCI_PROBE_CONF2;
-#endif
-		return 1;
-	}
-	return 0;
-}
-
-#if 0	/* Not used */
-
-static int pci_bios_find_class (unsigned int class_code, unsigned short index,
-	unsigned char *bus, unsigned char *device_fn)
-{
-	unsigned long bx;
-	unsigned long ret;
-
-	__asm__ ("lcall (%%edi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=b" (bx),
-		  "=a" (ret)
-		: "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
-		  "c" (class_code),
-		  "S" ((int) index),
-		  "D" (&pci_indirect));
-	*bus = (bx >> 8) & 0xff;
-	*device_fn = bx & 0xff;
-	return (int) (ret & 0xff00) >> 8;
-}
-
-#endif
-
-static int __init pci_bios_find_device (unsigned short vendor, unsigned short device_id,
-					unsigned short index, unsigned char *bus, unsigned char *device_fn)
-{
-	unsigned short bx;
-	unsigned short ret;
-
-	__asm__("lcall (%%edi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=b" (bx),
-		  "=a" (ret)
-		: "1" (PCIBIOS_FIND_PCI_DEVICE),
-		  "c" (device_id),
-		  "d" (vendor),
-		  "S" ((int) index),
-		  "D" (&pci_indirect));
-	*bus = (bx >> 8) & 0xff;
-	*device_fn = bx & 0xff;
-	return (int) (ret & 0xff00) >> 8;
-}
-
-static int pci_bios_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-	unsigned long ret;
-	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
-
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=c" (*value),
-		  "=a" (ret)
-		: "1" (PCIBIOS_READ_CONFIG_BYTE),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	return (int) (ret & 0xff00) >> 8;
-}
-
-static int pci_bios_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	unsigned long ret;
-	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
-
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=c" (*value),
-		  "=a" (ret)
-		: "1" (PCIBIOS_READ_CONFIG_WORD),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	return (int) (ret & 0xff00) >> 8;
-}
-
-static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	unsigned long ret;
-	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
-
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=c" (*value),
-		  "=a" (ret)
-		: "1" (PCIBIOS_READ_CONFIG_DWORD),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	return (int) (ret & 0xff00) >> 8;
-}
-
-static int pci_bios_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	unsigned long ret;
-	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
-
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=a" (ret)
-		: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
-		  "c" (value),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	return (int) (ret & 0xff00) >> 8;
-}
-
-static int pci_bios_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	unsigned long ret;
-	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
-
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=a" (ret)
-		: "0" (PCIBIOS_WRITE_CONFIG_WORD),
-		  "c" (value),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	return (int) (ret & 0xff00) >> 8;
-}
-
-static int pci_bios_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-	unsigned long ret;
-	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
-
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=a" (ret)
-		: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
-		  "c" (value),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	return (int) (ret & 0xff00) >> 8;
-}
-
-/*
- * Function table for BIOS32 access
- */
-
-static struct pci_ops pci_bios_access = {
-      pci_bios_read_config_byte,
-      pci_bios_read_config_word,
-      pci_bios_read_config_dword,
-      pci_bios_write_config_byte,
-      pci_bios_write_config_word,
-      pci_bios_write_config_dword
-};
-
-/*
- * Try to find PCI BIOS.
- */
-
-static struct pci_ops * __init pci_find_bios(void)
-{
-	union bios32 *check;
-	unsigned char sum;
-	int i, length;
-
-	/*
-	 * Follow the standard procedure for locating the BIOS32 Service
-	 * directory by scanning the permissible address range from
-	 * 0xe0000 through 0xfffff for a valid BIOS32 structure.
-	 */
-
-	for (check = (union bios32 *) __va(0xe0000);
-	     check <= (union bios32 *) __va(0xffff0);
-	     ++check) {
-		if (check->fields.signature != BIOS32_SIGNATURE)
-			continue;
-		length = check->fields.length * 16;
-		if (!length)
-			continue;
-		sum = 0;
-		for (i = 0; i < length ; ++i)
-			sum += check->chars[i];
-		if (sum != 0)
-			continue;
-		if (check->fields.revision != 0) {
-			printk("PCI: unsupported BIOS32 revision %d at 0x%p, report to <mj@ucw.cz>\n",
-				check->fields.revision, check);
-			continue;
-		}
-		DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
-		if (check->fields.entry >= 0x100000) {
-			printk("PCI: BIOS32 entry (0x%p) in high memory, cannot use.\n", check);
-			return NULL;
-		} else {
-			unsigned long bios32_entry = check->fields.entry;
-			DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
-			bios32_indirect.address = bios32_entry + PAGE_OFFSET;
-			if (check_pcibios())
-				return &pci_bios_access;
-		}
-		break;	/* Hopefully more than one BIOS32 cannot happen... */
-	}
-
-	return NULL;
-}
-
-/*
- * Sort the device list according to PCI BIOS. Nasty hack, but since some
- * fool forgot to define the `correct' device order in the PCI BIOS specs
- * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
- * which used BIOS ordering, we are bound to do this...
- */
-
-static void __init pcibios_sort(void)
-{
-	struct pci_dev *dev = pci_devices;
-	struct pci_dev **last = &pci_devices;
-	struct pci_dev *d, **dd, *e;
-	int idx;
-	unsigned char bus, devfn;
-
-	DBG("PCI: Sorting device list...\n");
-	while ((e = dev)) {
-		idx = 0;
-		while (pci_bios_find_device(e->vendor, e->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
-			idx++;
-			for(dd=&dev; (d = *dd); dd = &d->next) {
-				if (d->bus->number == bus && d->devfn == devfn) {
-					*dd = d->next;
-					*last = d;
-					last = &d->next;
-					break;
-				}
-			}
-			if (!d) {
-				printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
-				/*
-				 * We must not continue scanning as several buggy BIOSes
-				 * return garbage after the last device. Grr.
-				 */
-				break;
-			}
-		}
-		if (e == dev) {
-			printk("PCI: Device %02x:%02x not found by BIOS\n",
-				dev->bus->number, dev->devfn);
-			d = dev;
-			dev = dev->next;
-			*last = d;
-			last = &d->next;
-		}
-	}
-	*last = NULL;
-}
-
-#endif
-
-/*
- * Several BIOS'es forget to assign addresses to I/O ranges. Try to fix it.
- */
-
-static void __init pcibios_fixup_io_addr(struct pci_dev *dev, int idx)
-{
-	unsigned int reg = PCI_BASE_ADDRESS_0 + 4*idx;
-	struct resource *r = &dev->resource[idx];
-	unsigned int size = r->end - r->start + 1;
-
-	if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) ||
-	     (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
-		/*
-		 * In case the BIOS didn't assign an address 0--3 to an IDE
-		 * controller, we don't try to fix it as it means "use default
-		 * addresses" at least with several broken chips and the IDE
-		 * driver needs the original settings to recognize which devices
-		 * correspond to the primary controller.
-		 *
-		 * We don't assign VGA I/O ranges as well.
-		 */
-		return;
-	}
-	/*
-	 * We need to avoid collisions with `mirrored' VGA ports and other strange
-	 * ISA hardware, so we always want the addresses kilobyte aligned.
-	 */
-	if (!size || size > 256) {
-		printk(KERN_ERR "PCI: Cannot assign I/O space to device %s, %d bytes are too much.\n", dev->name, size);
-		return;
-	} else {
-		u32 try;
-
-		r->start = 0;
-		r->end = size - 1;
-		if (pci_assign_resource(dev, idx)) {
-			printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O space for device %s.\n", size, dev->name);
-			return;
-		}
-		printk("PCI: Assigned I/O space %04lx-%04lx to device %s\n", r->start, r->end, dev->name);
-		pci_read_config_dword(dev, reg, &try);
-		if ((try & PCI_BASE_ADDRESS_IO_MASK) != r->start) {
-			r->start = 0;
-			pci_write_config_dword(dev, reg, 0);
-			printk(KERN_ERR "PCI: I/O address setup failed, got %04x\n", try);
-		}
-	}
-}
-
-/*
- * Assign address to expansion ROM. This is a highly experimental feature
- * and you must enable it by "pci=rom". It's even not guaranteed to work
- * with all cards since the PCI specs allow address decoders to be shared
- * between the ROM space and one of the standard regions (sigh!).
- */
-static void __init pcibios_fixup_rom_addr(struct pci_dev *dev)
-{
-	int reg = (dev->hdr_type == 1) ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
-	struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
-	unsigned long rom_size = r->end - r->start + 1;
-
-	r->start = 0;
-	r->end = rom_size - 1;
-	if (pci_assign_resource(dev, PCI_ROM_RESOURCE))
-		printk(KERN_ERR "PCI: Unable to find free space for expansion ROM of device %s (0x%lx bytes)\n",
-		       dev->name, rom_size);
-	else {
-		DBG("PCI: Assigned address %08lx to expansion ROM of %s (0x%lx bytes)\n", r->start, dev->name, rom_size);
-		pci_write_config_dword(dev, reg, r->start | PCI_ROM_ADDRESS_ENABLE);
-		r->flags |= PCI_ROM_ADDRESS_ENABLE;
-	}
-}
-
-/*
- * Several buggy motherboards address only 16 devices and mirror
- * them to next 16 IDs. We try to detect this `feature' on all
- * primary busses (those containing host bridges as they are
- * expected to be unique) and remove the ghost devices.
- */
-
-static void __init pcibios_fixup_ghosts(struct pci_bus *b)
-{
-	struct pci_dev *d, *e, **z;
-	int mirror = PCI_DEVFN(16,0);
-	int seen_host_bridge = 0;
-	int i;
-
-	DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
-	for(d=b->devices; d && d->devfn < mirror; d=d->sibling) {
-		if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
-			seen_host_bridge++;
-		for(e=d->next; e; e=e->sibling) {
-			if (e->devfn != d->devfn + mirror ||
-			    e->vendor != d->vendor ||
-			    e->device != d->device ||
-			    e->class != d->class)
-				continue;
-			for(i=0; i<PCI_NUM_RESOURCES; i++)
-				if (e->resource[i].start != d->resource[i].start ||
-				    e->resource[i].end != d->resource[i].end ||
-				    e->resource[i].flags != d->resource[i].flags)
-					continue;
-			break;
-		}
-		if (!e)
-			return;
-	}
-	if (!seen_host_bridge)
-		return;
-	printk("PCI: Ignoring ghost devices on bus %d\n", b->number);
-	for(e=b->devices; e->sibling != d; e=e->sibling);
-	e->sibling = NULL;
-	for(z=&pci_devices; (d=*z);)
-		if (d->bus == b && d->devfn >= mirror) {
-			*z = d->next;
-			kfree_s(d, sizeof(*d));
-		} else
-			z = &d->next;
-}
-
-/*
- * In case there are peer host bridges, scan bus behind each of them.
- * Although several sources claim that the host bridges should have
- * header type 1 and be assigned a bus number as for PCI2PCI bridges,
- * the reality doesn't pass this test and the bus number is usually
- * set by BIOS to the first free value.
- */
-static void __init pcibios_fixup_peer_bridges(void)
-{
-	struct pci_bus *b = pci_root;
-	int n, cnt=-1;
-	struct pci_dev *d;
-	struct pci_ops *ops = pci_root->ops;
-
-#ifdef CONFIG_VISWS
-	pci_scan_bus(1, ops, NULL);
-	return;
-#endif
-
-#ifdef CONFIG_PCI_DIRECT
-	/*
-	 * Don't search for peer host bridges if we use config type 2
-	 * since it reads bogus values for non-existent busses and
-	 * chipsets supporting multiple primary busses use conf1 anyway.
-	 */
-	if (ops == &pci_direct_conf2)
-		return;
-#endif
-
-	for(d=b->devices; d; d=d->sibling)
-		if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
-			cnt++;
-	n = b->subordinate + 1;
-	while (n <= 0xff) {
-		int found = 0;
-		u16 l;
-		struct pci_bus bus;
-		struct pci_dev dev;
-		bus.number = n;
-		bus.ops = ops;
-		dev.bus = &bus;
-		for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
-			if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
-			    l != 0x0000 && l != 0xffff) {
-#ifdef CONFIG_PCI_BIOS
-				if (pci_bios_present) {
-					int err, idx = 0;
-					u8 bios_bus, bios_dfn;
-					u16 d;
-					pci_read_config_word(&dev, PCI_DEVICE_ID, &d);
-					DBG("BIOS test for %02x:%02x (%04x:%04x)\n", n, dev.devfn, l, d);
-					while (!(err = pci_bios_find_device(l, d, idx, &bios_bus, &bios_dfn)) &&
-					       (bios_bus != n || bios_dfn != dev.devfn))
-						idx++;
-					if (err)
-						break;
-				}
-#endif
-				DBG("Found device at %02x:%02x\n", n, dev.devfn);
-				found++;
-				if (!pci_read_config_word(&dev, PCI_CLASS_DEVICE, &l) &&
-				    l == PCI_CLASS_BRIDGE_HOST)
-					cnt++;
-			}
-		if (cnt-- <= 0)
-			break;
-		if (found) {
-			printk("PCI: Discovered primary peer bus %02x\n", n);
-			b = pci_scan_bus(n, ops, NULL);
-			if (b)
-				n = b->subordinate;
-		}
-		n++;
-	}
-}
-
-/*
- * Exceptions for specific devices. Usually work-arounds for fatal design flaws.
- */
-
-static void __init pci_fixup_i450nx(struct pci_dev *d)
-{
-	/*
-	 * i450NX -- Find and scan all secondary buses on all PXB's.
-	 */
-	int pxb, reg;
-	u8 busno, suba, subb;
-	printk("PCI: Searching for i450NX host bridges on %s\n", d->name);
-	reg = 0xd0;
-	for(pxb=0; pxb<2; pxb++) {
-		pci_read_config_byte(d, reg++, &busno);
-		pci_read_config_byte(d, reg++, &suba);
-		pci_read_config_byte(d, reg++, &subb);
-		DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
-		if (busno)
-			pci_scan_bus(busno, pci_root->ops, NULL);	/* Bus A */
-		if (suba < subb)
-			pci_scan_bus(suba+1, pci_root->ops, NULL);	/* Bus B */
-	}
-	pci_probe |= PCI_NO_PEER_FIXUP;
-}
-
-static void __init pci_fixup_umc_ide(struct pci_dev *d)
-{
-	/*
-	 * UM8886BF IDE controller sets region type bits incorrectly,
-	 * therefore they look like memory despite of them being I/O.
-	 */
-	int i;
-
-	printk("PCI: Fixing base address flags for device %s\n", d->name);
-	for(i=0; i<4; i++)
-		d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
-}
-
-struct pci_fixup pcibios_fixups[] = {
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_UMC,	PCI_DEVICE_ID_UMC_UM8886BF,	pci_fixup_umc_ide },
-	{ 0 }
-};
-
-/*
- * Allocate resources for all PCI devices. We need to do that before
- * we try to fix up anything.
- */
-
-static void __init pcibios_claim_resources(struct pci_bus *bus)
-{
-	struct pci_dev *dev;
-	int idx;
-
-	while (bus) {
-		for (dev=bus->devices; dev; dev=dev->sibling)
-			for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
-				struct resource *r = &dev->resource[idx];
-				struct resource *pr;
-				if (!r->start)
-					continue;
-				pr = pci_find_parent_resource(dev, r);
-				if (!pr || request_resource(pr, r) < 0) {
-					printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name);
-					/* We probably should disable the region, shouldn't we? */
-				}
-		}
-		if (bus->children)
-			pcibios_claim_resources(bus->children);
-		bus = bus->next;
-	}
-}
-
-/*
- * Fix base addresses, I/O and memory enables and IRQ's (mostly work-arounds
- * for buggy PCI BIOS'es :-[).
- */
-
-extern int skip_ioapic_setup;
-
-static void __init pcibios_fixup_devices(void)
-{
-	struct pci_dev *dev;
-	int i, has_io, has_mem;
-	unsigned short cmd;
-
-	for(dev = pci_devices; dev; dev=dev->next) {
-		/*
-		 * There are buggy BIOSes that forget to enable I/O and memory
-		 * access to PCI devices. We try to fix this, but we need to
-		 * be sure that the BIOS didn't forget to assign an address
-		 * to the device. [mj]
-		 */
-		has_io = has_mem = 0;
-		for(i=0; i<6; i++) {
-			struct resource *r = &dev->resource[i];
-			if (r->flags & PCI_BASE_ADDRESS_SPACE_IO) {
-				has_io = 1;
-				if (!r->start || r->start == PCI_BASE_ADDRESS_IO_MASK)
-					pcibios_fixup_io_addr(dev, i);
-			} else if (r->start)
-				has_mem = 1;
-		}
-		/*
-		 * Don't enable VGA-compatible cards since they have
-		 * fixed I/O and memory space.
-		 * 
-		 * Don't enabled disabled IDE interfaces either because
-		 * some BIOSes may reallocate the same address when they
-		 * find that no devices are attached. 
-		 */
-		if (((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) &&
-		    ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)) {
-			pci_read_config_word(dev, PCI_COMMAND, &cmd);
-			if (has_io && !(cmd & PCI_COMMAND_IO)) {
-				printk("PCI: Enabling I/O for device %s\n", dev->name);
-				cmd |= PCI_COMMAND_IO;
-				pci_write_config_word(dev, PCI_COMMAND, cmd);
-			}
-			if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) {
-				printk("PCI: Enabling memory for device %s\n", dev->name);
-				cmd |= PCI_COMMAND_MEMORY;
-				pci_write_config_word(dev, PCI_COMMAND, cmd);
-			}
-		}
-		/*
-		 * Assign address to expansion ROM if requested.
-		 */
-		if ((pci_probe & PCI_ASSIGN_ROMS) && dev->resource[PCI_ROM_RESOURCE].end)
-			pcibios_fixup_rom_addr(dev);
-#if defined(CONFIG_X86_IO_APIC)
-		/*
-		 * Recalculate IRQ numbers if we use the I/O APIC
-		 */
-		if(!skip_ioapic_setup)
-		{
-			int irq;
-			unsigned char pin;
-
-			pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-			if (pin) {
-				pin--;		/* interrupt pins are numbered starting from 1 */
-				irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
-				if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
-					struct pci_dev * bridge = dev->bus->self;
-
-					pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-					irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
-							PCI_SLOT(bridge->devfn), pin);
-					if (irq >= 0)
-						printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
-							bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
-				}
-				if (irq >= 0) {
-					printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
-						dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
-					dev->irq = irq;
-				}
-			}
-		}
-#endif
-		/*
-		 * Fix out-of-range IRQ numbers
-		 */
-		if (dev->irq >= NR_IRQS)
-			dev->irq = 0;
-	}
-}
-
-/*
- *  Called after each bus is probed, but before its children
- *  are examined.
- */
-
-void __init pcibios_fixup_bus(struct pci_bus *b)
-{
-	pcibios_fixup_ghosts(b);
-}
-
-/*
- * Initialization. Try all known PCI access methods. Note that we support
- * using both PCI BIOS and direct access: in such cases, we use I/O ports
- * to access config space, but we still keep BIOS order of cards to be
- * compatible with 2.0.X. This should go away some day.
- */
-
-void __init pcibios_init(void)
-{
-	struct pci_ops *bios = NULL;
-	struct pci_ops *dir = NULL;
-	struct pci_ops *ops;
-
-#ifdef CONFIG_PCI_BIOS
-	if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) {
-		pci_probe |= PCI_BIOS_SORT;
-		pci_bios_present = 1;
-	}
-#endif
-#ifdef CONFIG_PCI_DIRECT
-	if (pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2))
-		dir = pci_check_direct();
-#endif
-	if (dir)
-		ops = dir;
-	else if (bios)
-		ops = bios;
-	else {
-		printk("PCI: No PCI bus detected\n");
-		return;
-	}
-
-	printk("PCI: Probing PCI hardware\n");
-	pci_scan_bus(0, ops, NULL);
-
-	if (!(pci_probe & PCI_NO_PEER_FIXUP))
-		pcibios_fixup_peer_bridges();
-	pcibios_claim_resources(pci_root);
-	pcibios_fixup_devices();
-
-#ifdef CONFIG_PCI_BIOS
-	if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
-		pcibios_sort();
-#endif
-}
-
-char * __init pcibios_setup(char *str)
-{
-	if (!strcmp(str, "off")) {
-		pci_probe = 0;
-		return NULL;
-	}
-#ifdef CONFIG_PCI_BIOS
-	else if (!strcmp(str, "bios")) {
-		pci_probe = PCI_PROBE_BIOS;
-		return NULL;
-	} else if (!strcmp(str, "nobios")) {
-		pci_probe &= ~PCI_PROBE_BIOS;
-		return NULL;
-	} else if (!strcmp(str, "nosort")) {
-		pci_probe |= PCI_NO_SORT;
-		return NULL;
-	}
-#endif
-#ifdef CONFIG_PCI_DIRECT
-	else if (!strcmp(str, "conf1")) {
-		pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
-		return NULL;
-	}
-	else if (!strcmp(str, "conf2")) {
-		pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
-		return NULL;
-	}
-#endif
-	else if (!strcmp(str, "nopeer")) {
-		pci_probe |= PCI_NO_PEER_FIXUP;
-		return NULL;
-	} else if (!strcmp(str, "rom")) {
-		pci_probe |= PCI_ASSIGN_ROMS;
-		return NULL;
-	}
-	return str;
-}
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.3.19/linux/arch/i386/kernel/entry.S	Tue Sep  7 12:14:06 1999
+++ linux/arch/i386/kernel/entry.S	Thu Oct  7 10:17:08 1999
@@ -323,9 +323,14 @@
 	jmp error_code
 
 ENTRY(nmi)
+	pushl %eax
+	SAVE_ALL
+	movl %esp,%edx
 	pushl $0
-	pushl $ SYMBOL_NAME(do_nmi)
-	jmp error_code
+	pushl %edx
+	call SYMBOL_NAME(do_nmi)
+	addl $8,%esp
+	RESTORE_ALL
 
 ENTRY(int3)
 	pushl $0
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.3.19/linux/arch/i386/kernel/head.S	Sun Jul 11 09:11:46 1999
+++ linux/arch/i386/kernel/head.S	Thu Oct  7 10:17:08 1999
@@ -243,6 +243,15 @@
 	xorl %eax,%eax
 	lldt %ax
 	cld			# gcc2 wants the direction flag cleared at all times
+#ifdef __SMP__
+	movb ready, %cl	
+	cmpb $1,%cl
+	je 1f			# the first CPU calls start_kernel
+				# all other CPUs call initialize_secondary
+	call SYMBOL_NAME(initialize_secondary)
+	jmp L6
+1:
+#endif
 	call SYMBOL_NAME(start_kernel)
 L6:
 	jmp L6			# main should never return here, but
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.3.19/linux/arch/i386/kernel/i386_ksyms.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/kernel/i386_ksyms.c	Thu Oct  7 10:17:08 1999
@@ -8,6 +8,7 @@
 #include <linux/in6.h>
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
+#include <linux/acpi.h>
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
@@ -41,6 +42,7 @@
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(disable_irq_nosync);
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(acpi_idle);
 
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/i8259.c linux/arch/i386/kernel/i8259.c
--- v2.3.19/linux/arch/i386/kernel/i8259.c	Mon Oct  4 15:49:29 1999
+++ linux/arch/i386/kernel/i8259.c	Thu Oct  7 10:17:08 1999
@@ -1,7 +1,6 @@
 #include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
-#include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/ioport.h>
@@ -9,68 +8,23 @@
 #include <linux/timex.h>
 #include <linux/malloc.h>
 #include <linux/random.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/kernel_stat.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
-#include <asm/smp.h>
 #include <asm/pgtable.h>
 #include <asm/delay.h>
 #include <asm/desc.h>
 
 #include <linux/irq.h>
 
-
-/*
- * Intel specific no controller code
- * odd that no-controller should be architecture dependent
- * but see the ifdef __SMP__ 
- */
-
-static void enable_none(unsigned int irq) { }
-static unsigned int startup_none(unsigned int irq) { return 0; }
-static void disable_none(unsigned int irq) { }
-static void ack_none(unsigned int irq)
-{
-#ifdef __SMP__
-	/*
-	 * [currently unexpected vectors happen only on SMP and APIC.
-	 *  if we want to have non-APIC and non-8259A controllers
-	 *  in the future with unexpected vectors, this ack should
-	 *  probably be made controller-specific.]
-	 */
-	ack_APIC_irq();
-#endif
-}
-
-/* startup is the same as "enable", shutdown is same as "disable" */
-#define shutdown_none	disable_none
-#define end_none	enable_none
-
-struct hw_interrupt_type no_irq_type = {
-	"none",
-	startup_none,
-	shutdown_none,
-	enable_none,
-	disable_none,
-	ack_none,
-	end_none
-};
-
-
-/*
- * This is the 'legacy' 8259A Programmable Interrupt Controller,
- * present in the majority of PC/AT boxes.
- * plus some generic x86 specific things if generic specifics makes
- * any sense at all.
- * this file should become arch/i386/kernel/irq.c when the old irq.c
- * moves to arch independent land
- */
 /*
+ * Common place to define all x86 IRQ vectors
+ *
  * This builds up the IRQ handler stubs using some ugly macros in irq.h
  *
  * These macros create the low-level assembly IRQ routines that save
@@ -79,7 +33,6 @@
  * interrupt-controller happy.
  */
 
-
 BUILD_COMMON_IRQ()
 
 #define BI(x,y) \
@@ -93,7 +46,7 @@
 
 /*
  * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
- * (these are usually mapped to vectors 0x20-0x30)
+ * (these are usually mapped to vectors 0x20-0x2f)
  */
 BUILD_16_IRQS(0x0)
 
@@ -126,9 +79,9 @@
  */
 BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
 BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
-BUILD_SMP_INTERRUPT(stop_cpu_interrupt,STOP_CPU_VECTOR)
 BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
 BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
+BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
 
 /*
  * every pentium local APIC has two 'local interrupts', with a
@@ -150,7 +103,7 @@
 	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
 	IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
 
-static void (*interrupt[NR_IRQS])(void) = {
+void (*interrupt[NR_IRQS])(void) = {
 	IRQLIST_16(0x0),
 
 #ifdef CONFIG_X86_IO_APIC
@@ -164,17 +117,23 @@
 #undef IRQ
 #undef IRQLIST_16
 
+/*
+ * This is the 'legacy' 8259A Programmable Interrupt Controller,
+ * present in the majority of PC/AT boxes.
+ * plus some generic x86 specific things if generic specifics makes
+ * any sense at all.
+ * this file should become arch/i386/kernel/irq.c when the old irq.c
+ * moves to arch independent land
+ */
 
-
-
-static void enable_8259A_irq(unsigned int irq);
+void enable_8259A_irq(unsigned int irq);
 void disable_8259A_irq(unsigned int irq);
 
 /* shutdown is same as "disable" */
 #define end_8259A_irq		enable_8259A_irq
 #define shutdown_8259A_irq	disable_8259A_irq
 
-static void mask_and_ack_8259A(unsigned int);
+void mask_and_ack_8259A(unsigned int);
 
 static unsigned int startup_8259A_irq(unsigned int irq)
 { 
@@ -207,8 +166,8 @@
 
 /*
  * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
- * boards the timer interrupt is not connected to any IO-APIC pin, it's
- * fed to the CPU IRQ line directly.
+ * boards the timer interrupt is not really connected to any IO-APIC pin,
+ * it's fed to the master 8259A's IR0 line only.
  *
  * Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
  * this 'mixed mode' IRQ handling costs nothing because it's only used
@@ -224,22 +183,20 @@
 {
 	unsigned int mask = 1 << irq;
 	cached_irq_mask |= mask;
-	if (irq & 8) {
+	if (irq & 8)
 		outb(cached_A1,0xA1);
-	} else {
+	else
 		outb(cached_21,0x21);
-	}
 }
 
-static void enable_8259A_irq(unsigned int irq)
+void enable_8259A_irq(unsigned int irq)
 {
 	unsigned int mask = ~(1 << irq);
 	cached_irq_mask &= mask;
-	if (irq & 8) {
+	if (irq & 8)
 		outb(cached_A1,0xA1);
-	} else {
+	else
 		outb(cached_21,0x21);
-	}
 }
 
 int i8259A_irq_pending(unsigned int irq)
@@ -260,26 +217,141 @@
 }
 
 /*
+ * This function assumes to be called rarely. Switching between
+ * 8259A registers is slow.
+ */
+static inline int i8259A_irq_real(unsigned int irq)
+{
+	int value;
+	int irqmask = 1<<irq;
+
+	if (irq < 8) {
+		outb(0x0B,0x20);		/* ISR register */
+		value = inb(0x20) & irqmask;
+		outb(0x0A,0x20);		/* back to the IRR register */
+		return value;
+	}
+	outb(0x0B,0xA0);		/* ISR register */
+	value = inb(0xA0) & (irqmask >> 8);
+	outb(0x0A,0xA0);		/* back to the IRR register */
+	return value;
+}
+
+/*
  * 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 mask_and_ack_8259A(unsigned int irq)
+void mask_and_ack_8259A(unsigned int irq)
 {
-	cached_irq_mask |= 1 << irq;
+	unsigned int irqmask = 1 << irq;
+
+	/*
+	 * Lightweight spurious IRQ detection. We do not want
+	 * to overdo spurious IRQ handling - it's usually a sign
+	 * of hardware problems, so we only do the checks we can
+	 * do without slowing down good hardware unnecesserily.
+	 *
+	 * Note that IRQ7 and IRQ15 (the two spurious IRQs
+	 * usually resulting from the 8259A-1|2 PICs) occur
+	 * even if the IRQ is masked in the 8259A. Thus we
+	 * can check spurious 8259A IRQs without doing the
+	 * quite slow i8259A_irq_real() call for every IRQ.
+	 * This does not cover 100% of spurious interrupts,
+	 * but should be enough to warn the user that there
+	 * is something bad going on ...
+	 */
+	if (cached_irq_mask & irqmask)
+		goto spurious_8259A_irq;
+	cached_irq_mask |= irqmask;
+
+handle_real_irq:
 	if (irq & 8) {
-		inb(0xA1);	/* DUMMY */
+		inb(0xA1);		/* DUMMY - (do we need this?) */
 		outb(cached_A1,0xA1);
-		outb(0x62,0x20);	/* Specific EOI to cascade */
-		outb(0x20,0xA0);
+		outb(0x62,0x20);	/* 'Specific EOI' to master-IRQ2 */
+		outb(0x20,0xA0);	/* 'generic EOI' to slave */
 	} else {
-		inb(0x21);	/* DUMMY */
+		inb(0x21);		/* DUMMY - (do we need this?) */
 		outb(cached_21,0x21);
-		outb(0x20,0x20);
+		outb(0x20,0x20);	/* 'generic EOI' to master */
+	}
+	return;
+
+spurious_8259A_irq:
+	/*
+	 * this is the slow path - should happen rarely.
+	 */
+	if (i8259A_irq_real(irq))
+		/*
+		 * oops, the IRQ _is_ in service according to the
+		 * 8259A - not spurious, go handle it.
+		 */
+		goto handle_real_irq;
+
+	{
+		static int spurious_irq_mask = 0;
+		/*
+		 * At this point we can be sure the IRQ is spurious,
+		 * lets ACK and report it. [once per IRQ]
+		 */
+		if (!(spurious_irq_mask & irqmask)) {
+			printk("spurious 8259A interrupt: IRQ%d.\n", irq);
+			spurious_irq_mask |= irqmask;
+		}
+		irq_err_count++;
+		/*
+		 * Theoretically we do not have to handle this IRQ,
+		 * but in Linux this does not cause problems and is
+		 * simpler for us.
+		 */
+		goto handle_real_irq;
 	}
 }
 
+void init_8259A(int auto_eoi)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	outb(0xff, 0x21);	/* mask all of 8259A-1 */
+	outb(0xff, 0xA1);	/* mask all of 8259A-2 */
+
+	/*
+	 * outb_p - this has to work on a wide range of PC hardware.
+	 */
+	outb_p(0x11, 0x20);	/* ICW1: select 8259A-1 init */
+	outb_p(0x20 + 0, 0x21);	/* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
+	outb_p(0x04, 0x21);	/* 8259A-1 (the master) has a slave on IR2 */
+	if (auto_eoi)
+		outb_p(0x03, 0x21);	/* master does Auto EOI */
+	else
+		outb_p(0x01, 0x21);	/* master expects normal EOI */
+
+	outb_p(0x11, 0xA0);	/* ICW1: select 8259A-2 init */
+	outb_p(0x20 + 8, 0xA1);	/* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
+	outb_p(0x02, 0xA1);	/* 8259A-2 is a slave on master's IR2 */
+	outb_p(0x01, 0xA1);	/* (slave's support for AEOI in flat mode
+				    is to be investigated) */
+
+	if (auto_eoi)
+		/*
+		 * in AEOI mode we just have to mask the interrupt
+		 * when acking.
+		 */
+		i8259A_irq_type.ack = disable_8259A_irq;
+
+	udelay(100);		/* wait for 8259A to initialize */
+
+	outb(cached_21, 0x21);	/* restore master IRQ mask */
+	outb(cached_A1, 0xA1);	/* restore slave IRQ mask */
+
+	restore_flags(flags);
+}
+
 #ifndef CONFIG_VISWS
 /*
  * Note that on a 486, we don't want to do a SIGFPE on an irq13
@@ -307,7 +379,7 @@
  * IRQ2 is cascade interrupt to second interrupt controller
  */
 
-static struct irqaction irq2  = { no_action, 0, 0, "cascade", NULL, NULL};
+static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL};
 #endif
 
 
@@ -315,6 +387,8 @@
 {
 	int i;
 
+	init_8259A(0);
+
 	for (i = 0; i < NR_IRQS; i++) {
 		irq_desc[i].status = IRQ_DISABLED;
 		irq_desc[i].action = 0;
@@ -357,9 +431,9 @@
 #ifdef __SMP__	
 
 	/*
-	  IRQ0 must be given a fixed assignment and initialized
-	  before init_IRQ_SMP.
-	*/
+	 * IRQ0 must be given a fixed assignment and initialized,
+	 * because it's used before the IO-APIC is set up.
+	 */
 	set_intr_gate(IRQ0_TRAP_VECTOR, interrupt[0]);
 
 	/*
@@ -371,17 +445,15 @@
 	/* IPI for invalidation */
 	set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
 
-	/* IPI for CPU halt */
-	set_intr_gate(STOP_CPU_VECTOR, stop_cpu_interrupt);
-
 	/* self generated IPI for local APIC timer */
 	set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
 
 	/* IPI for generic function call */
 	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
 
-	/* IPI vector for APIC spurious interrupts */
+	/* IPI vectors for APIC spurious and error interrupts */
 	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
+	set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
 #endif	
 
 	/*
@@ -397,13 +469,3 @@
 	setup_irq(13, &irq13);
 #endif
 }
-
-#ifdef CONFIG_X86_IO_APIC
-void __init init_IRQ_SMP(void)
-{
-	int i;
-	for (i = 0; i < NR_IRQS ; i++)
-		if (IO_APIC_VECTOR(i) > 0)
-			set_intr_gate(IO_APIC_VECTOR(i), interrupt[i]);
-}
-#endif
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.3.19/linux/arch/i386/kernel/io_apic.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/kernel/io_apic.c	Thu Oct  7 10:17:08 1999
@@ -1,7 +1,7 @@
 /*
  *	Intel IO-APIC support for multi-Pentium hosts.
  *
- *	Copyright (C) 1997, 1998 Ingo Molnar, Hajnalka Szabo
+ *	Copyright (C) 1997, 1998, 1999 Ingo Molnar, Hajnalka Szabo
  *
  *	Many thanks to Stig Venaas for trying out countless experimental
  *	patches and reporting/debugging problems patiently!
@@ -18,15 +18,21 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <asm/io.h>
+#include <asm/desc.h>
 
 #include <linux/irq.h>
 
+#undef __init
+#define __init
+
 /*
  * volatile is justified in this case, IO-APIC register contents
  * might change spontaneously, GCC should not cache it
  */
 #define IO_APIC_BASE(idx) ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx))
 
+extern int nmi_watchdog;
+
 /*
  * The structure of the IO-APIC:
  */
@@ -59,6 +65,11 @@
 enum ioapic_irq_destination_types {
 	dest_Fixed = 0,
 	dest_LowestPrio = 1,
+	dest_SMI = 2,
+	dest__reserved_1 = 3,
+	dest_NMI = 4,
+	dest_INIT = 5,
+	dest__reserved_2 = 6,
 	dest_ExtINT = 7
 };
 
@@ -94,14 +105,7 @@
  * MP-BIOS irq configuration table structures:
  */
 
-enum mp_irq_source_types {
-	mp_INT = 0,
-	mp_NMI = 1,
-	mp_SMI = 2,
-	mp_ExtINT = 3
-};
-
-struct mpc_config_ioapic mp_apics[MAX_IO_APICS];/* I/O APIC entries */
+struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];/* I/O APIC entries */
 int mp_irq_entries = 0;				/* # of MP IRQ source entries */
 struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
 						/* MP IRQ source entries */
@@ -202,16 +206,10 @@
 	FINAL;								\
 }
 
-/*
- * We disable IO-APIC IRQs by setting their 'destination CPU mask' to
- * zero. Trick by Ramesh Nalluri.
- */
-DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync(entry->apic))/* destination = 0x00 */
-DO_ACTION( enable,  1, |= 0xff000000, )				/* destination = 0xff */
 DO_ACTION( mask,    0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */
 DO_ACTION( unmask,  0, &= 0xfffeffff, )				/* mask = 0 */
 
-static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
+void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
 	struct IO_APIC_route_entry entry;
 
@@ -289,7 +287,7 @@
 
 	for (i = 0; i < mp_irq_entries; i++)
 		if ( (mp_irqs[i].mpc_irqtype == type) &&
-			(mp_irqs[i].mpc_dstapic == mp_apics[apic].mpc_apicid) &&
+			(mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid) &&
 			(mp_irqs[i].mpc_dstirq == pin))
 
 			return i;
@@ -330,7 +328,7 @@
 		int lbus = mp_irqs[i].mpc_srcbus;
 
 		for (apic = 0; apic < nr_ioapics; apic++)
-			if (mp_apics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
+			if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
 				break;
 
 		if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) &&
@@ -589,24 +587,30 @@
 	static int current_vector = IRQ0_TRAP_VECTOR, offset = 0;
 	if (IO_APIC_VECTOR(irq) > 0)
 		return IO_APIC_VECTOR(irq);
+	if (current_vector == 0xFF)
+		panic("ran out of interrupt sources!");
+next:
 	current_vector += 8;
-	if (current_vector > 0xFE) {
+	if (current_vector == SYSCALL_VECTOR)
+		goto next;
+
+	if (current_vector > 0xFF) {
 		offset++;
 		current_vector = IRQ0_TRAP_VECTOR + offset;
-		printk("WARNING: ASSIGN_IRQ_VECTOR wrapped back to %02X\n",
-		       current_vector);
 	}
-	if (current_vector == SYSCALL_VECTOR)
-		panic("ran out of interrupt sources!");
 
 	IO_APIC_VECTOR(irq) = current_vector;
 	return current_vector;
 }
 
+extern void (*interrupt[NR_IRQS])(void);
+static struct hw_interrupt_type ioapic_level_irq_type;
+static struct hw_interrupt_type ioapic_edge_irq_type;
+
 void __init setup_IO_APIC_irqs(void)
 {
 	struct IO_APIC_route_entry entry;
-	int apic, pin, idx, irq, first_notcon = 1;
+	int apic, pin, idx, irq, first_notcon = 1, vector;
 
 	printk("init IO_APIC IRQs\n");
 
@@ -621,15 +625,15 @@
 		entry.delivery_mode = dest_LowestPrio;
 		entry.dest_mode = 1;			/* logical delivery */
 		entry.mask = 0;				/* enable IRQ */
-		entry.dest.logical.logical_dest = 0;	/* but no route */
+		entry.dest.logical.logical_dest = APIC_ALL_CPUS; /* all CPUs */
 
 		idx = find_irq_entry(apic,pin,mp_INT);
 		if (idx == -1) {
 			if (first_notcon) {
-				printk(" IO-APIC (apicid-pin) %d-%d", mp_apics[apic].mpc_apicid, pin);
+				printk(" IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin);
 				first_notcon = 0;
 			} else
-				printk(", %d-%d", mp_apics[apic].mpc_apicid, pin);
+				printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin);
 			continue;
 		}
 
@@ -639,17 +643,29 @@
 		if (irq_trigger(idx)) {
 			entry.trigger = 1;
 			entry.mask = 1;
-			entry.dest.logical.logical_dest = 0xff;
+			entry.dest.logical.logical_dest = APIC_ALL_CPUS;
 		}
 
-		irq = pin_2_irq(idx,apic,pin);
+		irq = pin_2_irq(idx, apic, pin);
 		add_pin_to_irq(irq, apic, pin);
 
 		if (!apic && !IO_APIC_IRQ(irq))
 			continue;
 
-		entry.vector = assign_irq_vector(irq);
+		if (IO_APIC_IRQ(irq)) {
+			vector = assign_irq_vector(irq);
+			entry.vector = vector;
+
+			if (IO_APIC_irq_trigger(irq))
+				irq_desc[irq].handler = &ioapic_level_irq_type;
+			else
+				irq_desc[irq].handler = &ioapic_edge_irq_type;
 
+			set_intr_gate(vector, interrupt[irq]);
+		
+			if (!apic && (irq < 16))
+				disable_8259A_irq(irq);
+		}
 		io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
 		io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
 	}
@@ -660,34 +676,47 @@
 }
 
 /*
- * Set up a certain pin as ExtINT delivered interrupt
+ * Set up the 8259A-master output pin as broadcast to all
+ * CPUs.
  */
-void __init setup_ExtINT_pin(unsigned int apic, unsigned int pin, int irq)
+void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
 {
 	struct IO_APIC_route_entry entry;
 
-	/*
-	 * add it to the IO-APIC irq-routing table:
-	 */
 	memset(&entry,0,sizeof(entry));
 
-	entry.delivery_mode = dest_ExtINT;
-	entry.dest_mode = 0;				/* physical delivery */
-	entry.mask = 0;					/* unmask IRQ now */
-	/*
-	 * We use physical delivery to get the timer IRQ
-	 * to the boot CPU. 'boot_cpu_id' is the physical
-	 * APIC ID of the boot CPU.
-	 */
-	entry.dest.physical.physical_dest = boot_cpu_id;
+	disable_8259A_irq(0);
+
+	apic_readaround(APIC_LVT0);
+	apic_write(APIC_LVT0, 0x00010700);	// mask LVT0
 
-	entry.vector = assign_irq_vector(irq);
+	init_8259A(1);
 
+	/*
+	 * We use logical delivery to get the timer IRQ
+	 * to the first CPU.
+	 */
+	entry.dest_mode = 1;				/* logical delivery */
+	entry.mask = 0;					/* unmask IRQ now */
+	entry.dest.logical.logical_dest = APIC_ALL_CPUS;
+	entry.delivery_mode = dest_LowestPrio;
 	entry.polarity = 0;
 	entry.trigger = 0;
+	entry.vector = vector;
+
+	/*
+	 * The timer IRQ doesnt have to know that behind the
+	 * scene we have a 8259A-master in AEOI mode ...
+	 */
+	irq_desc[0].handler = &ioapic_edge_irq_type;
 
-	io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
-	io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
+	/*
+	 * Add it to the IO-APIC irq-routing table:
+	 */
+	io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
+	io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
+
+	enable_8259A_irq(0);
 }
 
 void __init UNEXPECTED_IO_APIC(void)
@@ -705,7 +734,7 @@
 
  	printk("number of MP IRQ sources: %d.\n", mp_irq_entries);
 	for (i = 0; i < nr_ioapics; i++)
-		printk("number of IO-APIC #%d registers: %d.\n", mp_apics[i].mpc_apicid, nr_ioapic_registers[i]);
+		printk("number of IO-APIC #%d registers: %d.\n", mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
 
 	/*
 	 * We are a bit conservative about what we expect.  We have to
@@ -717,8 +746,10 @@
 
 	*(int *)&reg_00 = io_apic_read(apic, 0);
 	*(int *)&reg_01 = io_apic_read(apic, 1);
-	*(int *)&reg_02 = io_apic_read(apic, 2);
-	printk("\nIO APIC #%d......\n", mp_apics[apic].mpc_apicid);
+	if (reg_01.version >= 0x10)
+		*(int *)&reg_02 = io_apic_read(apic, 2);
+
+	printk("\nIO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
 	printk(".... register #00: %08X\n", *(int *)&reg_00);
 	printk(".......    : physical APIC id: %02X\n", reg_00.ID);
 	if (reg_00.__reserved_1 || reg_00.__reserved_2)
@@ -730,12 +761,15 @@
 		(reg_01.entries != 0x17) && /* typical ISA+PCI boards */
 		(reg_01.entries != 0x1b) && /* Compaq Proliant boards */
 		(reg_01.entries != 0x1f) && /* dual Xeon boards */
-		(reg_01.entries != 0x3F)    /* bigger Xeon boards */
+		(reg_01.entries != 0x22) && /* bigger Xeon boards */
+		(reg_01.entries != 0x2E) &&
+		(reg_01.entries != 0x3F)
 	)
 		UNEXPECTED_IO_APIC();
 
 	printk(".......     : IO APIC version: %04X\n", reg_01.version);
-	if (	(reg_01.version != 0x10) && /* oldest IO-APICs */
+	if (	(reg_01.version != 0x01) && /* 82489DX IO-APICs */
+		(reg_01.version != 0x10) && /* oldest IO-APICs */
 		(reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
 		(reg_01.version != 0x13)    /* Xeon IO-APICs */
 	)
@@ -743,10 +777,12 @@
 	if (reg_01.__reserved_1 || reg_01.__reserved_2)
 		UNEXPECTED_IO_APIC();
 
-	printk(".... register #02: %08X\n", *(int *)&reg_02);
-	printk(".......     : arbitration: %02X\n", reg_02.arbitration);
-	if (reg_02.__reserved_1 || reg_02.__reserved_2)
-		UNEXPECTED_IO_APIC();
+	if (reg_01.version >= 0x10) {
+		printk(".... register #02: %08X\n", *(int *)&reg_02);
+		printk(".......     : arbitration: %02X\n", reg_02.arbitration);
+		if (reg_02.__reserved_1 || reg_02.__reserved_2)
+			UNEXPECTED_IO_APIC();
+	}
 
 	printk(".... IRQ redirection table:\n");
 
@@ -797,8 +833,116 @@
 	return;
 }
 
+static void print_APIC_bitfield (int base)
+{
+	unsigned int v;
+	int i, j;
+
+	printk("0123456789abcdef0123456789abcdef\n");
+	for (i = 0; i < 8; i++) {
+		v = apic_read(base + i*0x10);
+		for (j = 0; j < 32; j++) {
+			if (v & (1<<j))
+				printk("1");
+			else
+				printk("0");
+		}
+		printk("\n");
+	}
+}
+
+void /*__init*/ print_local_APIC(void * dummy)
+{
+	unsigned int v, ver, maxlvt;
+
+	printk("\nprinting local APIC contents on CPU#%d/%d:\n",
+		smp_processor_id(), hard_smp_processor_id());
+	v = apic_read(APIC_ID);
+	printk("... APIC ID:      %08x (%01x)\n", v, GET_APIC_ID(v));
+	v = apic_read(APIC_LVR);
+	printk("... APIC VERSION: %08x\n", v);
+	ver = GET_APIC_VERSION(v);
+	maxlvt = get_maxlvt();
+
+	v = apic_read(APIC_TASKPRI);
+	printk("... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
+
+	if (APIC_INTEGRATED(ver)) {			/* !82489DX */
+		v = apic_read(APIC_ARBPRI);
+		printk("... APIC ARBPRI: %08x (%02x)\n", v,
+			v & APIC_ARBPRI_MASK);
+		v = apic_read(APIC_PROCPRI);
+		printk("... APIC PROCPRI: %08x\n", v);
+	}
+
+	v = apic_read(APIC_EOI);
+	printk("... APIC EOI: %08x\n", v);
+	v = apic_read(APIC_LDR);
+	printk("... APIC LDR: %08x\n", v);
+	v = apic_read(APIC_DFR);
+	printk("... APIC DFR: %08x\n", v);
+	v = apic_read(APIC_SPIV);
+	printk("... APIC SPIV: %08x\n", v);
+
+	printk("... APIC ISR field:\n");
+	print_APIC_bitfield(APIC_ISR);
+	printk("... APIC TMR field:\n");
+	print_APIC_bitfield(APIC_TMR);
+	printk("... APIC IRR field:\n");
+	print_APIC_bitfield(APIC_IRR);
+
+	if (APIC_INTEGRATED(ver)) {		/* !82489DX */
+		/*
+		 * Due to the Pentium erratum 3AP.
+		 */
+		if (maxlvt > 3) {
+			apic_readaround(APIC_SPIV); // not strictly necessery
+			apic_write(APIC_ESR, 0);
+		}
+		v = apic_read(APIC_ESR);
+		printk("... APIC ESR: %08x\n", v);
+	}
+
+	v = apic_read(APIC_ICR);
+	printk("... APIC ICR: %08x\n", v);
+	v = apic_read(APIC_ICR2);
+	printk("... APIC ICR2: %08x\n", v);
+
+	v = apic_read(APIC_LVTT);
+	printk("... APIC LVTT: %08x\n", v);
+
+	if (maxlvt > 3) {                       /* PC is LVT#4. */
+		v = apic_read(APIC_LVTPC);
+		printk("... APIC LVTPC: %08x\n", v);
+	}
+	v = apic_read(APIC_LVT0);
+	printk("... APIC LVT0: %08x\n", v);
+	v = apic_read(APIC_LVT1);
+	printk("... APIC LVT1: %08x\n", v);
+
+	if (maxlvt > 2) {			/* ERR is LVT#3. */
+		v = apic_read(APIC_LVTERR);
+		printk("... APIC LVTERR: %08x\n", v);
+	}
+
+	v = apic_read(APIC_TMICT);
+	printk("... APIC TMICT: %08x\n", v);
+	v = apic_read(APIC_TMCCT);
+	printk("... APIC TMCCT: %08x\n", v);
+	v = apic_read(APIC_TDCR);
+	printk("... APIC TDCR: %08x\n", v);
+	printk("\n");
+}
+
+void print_all_local_APICs (void)
+{
+	smp_call_function(print_local_APIC, NULL, 1, 1);
+	print_local_APIC(NULL);
+}
+
 static void __init init_sym_mode(void)
 {
+	struct IO_APIC_reg_01 reg_01;
 	int i;
 
 	for (i = 0; i < PIN_MAP_SIZE; i++) {
@@ -809,24 +953,21 @@
 		for (i = 0; i < MAX_PIRQS; i++)
 			pirq_entries[i] =- 1;
 
-	printk("enabling symmetric IO mode... ");
-
-	outb(0x70, 0x22);
-	outb(0x01, 0x23);
-
-	printk("...done.\n");
+	if (pic_mode) {
+		/*
+		 * PIC mode, enable symmetric IO mode in the IMCR.
+		 */
+		printk("leaving PIC mode, enabling symmetric IO mode.\n");
+		outb(0x70, 0x22);
+		outb(0x01, 0x23);
+	}
 
 	/*
 	 * The number of IO-APIC IRQ registers (== #pins):
 	 */
-	{
-		struct IO_APIC_reg_01 reg_01;
-		int i;
-
-		for (i = 0; i < nr_ioapics; i++) {
-			*(int *)&reg_01 = io_apic_read(i, 1);
-			nr_ioapic_registers[i] = reg_01.entries+1;
-		}
+	for (i = 0; i < nr_ioapics; i++) {
+		*(int *)&reg_01 = io_apic_read(i, 1);
+		nr_ioapic_registers[i] = reg_01.entries+1;
 	}
 
 	/*
@@ -835,24 +976,41 @@
 	clear_IO_APIC();
 }
 
+static void clear_lapic_ints (void * dummy)
+{
+	int maxlvt;
+
+	maxlvt = get_maxlvt();
+	apic_write_around(APIC_LVTT, 0x00010000);
+	apic_write_around(APIC_LVT0, 0x00010000);
+	apic_write_around(APIC_LVT1, 0x00010000);
+	if (maxlvt >= 3)
+		apic_write_around(APIC_LVTERR, 0x00010000);
+	if (maxlvt >= 4)
+		apic_write_around(APIC_LVTPC, 0x00010000);
+}
+
 /*
  * Not an __init, needed by the reboot code
  */
 void init_pic_mode(void)
 {
 	/*
-	 * Clear the IO-APIC before rebooting:
+	 * Clear the IO-APIC and local APICs before rebooting:
 	 */
 	clear_IO_APIC();
+	smp_call_function(clear_lapic_ints, NULL, 1, 1);
+	clear_lapic_ints(NULL);
 
 	/*
 	 * Put it back into PIC mode (has an effect only on
-	 * certain boards)
+	 * certain older boards)
 	 */
-	printk("disabling symmetric IO mode... ");
+	if (pic_mode) {
+		printk("disabling symmetric IO mode, entering PIC mode.\n");
 		outb_p(0x70, 0x22);
 		outb_p(0x00, 0x23);
-	printk("...done.\n");
+	}
 }
 
 static void __init setup_ioapic_id(void)
@@ -914,10 +1072,13 @@
 	 * MP specification 1.4 defines some extra rules for default
 	 * configurations, fix them up here:
 	 */
-	
 	switch (mpc_default_type)
 	{
 		case 2:
+		/*
+		 * IRQ0 is not connected:
+		 */
+			mp_irqs[0].mpc_irqtype = mp_ExtINT;
 			break;
 		default:
 		/*
@@ -942,7 +1103,7 @@
 	unsigned int t1 = jiffies;
 
 	sti();
-	mdelay(100);
+	mdelay(40);
 
 	if (jiffies-t1>1)
 		return 1;
@@ -950,6 +1111,27 @@
 	return 0;
 }
 
+extern atomic_t nmi_counter[NR_CPUS];
+
+static int __init nmi_irq_works(void)
+{
+	atomic_t tmp[NR_CPUS];
+	int j, cpu;
+
+	memcpy(tmp, nmi_counter, sizeof(tmp));
+	sti();
+	mdelay(50);
+
+	for (j = 0; j < smp_num_cpus; j++) {
+		cpu = cpu_logical_map(j);
+		if (atomic_read(nmi_counter+cpu) - atomic_read(tmp+cpu) <= 3) {
+			printk("CPU#%d NMI appears to be stuck.\n", cpu);
+			return 0;
+		}
+	}
+	return 1;
+}
+
 /*
  * In the SMP+IOAPIC case it might happen that there are an unspecified
  * number of pending IRQ events unhandled. These cases are very rare,
@@ -964,12 +1146,11 @@
  */
 static void enable_edge_ioapic_irq(unsigned int irq)
 {
-	enable_IO_APIC_irq(irq);
+	unmask_IO_APIC_irq(irq);
 }
 
 static void disable_edge_ioapic_irq(unsigned int irq)
 {
-	disable_IO_APIC_irq(irq);
 }
 
 /*
@@ -995,8 +1176,17 @@
 }
 
 #define shutdown_edge_ioapic_irq	disable_edge_ioapic_irq
-void static ack_edge_ioapic_irq(unsigned int i)
-{
+
+/*
+ * Once we have recorded IRQ_PENDING already, we can mask the
+ * interrupt for real. This prevents IRQ storms from unhandled
+ * devices.
+ */
+void static ack_edge_ioapic_irq(unsigned int irq)
+{
+	if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
+					== (IRQ_PENDING | IRQ_DISABLED))
+		mask_IO_APIC_irq(irq);
 	ack_APIC_irq();
 }
 void static end_edge_ioapic_irq(unsigned int i){}
@@ -1055,7 +1245,8 @@
 
 static inline void init_IO_APIC_traps(void)
 {
-	int i;
+	int irq;
+
 	/*
 	 * NOTE! The local APIC isn't very good at handling
 	 * multiple interrupts at the same interrupt level.
@@ -1067,36 +1258,62 @@
 	 * Also, we've got to be careful not to trash gate
 	 * 0x80, because int 0x80 is hm, kind of importantish. ;)
 	 */
-	for (i = 0; i < NR_IRQS ; i++) {
-		if (IO_APIC_VECTOR(i) > 0) {
-			if (IO_APIC_irq_trigger(i))
-				irq_desc[i].handler = &ioapic_level_irq_type;
-			else
-				irq_desc[i].handler = &ioapic_edge_irq_type;
-			/*
-			 * disable it in the 8259A:
-			 */
-			if (i < 16)
-				disable_8259A_irq(i);
-		} else {
-			if (!IO_APIC_IRQ(i))
-				continue;
-
+	for (irq = 0; irq < NR_IRQS ; irq++) {
+		if (IO_APIC_IRQ(irq) && !IO_APIC_VECTOR(irq)) {
 			/*
 			 * Hmm.. We don't have an entry for this,
 			 * so default to an old-fashioned 8259
 			 * interrupt if we can..
 			 */
-			if (i < 16) {
-				make_8259A_irq(i);
-				continue;
-			}
-
-			/* Strange. Oh, well.. */
-			irq_desc[i].handler = &no_irq_type;
+			if (irq < 16)
+				make_8259A_irq(irq);
+			else
+				/* Strange. Oh, well.. */
+				irq_desc[irq].handler = &no_irq_type;
 		}
 	}
-	init_IRQ_SMP();
+}
+
+void static ack_lapic_irq (unsigned int irq)
+{
+	ack_APIC_irq();
+}
+
+void static end_lapic_irq (unsigned int i) { /* nothing */ }
+
+static struct hw_interrupt_type lapic_irq_type = {
+	"local-APIC-edge",
+	NULL, /* startup_irq() not used for IRQ0 */
+	NULL, /* shutdown_irq() not used for IRQ0 */
+	NULL, /* enable_irq() not used for IRQ0 */
+	NULL, /* disable_irq() not used for IRQ0 */
+	ack_lapic_irq,
+	end_lapic_irq
+};
+
+static void enable_NMI_through_LVT0 (void * dummy)
+{
+	apic_readaround(APIC_LVT0);
+	apic_write(APIC_LVT0, 0x00000400);	// unmask and set to NMI
+}
+
+static void setup_nmi (void)
+{
+	/*
+ 	 * Dirty trick to enable the NMI watchdog ...
+	 * We put the 8259A master into AEOI mode and
+	 * unmask on all local APICs LVT0 as NMI.
+	 *
+	 * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire')
+	 * is from Maciej W. Rozycki - so we do not have to EOI from
+	 * the NMI handler or the timer interrupt.
+	 */ 
+	printk("activating NMI Watchdog ...");
+
+	smp_call_function(enable_NMI_through_LVT0, NULL, 1, 1);
+	enable_NMI_through_LVT0(NULL);
+
+	printk(" done.\n");
 }
 
 /*
@@ -1108,45 +1325,78 @@
 static inline void check_timer(void)
 {
 	int pin1, pin2;
+	int vector;
+
+	/*
+	 * get/set the timer IRQ vector:
+	 */
+	vector = assign_irq_vector(0);
+	set_intr_gate(vector, interrupt[0]);
 
 	pin1 = find_timer_pin(mp_INT);
 	pin2 = find_timer_pin(mp_ExtINT);
-	enable_IO_APIC_irq(0);
-	if (!timer_irq_works()) {
 
-		if (pin1 != -1)
-			printk("..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
-		printk("...trying to set up timer as ExtINT... ");
-
-		if (pin2 != -1) {
-			printk(".. (found pin %d) ...", pin2);
-			/*
-			 * legacy devices should be connected to IO APIC #0
-			 */
-			setup_ExtINT_pin(0, pin2, 0);
-			make_8259A_irq(0);
+	/*
+	 * Ok, does IRQ0 through the IOAPIC work?
+	 */
+	if (timer_irq_works()) {
+		if (nmi_watchdog) {
+			disable_8259A_irq(0);
+			init_8259A(1);
+			setup_nmi();
+			enable_8259A_irq(0);
+			if (nmi_irq_works())
+				return;
+		} else
+			return;
+	}
+
+	if (pin1 != -1) {
+		printk("..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
+		clear_IO_APIC_pin(0, pin1);
+	}
+
+	printk("...trying to set up timer (IRQ0) through the 8259A ... ");
+	if (pin2 != -1) {
+		printk("\n..... (found pin %d) ...", pin2);
+		/*
+		 * legacy devices should be connected to IO APIC #0
+		 */
+		setup_ExtINT_IRQ0_pin(pin2, vector);
+		if (timer_irq_works()) {
+			printk("works.\n");
+			if (nmi_watchdog) {
+				setup_nmi();
+				if (nmi_irq_works())
+					return;
+			} else
+				return;
 		}
+		/*
+		 * Cleanup, just in case ...
+		 */
+		clear_IO_APIC_pin(0, pin2);
+	}
+	printk(" failed.\n");
 
-		if (!timer_irq_works()) {
-			printk(" failed.\n");
-			printk("...trying to set up timer as BP IRQ...");
-			/*
-			 * Just in case ...
-			 */
-			if (pin1 != -1)
-				clear_IO_APIC_pin(0, pin1);
-			if (pin2 != -1)
-				clear_IO_APIC_pin(0, pin2);
-
-			make_8259A_irq(0);
-
-			if (!timer_irq_works()) {
-				printk(" failed.\n");
-				panic("IO-APIC + timer doesn't work!");
-			}
-		}
+	if (nmi_watchdog)
+		printk("timer doesnt work through the IO-APIC - cannot activate NMI Watchdog!\n");
+
+	printk("...trying to set up timer as Virtual Wire IRQ...");
+
+	disable_8259A_irq(0);
+	irq_desc[0].handler = &lapic_irq_type;
+	init_8259A(1);					// AEOI mode
+	apic_readaround(APIC_LVT0);
+	apic_write(APIC_LVT0, 0x00000000 | vector);	// Fixed mode
+	enable_8259A_irq(0);
+
+	if (timer_irq_works()) {
 		printk(" works.\n");
+		return;
 	}
+	printk(" failed :(.\n");
+	panic("IO-APIC + timer doesn't work! pester mingo@redhat.com");
 }
 
 /*
@@ -1189,6 +1439,5 @@
 	setup_IO_APIC_irqs();
 	init_IO_APIC_traps();
 	check_timer();
-
 	print_IO_APIC();
 }
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.3.19/linux/arch/i386/kernel/irq.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/kernel/irq.c	Thu Oct  7 10:17:08 1999
@@ -22,7 +22,6 @@
 
 #include <linux/ptrace.h>
 #include <linux/errno.h>
-#include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/ioport.h>
@@ -30,14 +29,13 @@
 #include <linux/timex.h>
 #include <linux/malloc.h>
 #include <linux/random.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/kernel_stat.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
-#include <asm/smp.h>
 #include <asm/pgtable.h>
 #include <asm/delay.h>
 #include <asm/desc.h>
@@ -48,7 +46,7 @@
 unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
 
-atomic_t nmi_counter;
+extern atomic_t nmi_counter[NR_CPUS];
 
 /*
  * Linux has a controller-independent x86 interrupt architecture.
@@ -75,7 +73,8 @@
 /*
  * Controller mappings for all interrupt sources:
  */
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
+				{ [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
 
 /*
  * Special irq handlers.
@@ -84,6 +83,52 @@
 void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
 
 /*
+ * Generic no controller code
+ */
+
+static void enable_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+static void disable_none(unsigned int irq) { }
+static void ack_none(unsigned int irq)
+{
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves, it doesnt deserve
+ * a generic callback i think.
+ */
+#if CONFIG_X86
+	printk("unexpected IRQ trap at vector %02x\n", irq);
+#ifdef __SMP__
+	/*
+	 * Currently unexpected vectors happen only on SMP and APIC.
+	 * We _must_ ack these because every local APIC has only N
+	 * irq slots per priority level, and a 'hanging, unacked' IRQ
+	 * holds up an irq slot - in excessive cases (when multiple
+	 * unexpected vectors occur) that might lock up the APIC
+	 * completely.
+	 */
+	ack_APIC_irq();
+#endif
+#endif
+}
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define shutdown_none	disable_none
+#define end_none	enable_none
+
+struct hw_interrupt_type no_irq_type = {
+	"none",
+	startup_none,
+	shutdown_none,
+	enable_none,
+	disable_none,
+	ack_none,
+	end_none
+};
+
+volatile unsigned long irq_err_count;
+
+/*
  * Generic, controller-independent functions:
  */
 
@@ -106,22 +151,30 @@
 #ifndef __SMP__
 		p += sprintf(p, "%10u ", kstat_irqs(i));
 #else
-		for (j=0; j<smp_num_cpus; j++)
+		for (j = 0; j < smp_num_cpus; j++)
 			p += sprintf(p, "%10u ",
 				kstat.irqs[cpu_logical_map(j)][i]);
 #endif
 		p += sprintf(p, " %14s", irq_desc[i].handler->typename);
 		p += sprintf(p, "  %s", action->name);
 
-		for (action=action->next; action; action = action->next) {
+		for (action=action->next; action; action = action->next)
 			p += sprintf(p, ", %s", action->name);
-		}
 		*p++ = '\n';
 	}
-	p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter));
-#ifdef __SMP__
-	p += sprintf(p, "ERR: %10lu\n", ipi_count);
-#endif		
+	p += sprintf(p, "NMI: ");
+	for (j = 0; j < smp_num_cpus; j++)
+		p += sprintf(p, "%10u ",
+			atomic_read(nmi_counter+cpu_logical_map(j)));
+	p += sprintf(p, "\n");
+#if CONFIG_SMP
+	p += sprintf(p, "LOC: ");
+	for (j = 0; j < smp_num_cpus; j++)
+		p += sprintf(p, "%10u ",
+			apic_timer_irqs[cpu_logical_map(j)]);
+	p += sprintf(p, "\n");
+#endif
+	p += sprintf(p, "ERR: %10lu\n", irq_err_count);
 	return p - buf;
 }
 
@@ -520,7 +573,7 @@
 	kstat.irqs[cpu][irq]++;
 	desc = irq_desc + irq;
 	spin_lock(&irq_controller_lock);
-	irq_desc[irq].handler->ack(irq);
+	desc->handler->ack(irq);
 	/*
 	   REPLAY is when Linux resends an IRQ that was dropped earlier
 	   WAITING is used by probe to mark irqs that are being tested
@@ -570,9 +623,8 @@
 		spin_unlock(&irq_controller_lock);
 	}
 	desc->status &= ~IRQ_INPROGRESS;
-	if (!(desc->status & IRQ_DISABLED)){
-			irq_desc[irq].handler->end(irq);
-	}
+	if (!(desc->status & IRQ_DISABLED))
+		desc->handler->end(irq);
 	spin_unlock(&irq_controller_lock);
 
 	/*
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.3.19/linux/arch/i386/kernel/mtrr.c	Mon Oct  4 15:49:29 1999
+++ linux/arch/i386/kernel/mtrr.c	Sat Oct  9 11:25:51 1999
@@ -223,6 +223,8 @@
     19990819   Alan Cox <alan@redhat.com>
                Tested Zoltan's changes on a pre production Athlon - 100%
                success.
+    19991008   Manfred Spraul <manfreds@colorfullife.com>
+    	       replaced spin_lock_reschedule() with a normal semaphore.
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -303,8 +305,6 @@
 						       TRUE)
 #endif
 
-#define spin_lock_reschedule(lock) while (!spin_trylock(lock)) schedule ();
-
 #ifndef CONFIG_PROC_FS
 #  define compute_ascii() while (0)
 #endif
@@ -314,7 +314,7 @@
 static unsigned int ascii_buf_bytes = 0;
 #endif
 static unsigned int *usage_table = NULL;
-static spinlock_t main_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_MUTEX(main_lock);
 
 /*  Private functions  */
 #ifdef CONFIG_PROC_FS
@@ -1172,7 +1172,7 @@
     increment = increment ? 1 : 0;
     max = get_num_var_ranges ();
     /*  Search for existing MTRR  */
-    spin_lock_reschedule (&main_lock);
+    down(&main_lock);
     for (i = 0; i < max; ++i)
     {
 	(*get_mtrr) (i, &lbase, &lsize, &ltype);
@@ -1181,7 +1181,7 @@
 	/*  At this point we know there is some kind of overlap/enclosure  */
 	if ( (base < lbase) || (base + size > lbase + lsize) )
 	{
-	    spin_unlock (&main_lock);
+	    up(&main_lock);
 	    printk ("mtrr: 0x%lx,0x%lx overlaps existing 0x%lx,0x%lx\n",
 		    base, size, lbase, lsize);
 	    return -EINVAL;
@@ -1190,14 +1190,14 @@
 	if (ltype != type)
 	{
 	    if (type == MTRR_TYPE_UNCACHABLE) continue;
-	    spin_unlock (&main_lock);
+	    up(&main_lock);
 	    printk ( "mtrr: type mismatch for %lx,%lx old: %s new: %s\n",
 		     base, size, attrib_to_str (ltype), attrib_to_str (type) );
 	    return -EINVAL;
 	}
 	if (increment) ++usage_table[i];
 	compute_ascii ();
-	spin_unlock (&main_lock);
+	up(&main_lock);
 	return i;
     }
     /*  Search for an empty MTRR  */
@@ -1211,7 +1211,7 @@
     set_mtrr (i, base, size, type);
     usage_table[i] = 1;
     compute_ascii ();
-    spin_unlock (&main_lock);
+    up(&main_lock);
     return i;
 }   /*  End Function mtrr_add  */
 
@@ -1232,7 +1232,7 @@
 
     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
     max = get_num_var_ranges ();
-    spin_lock_reschedule (&main_lock);
+    down(&main_lock);
     if (reg < 0)
     {
 	/*  Search for existing MTRR  */
@@ -1247,14 +1247,14 @@
 	}
 	if (reg < 0)
 	{
-	    spin_unlock (&main_lock);
+	    up(&main_lock);
 	    printk ("mtrr: no MTRR for %lx,%lx found\n", base, size);
 	    return -EINVAL;
 	}
     }
     if (reg >= max)
     {
-	spin_unlock (&main_lock);
+	up(&main_lock);
 	printk ("mtrr: register: %d too big\n", reg);
 	return -EINVAL;
     }
@@ -1262,7 +1262,7 @@
     {
 	if ((reg == 3) && arr3_protected)
 	{
-	    spin_unlock (&main_lock);
+	    up(&main_lock);
 	    printk ("mtrr: ARR3 cannot be changed\n");
 	    return -EINVAL;
 	}
@@ -1270,19 +1270,19 @@
     (*get_mtrr) (reg, &lbase, &lsize, &ltype);
     if (lsize < 1)
     {
-	spin_unlock (&main_lock);
+	up(&main_lock);
 	printk ("mtrr: MTRR %d not used\n", reg);
 	return -EINVAL;
     }
     if (usage_table[reg] < 1)
     {
-	spin_unlock (&main_lock);
+	up(&main_lock);
 	printk ("mtrr: reg: %d has count=0\n", reg);
 	return -EINVAL;
     }
     if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0);
     compute_ascii ();
-    spin_unlock (&main_lock);
+    up(&main_lock);
     return reg;
 }   /*  End Function mtrr_del  */
 
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c
--- v2.3.19/linux/arch/i386/kernel/pci-i386.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/kernel/pci-i386.c	Fri Oct  8 10:06:21 1999
@@ -0,0 +1,312 @@
+/*
+ *	Low-Level PCI Access for i386 machines
+ *
+ * Copyright 1993, 1994 Drew Eckhardt
+ *      Visionary Computing
+ *      (Unix and Linux consulting and custom programming)
+ *      Drew@Colorado.EDU
+ *      +1 (303) 786-7975
+ *
+ * Drew's work was sponsored by:
+ *	iX Multiuser Multitasking Magazine
+ *	Hannover, Germany
+ *	hm@ix.de
+ *
+ * Copyright 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
+ *
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
+ *
+ *
+ * CHANGELOG :
+ * Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
+ *	Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
+ *
+ * Jan 5,  1995 : Modified to probe PCI hardware at boot time by Frederic
+ *     Potter, potter@cao-vlsi.ibp.fr
+ *
+ * Jan 10, 1995 : Modified to store the information about configured pci
+ *      devices into a list, which can be accessed via /proc/pci by
+ *      Curtis Varner, cvarner@cs.ucr.edu
+ *
+ * Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
+ *	Alpha version. Intel & UMC chipset support only.
+ *
+ * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
+ *	moved to drivers/pci/pci.c.
+ *
+ * Dec 7, 1996  : Added support for direct configuration access of boards
+ *      with Intel compatible access schemes (tsbogend@alpha.franken.de)
+ *
+ * Feb 3, 1997  : Set internal functions to static, save/restore flags
+ *	avoid dead locks reading broken PCI BIOS, werner@suse.de 
+ *
+ * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
+ *	(mj@atrey.karlin.mff.cuni.cz)
+ *
+ * May 7,  1997 : Added some missing cli()'s. [mj]
+ * 
+ * Jun 20, 1997 : Corrected problems in "conf1" type accesses.
+ *      (paubert@iram.es)
+ *
+ * Aug 2,  1997 : Split to PCI BIOS handling and direct PCI access parts
+ *	and cleaned it up...     Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Feb 6,  1998 : No longer using BIOS to find devices and device classes. [mj]
+ *
+ * May 1,  1998 : Support for peer host bridges. [mj]
+ *
+ * Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
+ *	can be accessed from interrupts even on SMP systems. [mj]
+ *
+ * August  1998 : Better support for peer host bridges and more paranoid
+ *	checks for direct hardware access. Ugh, this file starts to look as
+ *	a large gallery of common hardware bug workarounds (watch the comments)
+ *	-- the PCI specs themselves are sane, but most implementors should be
+ *	hit hard with \hammer scaled \magstep5. [mj]
+ *
+ * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
+ *
+ * Feb 8,  1999 : Added UM8886BF I/O address fixup. [mj]
+ *
+ * August  1999 : New resource management and configuration access stuff. [mj]
+ *
+ * Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges.
+ *		  Based on ideas by Chris Frantz and David Hinds. [mj]
+ *
+ * Sep 28, 1999 : Handle unreported/unassigned IRQs. Thanks to Shuu Yamaguchi
+ *		  for a lot of patience during testing. [mj]
+ *
+ * Oct  8, 1999 : Split to pci-i386.c, pci-pc.c and pci-visws.c. [mj]
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+
+#include "pci-i386.h"
+
+/*
+ * Assign new address to PCI resource.  We hope our resource information
+ * is complete.  On the PC, we don't re-assign resources unless we are
+ * forced to do so.
+ *
+ * Expects start=0, end=size-1, flags=resource type.
+ */
+
+static int __init pcibios_assign_resource(struct pci_dev *dev, int i)
+{
+	struct resource *r = &dev->resource[i];
+	struct resource *pr = pci_find_parent_resource(dev, r);
+	unsigned long size = r->end + 1;
+	u32 new, check;
+
+	if (!pr) {
+		printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name);
+		return -EINVAL;
+	}
+	if (r->flags & IORESOURCE_IO) {
+		/*
+		 * We need to avoid collisions with `mirrored' VGA ports and other strange
+		 * ISA hardware, so we always want the addresses kilobyte aligned.
+		 */
+		if (size > 0x100) {
+			printk(KERN_ERR "PCI: I/O Region %s/%d too large (%ld bytes)\n", dev->slot_name, i, size);
+			return -EFBIG;
+		}
+		if (allocate_resource(pr, r, size, 0x1000, ~0, 1024)) {
+			printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
+			return -EBUSY;
+		}
+	} else {
+		if (allocate_resource(pr, r, size, 0x10000000, ~0, size)) {
+			printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
+			return -EBUSY;
+		}
+	}
+	if (i < 6) {
+		int reg = PCI_BASE_ADDRESS_0 + 4*i;
+		new = r->start | (r->flags & PCI_REGION_FLAG_MASK);
+		pci_write_config_dword(dev, reg, new);
+		pci_read_config_dword(dev, reg, &check);
+		if (new != check)
+			printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check);
+	} else if (i == PCI_ROM_RESOURCE) {
+		r->flags |= PCI_ROM_ADDRESS_ENABLE;
+		pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK));
+	}
+	printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i);
+	return 0;
+}
+
+/*
+ *  Handle resources of PCI devices.  If the world were perfect, we could
+ *  just allocate all the resource regions and do nothing more.  It isn't.
+ *  On the other hand, we cannot just re-allocate all devices, as it would
+ *  require us to know lots of host bridge internals.  So we attempt to
+ *  keep as much of the original configuration as possible, but tweak it
+ *  when it's found to be wrong.
+ *
+ *  Known BIOS problems we have to work around:
+ *	- I/O or memory regions not configured
+ *	- regions configured, but not enabled in the command register
+ *	- bogus I/O addresses above 64K used
+ *	- expansion ROMs left enabled (this may sound harmless, but given
+ *	  the fact the PCI specs explicitly allow address decoders to be
+ *	  shared between expansion ROMs and other resource regions, it's
+ *	  at least dangerous)
+ *
+ *  Our solution:
+ *	(1) Allocate resources for all buses behind PCI-to-PCI bridges.
+ *	    This gives us fixed barriers on where we can allocate.
+ *	(2) Allocate resources for all enabled devices.  If there is
+ *	    a collision, just mark the resource as unallocated. Also
+ *	    disable expansion ROMs during this step.
+ *	(3) Try to allocate resources for disabled devices.  If the
+ *	    resources were assigned correctly, everything goes well,
+ *	    if they weren't, they won't disturb allocation of other
+ *	    resources.
+ *	(4) Assign new addresses to resources which were either
+ *	    not configured at all or misconfigured.  If explicitly
+ *	    requested by the user, configure expansion ROM address
+ *	    as well.  Finally enable the I/O and Memory bits.
+ */
+
+static void __init pcibios_allocate_bus_resources(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+	int idx;
+	struct resource *r, *pr;
+
+	/* Depth-First Search on bus tree */
+	while (bus) {
+		if ((dev = bus->self)) {
+			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+				r = &dev->resource[idx];
+				if (!r->start)
+					continue;
+				pr = pci_find_parent_resource(dev, r);
+				if (!pr || request_resource(pr, r) < 0)
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
+			}
+		}
+		if (bus->children)
+			pcibios_allocate_bus_resources(bus->children);
+		bus = bus->next;
+	}
+}
+
+static void __init pcibios_allocate_resources(int pass)
+{
+	struct pci_dev *dev;
+	int idx, disabled;
+	u16 command;
+	struct resource *r, *pr;
+
+	for(dev=pci_devices; dev; dev=dev->next) {
+		pci_read_config_word(dev, PCI_COMMAND, &command);
+		for(idx = 0; idx < 6; idx++) {
+			r = &dev->resource[idx];
+			if (r->parent)		/* Already allocated */
+				continue;
+			if (!r->start)		/* Address not assigned at all */
+				continue;
+			if (r->flags & IORESOURCE_IO)
+				disabled = !(command & PCI_COMMAND_IO);
+			else
+				disabled = !(command & PCI_COMMAND_MEMORY);
+			if (pass == disabled) {
+				DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
+				    r->start, r->end, r->flags, disabled, pass);
+				pr = pci_find_parent_resource(dev, r);
+				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->start = 0;
+				}
+			}
+		}
+		if (!pass) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
+				u32 reg;
+				DBG("PCI: Switching off ROM of %s\n", dev->slot_name);
+				r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+				pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
+			}
+		}
+	}
+}
+
+static void __init pcibios_assign_resources(void)
+{
+	struct pci_dev *dev;
+	u16 cmd, old_cmd;
+	int idx;
+	int fault = 0;
+	struct resource *r;
+
+	for(dev=pci_devices; dev; dev=dev->next) {
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		old_cmd = cmd;
+		for(idx=0; idx<6; idx++) {
+			r = &dev->resource[idx];
+			if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) ||
+			    ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
+				/*
+				 *  Don't touch IDE controllers and I/O ports of video cards!
+				 *  Neither enable anything in their command registers.
+				 */
+				continue;
+			if (!r->start && r->end) {
+				/*
+				 *  We shall assign a new address to this resource, either because
+				 *  the BIOS forgot to do so or because we have decided the old
+				 *  address was unusable for some reason.
+				 */
+				if (pcibios_assign_resource(dev, idx) < 0)
+					fault = 1;
+			}
+			if (r->flags & IORESOURCE_IO)
+				cmd |= PCI_COMMAND_IO;
+			if (r->flags & IORESOURCE_MEM)
+				cmd |= PCI_COMMAND_MEMORY;
+		}
+
+		if (cmd != old_cmd) {
+			if (fault)
+				printk("PCI: Not enabling device %s because of resource collisions\n", dev->slot_name);
+			else {
+				printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+				pci_write_config_word(dev, PCI_COMMAND, cmd);
+			}
+		}
+
+		if (pci_probe & PCI_ASSIGN_ROMS) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			r->end -= r->start;
+			r->start = 0;
+			if (r->end)
+				pcibios_assign_resource(dev, PCI_ROM_RESOURCE);
+		}
+	}
+}
+
+void __init pcibios_resource_survey(void)
+{
+	pcibios_allocate_bus_resources(pci_root);
+	pcibios_allocate_resources(0);
+	pcibios_allocate_resources(1);
+	pcibios_assign_resources();
+}
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/pci-i386.h linux/arch/i386/kernel/pci-i386.h
--- v2.3.19/linux/arch/i386/kernel/pci-i386.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/kernel/pci-i386.h	Fri Oct  8 10:06:21 1999
@@ -0,0 +1,29 @@
+/*
+ *	Low-Level PCI Access for i386 machines.
+ *
+ *	(c) 1999 Martin Mares <mj@ucw.cz>
+ */
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define PCI_PROBE_BIOS 1
+#define PCI_PROBE_CONF1 2
+#define PCI_PROBE_CONF2 4
+#define PCI_NO_SORT 0x100
+#define PCI_BIOS_SORT 0x200
+#define PCI_NO_CHECKS 0x400
+#define PCI_NO_PEER_FIXUP 0x800
+#define PCI_ASSIGN_ROMS 0x1000
+#define PCI_NO_IRQ_SCAN 0x2000
+
+extern unsigned int pci_probe;
+
+/* pci-i386.c */
+
+void pcibios_resource_survey(void);
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
--- v2.3.19/linux/arch/i386/kernel/pci-pc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/kernel/pci-pc.c	Fri Oct  8 10:33:53 1999
@@ -0,0 +1,1225 @@
+/*
+ *	Low-Level PCI Support for PC
+ *
+ *	(c) 1999 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+
+#include "pci-i386.h"
+
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
+
+/*
+ * IRQ routing table provided by the BIOS
+ */
+
+struct irq_info {
+	u8 bus, devfn;			/* Bus, device and function */
+	struct {
+		u8 link;		/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;		/* Available IRQs */
+	} __attribute__((packed)) irq[4];
+	u8 slot;			/* Slot number, 0=onboard */
+	u8 rfu;
+} __attribute__((packed));
+
+struct irq_routing_table {
+	u32 signature;			/* PIRQ_SIGNATURE should be here */
+	u16 version;			/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;		/* Where the interrupt router lies */
+	u16 exclusive_irqs;		/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;		/* Crap */
+	u8 rfu[11];
+	u8 checksum;			/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__((packed));
+
+/*
+ * Direct access to PCI hardware...
+ */
+
+#ifdef CONFIG_PCI_DIRECT
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+
+#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
+
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	*value = inb(0xCFC + (where&3));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);    
+	*value = inw(0xCFC + (where&2));
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	*value = inl(0xCFC);
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);    
+	outb(value, 0xCFC + (where&3));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	outw(value, 0xCFC + (where&2));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	outl(value, 0xCFC);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+static struct pci_ops pci_direct_conf1 = {
+	pci_conf1_read_config_byte,
+	pci_conf1_read_config_word,
+	pci_conf1_read_config_dword,
+	pci_conf1_write_config_byte,
+	pci_conf1_write_config_word,
+	pci_conf1_write_config_dword
+};
+
+/*
+ * Functions for accessing PCI configuration space with type 2 accesses
+ */
+
+#define IOADDR(devfn, where)	((0xC000 | ((devfn & 0x78) << 5)) + where)
+#define FUNC(devfn)		(((devfn & 7) << 1) | 0xf0)
+#define SET(dev)		if (dev->devfn) return PCIBIOS_DEVICE_NOT_FOUND;		\
+				outb(FUNC(dev->devfn), 0xCF8);					\
+				outb(dev->bus->number, 0xCFA);
+
+static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	SET(dev);
+	*value = inb(IOADDR(dev->devfn,where));
+	outb (0, 0xCF8);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	SET(dev);
+	*value = inw(IOADDR(dev->devfn,where));
+	outb (0, 0xCF8);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	SET(dev);
+	*value = inl (IOADDR(dev->devfn,where));    
+	outb (0, 0xCF8);    
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	SET(dev);
+	outb (value, IOADDR(dev->devfn,where));
+	outb (0, 0xCF8);    
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	SET(dev);
+	outw (value, IOADDR(dev->devfn,where));
+	outb (0, 0xCF8);    
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	SET(dev);
+	outl (value, IOADDR(dev->devfn,where));    
+	outb (0, 0xCF8);    
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#undef SET
+#undef IOADDR
+#undef FUNC
+
+static struct pci_ops pci_direct_conf2 = {
+	pci_conf2_read_config_byte,
+	pci_conf2_read_config_word,
+	pci_conf2_read_config_dword,
+	pci_conf2_write_config_byte,
+	pci_conf2_write_config_word,
+	pci_conf2_write_config_dword
+};
+
+/*
+ * Before we decide to use direct hardware access mechanisms, we try to do some
+ * trivial checks to ensure it at least _seems_ to be working -- we just test
+ * whether bus 00 contains a host bridge (this is similar to checking
+ * techniques used in XFree86, but ours should be more reliable since we
+ * attempt to make use of direct access hints provided by the PCI BIOS).
+ *
+ * This should be close to trivial, but it isn't, because there are buggy
+ * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
+ */
+static int __init pci_sanity_check(struct pci_ops *o)
+{
+	u16 x;
+	struct pci_bus bus;		/* Fake bus and device */
+	struct pci_dev dev;
+
+	if (pci_probe & PCI_NO_CHECKS)
+		return 1;
+	bus.number = 0;
+	dev.bus = &bus;
+	for(dev.devfn=0; dev.devfn < 0x100; dev.devfn++)
+		if ((!o->read_word(&dev, PCI_CLASS_DEVICE, &x) &&
+		     (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
+		    (!o->read_word(&dev, PCI_VENDOR_ID, &x) &&
+		     (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
+			return 1;
+	DBG("PCI: Sanity check failed\n");
+	return 0;
+}
+
+static struct pci_ops * __init pci_check_direct(void)
+{
+	unsigned int tmp;
+	unsigned long flags;
+
+	__save_flags(flags); __cli();
+
+	/*
+	 * Check if configuration type 1 works.
+	 */
+	if (pci_probe & PCI_PROBE_CONF1) {
+		outb (0x01, 0xCFB);
+		tmp = inl (0xCF8);
+		outl (0x80000000, 0xCF8);
+		if (inl (0xCF8) == 0x80000000 &&
+		    pci_sanity_check(&pci_direct_conf1)) {
+			outl (tmp, 0xCF8);
+			__restore_flags(flags);
+			printk("PCI: Using configuration type 1\n");
+			return &pci_direct_conf1;
+		}
+		outl (tmp, 0xCF8);
+	}
+
+	/*
+	 * Check if configuration type 2 works.
+	 */
+	if (pci_probe & PCI_PROBE_CONF2) {
+		outb (0x00, 0xCFB);
+		outb (0x00, 0xCF8);
+		outb (0x00, 0xCFA);
+		if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 &&
+		    pci_sanity_check(&pci_direct_conf2)) {
+			__restore_flags(flags);
+			printk("PCI: Using configuration type 2\n");
+			return &pci_direct_conf2;
+		}
+	}
+
+	__restore_flags(flags);
+	return NULL;
+}
+
+#endif
+
+/*
+ * BIOS32 and PCI BIOS handling.
+ */
+
+#ifdef CONFIG_PCI_BIOS
+
+#define PCIBIOS_PCI_FUNCTION_ID 	0xb1XX
+#define PCIBIOS_PCI_BIOS_PRESENT 	0xb101
+#define PCIBIOS_FIND_PCI_DEVICE		0xb102
+#define PCIBIOS_FIND_PCI_CLASS_CODE	0xb103
+#define PCIBIOS_GENERATE_SPECIAL_CYCLE	0xb106
+#define PCIBIOS_READ_CONFIG_BYTE	0xb108
+#define PCIBIOS_READ_CONFIG_WORD	0xb109
+#define PCIBIOS_READ_CONFIG_DWORD	0xb10a
+#define PCIBIOS_WRITE_CONFIG_BYTE	0xb10b
+#define PCIBIOS_WRITE_CONFIG_WORD	0xb10c
+#define PCIBIOS_WRITE_CONFIG_DWORD	0xb10d
+#define PCIBIOS_GET_ROUTING_OPTIONS	0xb10e
+#define PCIBIOS_SET_PCI_HW_INT		0xb10f
+
+/* BIOS32 signature: "_32_" */
+#define BIOS32_SIGNATURE	(('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
+
+/* PCI signature: "PCI " */
+#define PCI_SIGNATURE		(('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
+
+/* PCI service signature: "$PCI" */
+#define PCI_SERVICE		(('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
+
+/* PCI BIOS hardware mechanism flags */
+#define PCIBIOS_HW_TYPE1		0x01
+#define PCIBIOS_HW_TYPE2		0x02
+#define PCIBIOS_HW_TYPE1_SPEC		0x10
+#define PCIBIOS_HW_TYPE2_SPEC		0x20
+
+/*
+ * This is the standard structure used to identify the entry point
+ * to the BIOS32 Service Directory, as documented in
+ * 	Standard BIOS 32-bit Service Directory Proposal
+ * 	Revision 0.4 May 24, 1993
+ * 	Phoenix Technologies Ltd.
+ *	Norwood, MA
+ * and the PCI BIOS specification.
+ */
+
+union bios32 {
+	struct {
+		unsigned long signature;	/* _32_ */
+		unsigned long entry;		/* 32 bit physical address */
+		unsigned char revision;		/* Revision level, 0 */
+		unsigned char length;		/* Length in paragraphs should be 01 */
+		unsigned char checksum;		/* All bytes must add up to zero */
+		unsigned char reserved[5]; 	/* Must be zero */
+	} fields;
+	char chars[16];
+};
+
+/*
+ * Physical address of the service directory.  I don't know if we're
+ * allowed to have more than one of these or not, so just in case
+ * we'll make pcibios_present() take a memory start parameter and store
+ * the array there.
+ */
+
+static struct {
+	unsigned long address;
+	unsigned short segment;
+} bios32_indirect = { 0, __KERNEL_CS };
+
+/*
+ * Returns the entry point for the given service, NULL on error
+ */
+
+static unsigned long bios32_service(unsigned long service)
+{
+	unsigned char return_code;	/* %al */
+	unsigned long address;		/* %ebx */
+	unsigned long length;		/* %ecx */
+	unsigned long entry;		/* %edx */
+	unsigned long flags;
+
+	__save_flags(flags); __cli();
+	__asm__("lcall (%%edi)"
+		: "=a" (return_code),
+		  "=b" (address),
+		  "=c" (length),
+		  "=d" (entry)
+		: "0" (service),
+		  "1" (0),
+		  "D" (&bios32_indirect));
+	__restore_flags(flags);
+
+	switch (return_code) {
+		case 0:
+			return address + entry;
+		case 0x80:	/* Not present */
+			printk("bios32_service(0x%lx): not present\n", service);
+			return 0;
+		default: /* Shouldn't happen */
+			printk("bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
+				service, return_code);
+			return 0;
+	}
+}
+
+static struct {
+	unsigned long address;
+	unsigned short segment;
+} pci_indirect = { 0, __KERNEL_CS };
+
+static int pci_bios_present;
+
+static int __init check_pcibios(void)
+{
+	u32 signature, eax, ebx, ecx;
+	u8 status, major_ver, minor_ver, hw_mech, last_bus;
+	unsigned long flags, pcibios_entry;
+
+	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
+		pci_indirect.address = pcibios_entry + PAGE_OFFSET;
+
+		__save_flags(flags); __cli();
+		__asm__(
+			"lcall (%%edi)\n\t"
+			"jc 1f\n\t"
+			"xor %%ah, %%ah\n"
+			"1:"
+			: "=d" (signature),
+			  "=a" (eax),
+			  "=b" (ebx),
+			  "=c" (ecx)
+			: "1" (PCIBIOS_PCI_BIOS_PRESENT),
+			  "D" (&pci_indirect)
+			: "memory");
+		__restore_flags(flags);
+
+		status = (eax >> 8) & 0xff;
+		hw_mech = eax & 0xff;
+		major_ver = (ebx >> 8) & 0xff;
+		minor_ver = ebx & 0xff;
+		last_bus = ecx & 0xff;
+		DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
+			status, hw_mech, major_ver, minor_ver, last_bus);
+		if (status || signature != PCI_SIGNATURE) {
+			printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found, report to <mj@ucw.cz>\n",
+				status, signature);
+			return 0;
+		}
+		printk("PCI: PCI BIOS revision %x.%02x entry at 0x%lx\n",
+			major_ver, minor_ver, pcibios_entry);
+#ifdef CONFIG_PCI_DIRECT
+		if (!(hw_mech & PCIBIOS_HW_TYPE1))
+			pci_probe &= ~PCI_PROBE_CONF1;
+		if (!(hw_mech & PCIBIOS_HW_TYPE2))
+			pci_probe &= ~PCI_PROBE_CONF2;
+#endif
+		return 1;
+	}
+	return 0;
+}
+
+static int __init pci_bios_find_device (unsigned short vendor, unsigned short device_id,
+					unsigned short index, unsigned char *bus, unsigned char *device_fn)
+{
+	unsigned short bx;
+	unsigned short ret;
+
+	__asm__("lcall (%%edi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=b" (bx),
+		  "=a" (ret)
+		: "1" (PCIBIOS_FIND_PCI_DEVICE),
+		  "c" (device_id),
+		  "d" (vendor),
+		  "S" ((int) index),
+		  "D" (&pci_indirect));
+	*bus = (bx >> 8) & 0xff;
+	*device_fn = bx & 0xff;
+	return (int) (ret & 0xff00) >> 8;
+}
+
+static int pci_bios_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	unsigned long ret;
+	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
+
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=c" (*value),
+		  "=a" (ret)
+		: "1" (PCIBIOS_READ_CONFIG_BYTE),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	return (int) (ret & 0xff00) >> 8;
+}
+
+static int pci_bios_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	unsigned long ret;
+	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
+
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=c" (*value),
+		  "=a" (ret)
+		: "1" (PCIBIOS_READ_CONFIG_WORD),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	return (int) (ret & 0xff00) >> 8;
+}
+
+static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	unsigned long ret;
+	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
+
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=c" (*value),
+		  "=a" (ret)
+		: "1" (PCIBIOS_READ_CONFIG_DWORD),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	return (int) (ret & 0xff00) >> 8;
+}
+
+static int pci_bios_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	unsigned long ret;
+	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
+
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=a" (ret)
+		: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
+		  "c" (value),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	return (int) (ret & 0xff00) >> 8;
+}
+
+static int pci_bios_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	unsigned long ret;
+	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
+
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=a" (ret)
+		: "0" (PCIBIOS_WRITE_CONFIG_WORD),
+		  "c" (value),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	return (int) (ret & 0xff00) >> 8;
+}
+
+static int pci_bios_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	unsigned long ret;
+	unsigned long bx = (dev->bus->number << 8) | dev->devfn;
+
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=a" (ret)
+		: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
+		  "c" (value),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	return (int) (ret & 0xff00) >> 8;
+}
+
+/*
+ * Function table for BIOS32 access
+ */
+
+static struct pci_ops pci_bios_access = {
+      pci_bios_read_config_byte,
+      pci_bios_read_config_word,
+      pci_bios_read_config_dword,
+      pci_bios_write_config_byte,
+      pci_bios_write_config_word,
+      pci_bios_write_config_dword
+};
+
+/*
+ * Try to find PCI BIOS.
+ */
+
+static struct pci_ops * __init pci_find_bios(void)
+{
+	union bios32 *check;
+	unsigned char sum;
+	int i, length;
+
+	/*
+	 * Follow the standard procedure for locating the BIOS32 Service
+	 * directory by scanning the permissible address range from
+	 * 0xe0000 through 0xfffff for a valid BIOS32 structure.
+	 */
+
+	for (check = (union bios32 *) __va(0xe0000);
+	     check <= (union bios32 *) __va(0xffff0);
+	     ++check) {
+		if (check->fields.signature != BIOS32_SIGNATURE)
+			continue;
+		length = check->fields.length * 16;
+		if (!length)
+			continue;
+		sum = 0;
+		for (i = 0; i < length ; ++i)
+			sum += check->chars[i];
+		if (sum != 0)
+			continue;
+		if (check->fields.revision != 0) {
+			printk("PCI: unsupported BIOS32 revision %d at 0x%p, report to <mj@ucw.cz>\n",
+				check->fields.revision, check);
+			continue;
+		}
+		DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
+		if (check->fields.entry >= 0x100000) {
+			printk("PCI: BIOS32 entry (0x%p) in high memory, cannot use.\n", check);
+			return NULL;
+		} else {
+			unsigned long bios32_entry = check->fields.entry;
+			DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
+			bios32_indirect.address = bios32_entry + PAGE_OFFSET;
+			if (check_pcibios())
+				return &pci_bios_access;
+		}
+		break;	/* Hopefully more than one BIOS32 cannot happen... */
+	}
+
+	return NULL;
+}
+
+/*
+ * Sort the device list according to PCI BIOS. Nasty hack, but since some
+ * fool forgot to define the `correct' device order in the PCI BIOS specs
+ * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
+ * which used BIOS ordering, we are bound to do this...
+ */
+
+static void __init pcibios_sort(void)
+{
+	struct pci_dev *dev = pci_devices;
+	struct pci_dev **last = &pci_devices;
+	struct pci_dev *d, **dd, *e;
+	int idx;
+	unsigned char bus, devfn;
+
+	DBG("PCI: Sorting device list...\n");
+	while ((e = dev)) {
+		idx = 0;
+		while (pci_bios_find_device(e->vendor, e->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
+			idx++;
+			for(dd=&dev; (d = *dd); dd = &d->next) {
+				if (d->bus->number == bus && d->devfn == devfn) {
+					*dd = d->next;
+					*last = d;
+					last = &d->next;
+					break;
+				}
+			}
+			if (!d) {
+				printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
+				/*
+				 * We must not continue scanning as several buggy BIOSes
+				 * return garbage after the last device. Grr.
+				 */
+				break;
+			}
+		}
+		if (e == dev) {
+			printk("PCI: Device %02x:%02x not found by BIOS\n",
+				dev->bus->number, dev->devfn);
+			d = dev;
+			dev = dev->next;
+			*last = d;
+			last = &d->next;
+		}
+	}
+	*last = NULL;
+}
+
+/*
+ *  Ask BIOS for IRQ Routing Table
+ */
+
+struct irq_routing_options {
+	u16 size;
+	struct irq_info *table;
+	u16 segment;
+} __attribute__((packed));
+
+static unsigned long pcibios_irq_page __initdata = 0;
+
+static inline void __init pcibios_free_irq_routing_table(void)
+{
+	if (pcibios_irq_page)
+		free_page(pcibios_irq_page);
+}
+
+static struct irq_routing_table * __init pcibios_get_irq_routing_table(void)
+{
+	struct irq_routing_options opt;
+	struct irq_routing_table *rt;
+	int ret, map;
+
+	if (pci_probe & PCI_NO_IRQ_SCAN)
+		return NULL;
+	pcibios_irq_page = __get_free_page(GFP_KERNEL);
+	if (!pcibios_irq_page)
+		return 0;
+	rt = (void *) pcibios_irq_page;
+	opt.table = rt->slots;
+	opt.size = PAGE_SIZE - sizeof(struct irq_routing_table);
+	opt.segment = __KERNEL_DS;
+
+	DBG("PCI: Fetching IRQ routing table... ");
+	__asm__("push %%es\n\t"
+		"push %%ds\n\t"
+		"pop  %%es\n\t"
+		"lcall (%%esi)\n\t"
+		"pop %%es\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=a" (ret),
+		  "=b" (map)
+		: "0" (PCIBIOS_GET_ROUTING_OPTIONS),
+		  "1" (0),
+		  "D" ((long) &opt),
+		  "S" (&pci_indirect));
+	DBG("OK  ret=%d, size=%d, map=%x\n", ret, opt.size, map);
+	if (ret & 0xff00) {
+		printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
+		return 0;
+	}
+
+	memset(rt, 0, sizeof(struct irq_routing_table));
+	rt->size = opt.size + sizeof(struct irq_routing_table);
+	printk("PCI: Using BIOS Interrupt Routing Table\n");
+	return rt;
+}
+
+#endif
+
+/*
+ * Several buggy motherboards address only 16 devices and mirror
+ * them to next 16 IDs. We try to detect this `feature' on all
+ * primary buses (those containing host bridges as they are
+ * expected to be unique) and remove the ghost devices.
+ */
+
+static void __init pcibios_fixup_ghosts(struct pci_bus *b)
+{
+	struct pci_dev *d, *e, **z;
+	int mirror = PCI_DEVFN(16,0);
+	int seen_host_bridge = 0;
+	int i;
+
+	DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
+	for(d=b->devices; d && d->devfn < mirror; d=d->sibling) {
+		if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+			seen_host_bridge++;
+		for(e=d->next; e; e=e->sibling) {
+			if (e->devfn != d->devfn + mirror ||
+			    e->vendor != d->vendor ||
+			    e->device != d->device ||
+			    e->class != d->class)
+				continue;
+			for(i=0; i<PCI_NUM_RESOURCES; i++)
+				if (e->resource[i].start != d->resource[i].start ||
+				    e->resource[i].end != d->resource[i].end ||
+				    e->resource[i].flags != d->resource[i].flags)
+					continue;
+			break;
+		}
+		if (!e)
+			return;
+	}
+	if (!seen_host_bridge)
+		return;
+	printk("PCI: Ignoring ghost devices on bus %02x\n", b->number);
+	for(e=b->devices; e->sibling != d; e=e->sibling);
+	e->sibling = NULL;
+	for(z=&pci_devices; (d=*z);)
+		if (d->bus == b && d->devfn >= mirror) {
+			*z = d->next;
+			kfree_s(d, sizeof(*d));
+		} else
+			z = &d->next;
+}
+
+/*
+ * In case there are peer host bridges, scan bus behind each of them.
+ * Although several sources claim that the host bridges should have
+ * header type 1 and be assigned a bus number as for PCI2PCI bridges,
+ * the reality doesn't pass this test and the bus number is usually
+ * set by BIOS to the first free value.
+ */
+static void __init pcibios_fixup_peer_bridges(void)
+{
+	struct pci_bus *b = pci_root;
+	int n, cnt=-1;
+	struct pci_dev *d;
+	struct pci_ops *ops = pci_root->ops;
+
+#ifdef CONFIG_PCI_DIRECT
+	/*
+	 * Don't search for peer host bridges if we use config type 2
+	 * since it reads bogus values for non-existent buses and
+	 * chipsets supporting multiple primary buses use conf1 anyway.
+	 */
+	if (ops == &pci_direct_conf2)
+		return;
+#endif
+
+	for(d=b->devices; d; d=d->sibling)
+		if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+			cnt++;
+	n = b->subordinate + 1;
+	while (n <= 0xff) {
+		int found = 0;
+		u16 l;
+		struct pci_bus bus;
+		struct pci_dev dev;
+		bus.number = n;
+		bus.ops = ops;
+		dev.bus = &bus;
+		for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
+			if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
+			    l != 0x0000 && l != 0xffff) {
+#ifdef CONFIG_PCI_BIOS
+				if (pci_bios_present) {
+					int err, idx = 0;
+					u8 bios_bus, bios_dfn;
+					u16 d;
+					pci_read_config_word(&dev, PCI_DEVICE_ID, &d);
+					DBG("BIOS test for %02x:%02x (%04x:%04x)\n", n, dev.devfn, l, d);
+					while (!(err = pci_bios_find_device(l, d, idx, &bios_bus, &bios_dfn)) &&
+					       (bios_bus != n || bios_dfn != dev.devfn))
+						idx++;
+					if (err)
+						break;
+				}
+#endif
+				DBG("Found device at %02x:%02x\n", n, dev.devfn);
+				found++;
+				if (!pci_read_config_word(&dev, PCI_CLASS_DEVICE, &l) &&
+				    l == PCI_CLASS_BRIDGE_HOST)
+					cnt++;
+			}
+		if (cnt-- <= 0)
+			break;
+		if (found) {
+			printk("PCI: Discovered primary peer bus %02x\n", n);
+			b = pci_scan_bus(n, ops, NULL);
+			if (b)
+				n = b->subordinate;
+		}
+		n++;
+	}
+}
+
+/*
+ * Exceptions for specific devices. Usually work-arounds for fatal design flaws.
+ */
+
+static void __init pci_fixup_i450nx(struct pci_dev *d)
+{
+	/*
+	 * i450NX -- Find and scan all secondary buses on all PXB's.
+	 */
+	int pxb, reg;
+	u8 busno, suba, subb;
+	printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
+	reg = 0xd0;
+	for(pxb=0; pxb<2; pxb++) {
+		pci_read_config_byte(d, reg++, &busno);
+		pci_read_config_byte(d, reg++, &suba);
+		pci_read_config_byte(d, reg++, &subb);
+		DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
+		if (busno)
+			pci_scan_bus(busno, pci_root->ops, NULL);	/* Bus A */
+		if (suba < subb)
+			pci_scan_bus(suba+1, pci_root->ops, NULL);	/* Bus B */
+	}
+	pci_probe |= PCI_NO_PEER_FIXUP;
+}
+
+static void __init pci_fixup_umc_ide(struct pci_dev *d)
+{
+	/*
+	 * UM8886BF IDE controller sets region type bits incorrectly,
+	 * therefore they look like memory despite of them being I/O.
+	 */
+	int i;
+
+	printk("PCI: Fixing base address flags for device %s\n", d->slot_name);
+	for(i=0; i<4; i++)
+		d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
+}
+
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+	int i;
+
+	/*
+	 * PCI IDE controllers use non-standard I/O port decoding, respect it.
+	 */
+	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+		return;
+	DBG("PCI: IDE base address fixup for %s\n", d->slot_name);
+	for(i=0; i<4; i++) {
+		struct resource *r = &d->resource[i];
+		if ((r->start & ~0x80) == 0x374) {
+			r->start |= 2;
+			r->end = r->start;
+		}
+	}
+}
+
+struct pci_fixup pcibios_fixups[] = {
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_UMC,	PCI_DEVICE_ID_UMC_UM8886BF,	pci_fixup_umc_ide },
+	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pci_fixup_ide_bases },
+	{ 0 }
+};
+
+/*
+ *  Fix up IRQs of all PCI devices.
+ */
+
+extern int skip_ioapic_setup;
+
+#define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
+#define PIRQ_VERSION 0x0100
+
+/*
+ *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
+ */
+
+static struct irq_routing_table * __init pcibios_find_irq_routing_table(void)
+{
+	u8 *addr;
+	struct irq_routing_table *rt;
+	int i;
+	u8 sum;
+
+	for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
+		rt = (struct irq_routing_table *) addr;
+		if (rt->signature != PIRQ_SIGNATURE ||
+		    rt->version != PIRQ_VERSION ||
+		    rt->size % 16 ||
+		    rt->size < sizeof(struct irq_routing_table))
+			continue;
+		sum = 0;
+		for(i=0; i<rt->size; i++)
+			sum += addr[i];
+		if (!sum) {
+			printk("PCI: Interrupt Routing Table found at 0x%p [router type %04x/%04x]\n",
+			       rt, rt->rtr_vendor, rt->rtr_device);
+			return rt;
+		}
+	}
+	return NULL;
+}
+
+/*
+ *  If we have a IRQ routing table, use it to search for peer host
+ *  bridges.  It's a gross hack, but since there are no other known
+ *  ways how to get a list of buses, we have to go this way.
+ */
+
+static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt)
+{
+	u8 busmap[256];
+	int i;
+	struct irq_info *e;
+
+	memset(busmap, 0, sizeof(busmap));
+	for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) {
+		e = &rt->slots[i];
+		DBG("b=%02x d=%02x s=%02x\n", e->bus, e->devfn, e->slot);
+		busmap[e->bus] = 1;
+	}
+	for(i=1; i<256; i++)
+		/*
+		 *  It might be a secondary bus, but in this case its parent is already
+		 *  known (ascending bus order) and therefore pci_scan_bus returns immediately.
+		 */
+		if (busmap[i] && pci_scan_bus(i, pci_root->ops, NULL))
+			printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i);
+	pci_probe |= PCI_NO_PEER_FIXUP;
+}
+
+/*
+ *  In case BIOS forgets to tell us about IRQ, we try to look it up in the routing
+ *  table, but unfortunately we have to know the interrupt router chip.
+ */
+
+static char * __init pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin)
+{
+	struct irq_info *q;
+	struct pci_dev *router;
+	int i, pirq, newirq;
+	u32 rtrid, mask;
+	u8 x;
+
+	pin--;
+	DBG("IRQ for %s(%d)", dev->slot_name, pin);
+	while (dev->bus->self) {
+		pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+		dev = dev->bus->self;
+		DBG(" -> %s(%d)", dev->slot_name, pin);
+	}
+	for(q = rt->slots, i = rt->size - sizeof(struct irq_routing_table);
+	    i && (q->bus != dev->bus->number || PCI_SLOT(q->devfn) != PCI_SLOT(dev->devfn));
+	    i -= sizeof(struct irq_info), q++)
+		;
+	if (!i) {
+		DBG(" -> not found in routing table\n");
+		return NULL;
+	}
+	pirq = q->irq[pin].link;
+	mask = q->irq[pin].bitmap;
+	if (!pirq) {
+		DBG(" -> not routed\n");
+		return NULL;
+	}
+	DBG(" -> PIRQ %02x, mask %04x", pirq, mask);
+	if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+		newirq = 0;
+	else for(newirq = 15; newirq && !(mask & (1 << newirq)); newirq--)
+		;
+	if (!(router = pci_find_slot(rt->rtr_bus, rt->rtr_devfn))) {
+		DBG(" -> router not found\n");
+		return NULL;
+	}
+#define ID(x,y) ((x << 16) | y)
+	rtrid = ID(rt->rtr_vendor, rt->rtr_device);
+	if (!rtrid) {
+		/*
+		 * Several BIOSes forget to set the router type. In such cases, we
+		 * use chip vendor/device. This doesn't guarantee us semantics of
+		 * PIRQ values, but was found to work in practice and it's still
+		 * better than not trying.
+		 */
+		DBG(" [%s]", router->slot_name);
+		rtrid = ID(router->vendor, router->device);
+	}
+	switch (rtrid) {
+	case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0):
+	case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0):
+	case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0):
+		/* Intel PIIX: PIRQ holds configuration register address */
+		pci_read_config_byte(router, pirq, &x);
+		if (x < 16) {
+			DBG(" -> [PIIX] %02x\n", x);
+			dev->irq = x;
+			return "PIIX";
+		} else if (newirq) {
+			DBG(" -> [PIIX] set to %02x\n", newirq);
+			pci_write_config_byte(router, pirq, newirq);
+			dev->irq = newirq;
+			return "PIIX-NEW";
+		}
+		DBG(" -> [PIIX] sink\n");
+		return NULL;
+	default:
+		DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device);
+		if (newirq && mask == (1 << newirq)) {
+			/* Only one IRQ available -> use it */
+			dev->irq = newirq;
+			return "guess";
+		}
+		return NULL;
+	}
+#undef ID
+}
+
+static void __init pcibios_fixup_irqs(void)
+{
+	struct irq_routing_table *rtable;
+	struct pci_dev *dev;
+	u8 pin;
+
+	rtable = pcibios_find_irq_routing_table();
+#ifdef CONFIG_PCI_BIOS
+	if (!rtable && pci_bios_present)
+		rtable = pcibios_get_irq_routing_table();
+#endif
+
+	if (rtable)
+		pcibios_irq_peer_trick(rtable);
+
+	for(dev=pci_devices; dev; dev=dev->next) {
+		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+#if defined(CONFIG_X86_IO_APIC)
+		/*
+		 * Recalculate IRQ numbers if we use the I/O APIC.
+		 */
+		if(!skip_ioapic_setup)
+		{
+			int irq;
+
+			if (pin) {
+				pin--;		/* interrupt pins are numbered starting from 1 */
+				irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
+				if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
+					struct pci_dev * bridge = dev->bus->self;
+
+					pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+					irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
+							PCI_SLOT(bridge->devfn), pin);
+					if (irq >= 0)
+						printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
+							bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
+				}
+				if (irq >= 0) {
+					printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
+						dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
+					dev->irq = irq;
+				}
+			}
+			rtable = NULL;	/* Avoid IRQ assignment below */
+		}
+#endif
+		/*
+		 * Fix out-of-range IRQ numbers and missing IRQs.
+		 */
+		if (dev->irq >= NR_IRQS)
+			dev->irq = 0;
+		if (pin && !dev->irq && rtable && rtable->version) {
+			char *msg = pcibios_lookup_irq(dev, rtable, pin);
+			if (msg)
+				printk("PCI: Assigned IRQ %d to device %s [%s]\n", dev->irq, dev->slot_name, msg);
+		}
+	}
+
+#ifdef CONFIG_PCI_BIOS
+	pcibios_free_irq_routing_table();
+#endif
+}
+
+/*
+ *  Called after each bus is probed, but before its children
+ *  are examined.
+ */
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+	pcibios_fixup_ghosts(b);
+	pci_read_bridge_bases(b);
+}
+
+/*
+ * Initialization. Try all known PCI access methods. Note that we support
+ * using both PCI BIOS and direct access: in such cases, we use I/O ports
+ * to access config space, but we still keep BIOS order of cards to be
+ * compatible with 2.0.X. This should go away some day.
+ */
+
+void __init pcibios_init(void)
+{
+	struct pci_ops *bios = NULL;
+	struct pci_ops *dir = NULL;
+	struct pci_ops *ops;
+
+#ifdef CONFIG_PCI_BIOS
+	if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) {
+		pci_probe |= PCI_BIOS_SORT;
+		pci_bios_present = 1;
+	}
+#endif
+#ifdef CONFIG_PCI_DIRECT
+	if (pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2))
+		dir = pci_check_direct();
+#endif
+	if (dir)
+		ops = dir;
+	else if (bios)
+		ops = bios;
+	else {
+		printk("PCI: No PCI bus detected\n");
+		return;
+	}
+
+	printk("PCI: Probing PCI hardware\n");
+	pci_scan_bus(0, ops, NULL);
+
+	pcibios_fixup_irqs();
+	if (!(pci_probe & PCI_NO_PEER_FIXUP))
+		pcibios_fixup_peer_bridges();
+	pcibios_resource_survey();
+
+#ifdef CONFIG_PCI_BIOS
+	if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
+		pcibios_sort();
+#endif
+}
+
+char * __init pcibios_setup(char *str)
+{
+	if (!strcmp(str, "off")) {
+		pci_probe = 0;
+		return NULL;
+	}
+#ifdef CONFIG_PCI_BIOS
+	else if (!strcmp(str, "bios")) {
+		pci_probe = PCI_PROBE_BIOS;
+		return NULL;
+	} else if (!strcmp(str, "nobios")) {
+		pci_probe &= ~PCI_PROBE_BIOS;
+		return NULL;
+	} else if (!strcmp(str, "nosort")) {
+		pci_probe |= PCI_NO_SORT;
+		return NULL;
+	} else if (!strcmp(str, "noirq")) {
+		pci_probe |= PCI_NO_IRQ_SCAN;
+		return NULL;
+	}
+#endif
+#ifdef CONFIG_PCI_DIRECT
+	else if (!strcmp(str, "conf1")) {
+		pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
+		return NULL;
+	}
+	else if (!strcmp(str, "conf2")) {
+		pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
+		return NULL;
+	}
+#endif
+	else if (!strcmp(str, "nopeer")) {
+		pci_probe |= PCI_NO_PEER_FIXUP;
+		return NULL;
+	} else if (!strcmp(str, "rom")) {
+		pci_probe |= PCI_ASSIGN_ROMS;
+		return NULL;
+	}
+	return str;
+}
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/pci-visws.c linux/arch/i386/kernel/pci-visws.c
--- v2.3.19/linux/arch/i386/kernel/pci-visws.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/kernel/pci-visws.c	Fri Oct  8 10:06:21 1999
@@ -0,0 +1,131 @@
+/*
+ *	Low-Level PCI Support for SGI Visual Workstation
+ *
+ *	(c) 1999 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/smp.h>
+#include <asm/lithium.h>
+
+#include "pci-i386.h"
+
+unsigned int pci_probe = 0;
+
+/*
+ *  The VISWS uses configuration access type 1 only.
+ */
+
+#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
+
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	*value = inb(0xCFC + (where&3));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);    
+	*value = inw(0xCFC + (where&2));
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	*value = inl(0xCFC);
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);    
+	outb(value, 0xCFC + (where&3));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	outw(value, 0xCFC + (where&2));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	outl(value, 0xCFC);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+static struct pci_ops visws_pci_ops = {
+	pci_conf1_read_config_byte,
+	pci_conf1_read_config_word,
+	pci_conf1_read_config_dword,
+	pci_conf1_write_config_byte,
+	pci_conf1_write_config_word,
+	pci_conf1_write_config_dword
+};
+
+static void __init pcibios_fixup_irqs(void)
+{
+	struct pci_dev *dev, *p;
+	u8 pin;
+	int irq;
+
+	for(dev=pci_devices; dev; dev=dev->next) {
+		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+		dev->irq = 0;
+		if (!pin)
+			continue;
+		pin--;
+		if (dev->bus->parent) {
+			p = dev->bus->parent->self;
+			pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+		} else
+			p = dev;
+		irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1);
+		if (irq >= 0)
+			dev->irq = irq;
+		DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq);
+	}
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+	pci_read_bridge_bases(b);
+}
+
+#if 0
+static struct resource visws_pci_bus_resources[2] = {
+	{ "Host bus 1", 0xf4000000, 0xf7ffffff, 0 },
+	{ "Host bus 2", 0xf0000000, 0xf3ffffff, 0 }
+};
+#endif
+
+void __init pcibios_init(void)
+{
+	unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
+
+	printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus);
+	pci_scan_bus(0, &visws_pci_ops, NULL);
+	pci_scan_bus(sec_bus, &visws_pci_ops, NULL);
+	pcibios_fixup_irqs();
+	pcibios_resource_survey();
+}
+
+char * __init pcibios_setup(char *str)
+{
+	return str;
+}
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.3.19/linux/arch/i386/kernel/smp.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/i386/kernel/smp.c	Thu Oct  7 10:17:08 1999
@@ -1,1427 +1,108 @@
 /*
- *	Intel MP v1.1/v1.4 specification support routines for multi-pentium
- *	hosts.
+ *	Intel SMP support routines.
  *
  *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
- *	(c) 1998 Ingo Molnar
+ *	(c) 1998-99 Ingo Molnar <mingo@redhat.com>
  *
- *	Supported by Caldera http://www.caldera.com.
- *	Much of the core SMP work is based on previous work by Thomas Radke, to
- *	whom a great many thanks are extended.
- *
- *	Thanks to Intel for making available several different Pentium,
- *	Pentium Pro and Pentium-II/Xeon MP machines.
- *
- *	This code is released under the GNU public license version 2 or
- *	later.
- *
- *	Fixes
- *		Felix Koop	:	NR_CPUS used properly
- *		Jose Renau	:	Handle single CPU case.
- *		Alan Cox	:	By repeated request 8) - Total BogoMIP report.
- *		Greg Wright	:	Fix for kernel stacks panic.
- *		Erich Boleyn	:	MP v1.4 and additional changes.
- *	Matthias Sattler	:	Changes for 2.1 kernel map.
- *	Michel Lespinasse	:	Changes for 2.1 kernel map.
- *	Michael Chastain	:	Change trampoline.S to gnu as.
- *		Alan Cox	:	Dumb bug: 'B' step PPro's are fine
- *		Ingo Molnar	:	Added APIC timers, based on code
- *					from Jose Renau
- *		Alan Cox	:	Added EBDA scanning
- *		Ingo Molnar	:	various cleanups and rewrites
- *		Tigran Aivazian	:	fixed "0.00 in /proc/uptime on SMP" bug.
- */
-
-#include <linux/config.h>
-#include <linux/mm.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
-#include <linux/mc146818rtc.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <asm/mtrr.h>
-#include <asm/msr.h>
-
-#include <linux/irq.h>
-
-#define JIFFIE_TIMEOUT 100
-
-extern void update_one_process( struct task_struct *p,
-				unsigned long ticks, unsigned long user,
-				unsigned long system, int cpu);
-/*
- *	Some notes on processor bugs:
- *
- *	Pentium and Pentium Pro (and all CPUs) have bugs. The Linux issues
- *	for SMP are handled as follows.
- *
- *	Pentium Pro
- *		Occasional delivery of 'spurious interrupt' as trap #16. This
- *	is very rare. The kernel logs the event and recovers
- *
- *	Pentium
- *		There is a marginal case where REP MOVS on 100MHz SMP
- *	machines with B stepping processors can fail. XXX should provide
- *	an L1cache=Writethrough or L1cache=off option.
- *
- *		B stepping CPUs may hang. There are hardware work arounds
- *	for this. We warn about it in case your board doesnt have the work
- *	arounds. Basically thats so I can tell anyone with a B stepping
- *	CPU and SMP problems "tough".
- *
- *	Specific items [From Pentium Processor Specification Update]
- *
- *	1AP.	Linux doesn't use remote read
- *	2AP.	Linux doesn't trust APIC errors
- *	3AP.	We work around this
- *	4AP.	Linux never generated 3 interrupts of the same priority
- *		to cause a lost local interrupt.
- *	5AP.	Remote read is never used
- *	9AP.	XXX NEED TO CHECK WE HANDLE THIS XXX
- *	10AP.	XXX NEED TO CHECK WE HANDLE THIS XXX
- *	11AP.	Linux reads the APIC between writes to avoid this, as per
- *		the documentation. Make sure you preserve this as it affects
- *		the C stepping chips too.
- *
- *	If this sounds worrying believe me these bugs are ___RARE___ and
- *	there's about nothing of note with C stepping upwards.
- */
-
-
-/* Kernel spinlock */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
-
-/*
- * function prototypes:
- */
-static void cache_APIC_registers (void);
-static void stop_this_cpu (void);
-
-static int smp_b_stepping = 0;				/* Set if we find a B stepping CPU			*/
-
-static int max_cpus = -1;				/* Setup configured maximum number of CPUs to activate	*/
-int smp_found_config=0;					/* Have we found an SMP box 				*/
-
-unsigned long cpu_present_map = 0;			/* Bitmask of physically existing CPUs 				*/
-unsigned long cpu_online_map = 0;			/* Bitmask of currently online CPUs 				*/
-int smp_num_cpus = 0;					/* Total count of live CPUs 				*/
-int smp_threads_ready=0;				/* Set when the idlers are all forked 			*/
-volatile int cpu_number_map[NR_CPUS];			/* which CPU maps to which logical number		*/
-volatile int __cpu_logical_map[NR_CPUS];			/* which logical number maps to which CPU		*/
-static volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};	/* We always use 0 the rest is ready for parallel delivery */
-static volatile unsigned long cpu_callout_map[NR_CPUS] = {0,};	/* We always use 0 the rest is ready for parallel delivery */
-volatile unsigned long smp_invalidate_needed;		/* Used for the invalidate map that's also checked in the spinlock */
-volatile unsigned long kstack_ptr;			/* Stack vector for booting CPUs			*/
-struct cpuinfo_x86 cpu_data[NR_CPUS];			/* Per CPU bogomips and other parameters 		*/
-static unsigned int num_processors = 1;			/* Internal processor count				*/
-unsigned long mp_ioapic_addr = 0xFEC00000;		/* Address of the I/O apic (not yet used) 		*/
-unsigned char boot_cpu_id = 0;				/* Processor that is doing the boot up 			*/
-static int smp_activated = 0;				/* Tripped once we need to start cross invalidating 	*/
-int apic_version[NR_CPUS];				/* APIC version number					*/
-unsigned long apic_retval;				/* Just debugging the assembler.. 			*/
-
-volatile unsigned long kernel_counter=0;		/* Number of times the processor holds the lock		*/
-volatile unsigned long syscall_count=0;			/* Number of times the processor holds the syscall lock	*/
-
-volatile unsigned long ipi_count;			/* Number of IPIs delivered				*/
-
-const char lk_lockmsg[] = "lock from interrupt context at %p\n"; 
-
-int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
-extern int nr_ioapics;
-extern struct mpc_config_ioapic mp_apics [MAX_IO_APICS];
-extern int mp_irq_entries;
-extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
-extern int mpc_default_type;
-int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, };
-int mp_current_pci_id = 0;
-unsigned long mp_lapic_addr = 0;
-int skip_ioapic_setup = 0;				/* 1 if "noapic" boot option passed */
-
-/* #define SMP_DEBUG */
-
-#ifdef SMP_DEBUG
-#define SMP_PRINTK(x)	printk x
-#else
-#define SMP_PRINTK(x)
-#endif
-
-/*
- * IA s/w dev Vol 3, Section 7.4
- */
-#define APIC_DEFAULT_PHYS_BASE 0xfee00000
-
-#define CLEAR_TSC wrmsr(0x10, 0x00001000, 0x00001000)
-
-/*
- *	Setup routine for controlling SMP activation
- *
- *	Command-line option of "nosmp" or "maxcpus=0" will disable SMP
- *      activation entirely (the MPS table probe still happens, though).
- *
- *	Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
- *	greater than 0, limits the maximum number of CPUs activated in
- *	SMP mode to <NUM>.
- */
-
-static int __init nosmp(char *str)
-{
-	max_cpus = 0;
-	return 1;
-}
-
-__setup("nosmp", nosmp);
-
-static int __init maxcpus(char *str)
-{
-	get_option(&str, &max_cpus);
-	return 1;
-}
-
-__setup("maxcpus=", maxcpus);
-
-void ack_APIC_irq(void)
-{
-	/* Clear the IPI */
-
-	/* Dummy read */
-	apic_read(APIC_SPIV);
-
-	/* Docs say use 0 for future compatibility */
-	apic_write(APIC_EOI, 0);
-}
-
-/*
- * Intel MP BIOS table parsing routines:
- */
-
-#ifndef CONFIG_X86_VISWS_APIC
-/*
- *	Checksum an MP configuration block.
- */
-
-static int mpf_checksum(unsigned char *mp, int len)
-{
-	int sum=0;
-	while(len--)
-		sum+=*mp++;
-	return sum&0xFF;
-}
-
-/*
- *	Processor encoding in an MP configuration block
- */
-
-static char *mpc_family(int family,int model)
-{
-	static char n[32];
-	static char *model_defs[]=
-	{
-		"80486DX","80486DX",
-		"80486SX","80486DX/2 or 80487",
-		"80486SL","Intel5X2(tm)",
-		"Unknown","Unknown",
-		"80486DX/4"
-	};
-	if (family==0x6)
-		return("Pentium(tm) Pro");
-	if (family==0x5)
-		return("Pentium(tm)");
-	if (family==0x0F && model==0x0F)
-		return("Special controller");
-	if (family==0x04 && model<9)
-		return model_defs[model];
-	sprintf(n,"Unknown CPU [%d:%d]",family, model);
-	return n;
-}
-
-
-/*
- *	Read the MPC
- */
-
-static int __init smp_read_mpc(struct mp_config_table *mpc)
-{
-	char str[16];
-	int count=sizeof(*mpc);
-	int ioapics = 0;
-	unsigned char *mpt=((unsigned char *)mpc)+count;
-
-	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4))
-	{
-		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
-			mpc->mpc_signature[0],
-			mpc->mpc_signature[1],
-			mpc->mpc_signature[2],
-			mpc->mpc_signature[3]);
-		return 1;
-	}
-	if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length))
-	{
-		panic("SMP mptable: checksum error!\n");
-		return 1;
-	}
-	if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04)
-	{
-		printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec);
-		return 1;
-	}
-	memcpy(str,mpc->mpc_oem,8);
-	str[8]=0;
-	printk("OEM ID: %s ",str);
-	
-	memcpy(str,mpc->mpc_productid,12);
-	str[12]=0;
-	printk("Product ID: %s ",str);
-
-	printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
-
-	/* save the local APIC address, it might be non-default */
-	mp_lapic_addr = mpc->mpc_lapic;
-
-	/*
-	 *	Now process the configuration blocks.
-	 */
-	
-	while(count<mpc->mpc_length)
-	{
-		switch(*mpt)
-		{
-			case MP_PROCESSOR:
-			{
-				struct mpc_config_processor *m=
-					(struct mpc_config_processor *)mpt;
-				if (m->mpc_cpuflag&CPU_ENABLED)
-				{
-					printk("Processor #%d %s APIC version %d\n",
-						m->mpc_apicid,
-						mpc_family((m->mpc_cpufeature&
-							CPU_FAMILY_MASK)>>8,
-							(m->mpc_cpufeature&
-								CPU_MODEL_MASK)>>4),
-						m->mpc_apicver);
-#ifdef SMP_DEBUG
-					if (m->mpc_featureflag&(1<<0))
-						printk("    Floating point unit present.\n");
-					if (m->mpc_featureflag&(1<<7))
-						printk("    Machine Exception supported.\n");
-					if (m->mpc_featureflag&(1<<8))
-						printk("    64 bit compare & exchange supported.\n");
-					if (m->mpc_featureflag&(1<<9))
-						printk("    Internal APIC present.\n");
-#endif
-					if (m->mpc_cpuflag&CPU_BOOTPROCESSOR)
-					{
-						SMP_PRINTK(("    Bootup CPU\n"));
-						boot_cpu_id=m->mpc_apicid;
-					}
-					else	/* Boot CPU already counted */
-						num_processors++;
-
-					if (m->mpc_apicid>NR_CPUS)
-						printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS);
-					else
-					{
-						int ver = m->mpc_apicver;
-
-						cpu_present_map|=(1<<m->mpc_apicid);
-						/*
-						 * Validate version
-						 */
-						if (ver == 0x0) {
-							printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid);
-							ver = 0x10;
-						}
-						apic_version[m->mpc_apicid] = ver;
-					}
-				}
-				mpt+=sizeof(*m);
-				count+=sizeof(*m);
-				break;
-			}
-			case MP_BUS:
-			{
-				struct mpc_config_bus *m=
-					(struct mpc_config_bus *)mpt;
-				memcpy(str,m->mpc_bustype,6);
-				str[6]=0;
-				SMP_PRINTK(("Bus #%d is %s\n",
-					m->mpc_busid,
-					str));
-				if (strncmp(m->mpc_bustype,"ISA",3) == 0)
-					mp_bus_id_to_type[m->mpc_busid] =
-						MP_BUS_ISA;
-				else
-				if (strncmp(m->mpc_bustype,"EISA",4) == 0)
-					mp_bus_id_to_type[m->mpc_busid] =
-						MP_BUS_EISA;
-				if (strncmp(m->mpc_bustype,"PCI",3) == 0) {
-					mp_bus_id_to_type[m->mpc_busid] =
-						MP_BUS_PCI;
-					mp_bus_id_to_pci_bus[m->mpc_busid] =
-						mp_current_pci_id;
-					mp_current_pci_id++;
-				}
-				mpt+=sizeof(*m);
-				count+=sizeof(*m);
-				break;
-			}
-			case MP_IOAPIC:
-			{
-				struct mpc_config_ioapic *m=
-					(struct mpc_config_ioapic *)mpt;
-				if (m->mpc_flags&MPC_APIC_USABLE)
-				{
-					ioapics++;
-					printk("I/O APIC #%d Version %d at 0x%lX.\n",
-						m->mpc_apicid,m->mpc_apicver,
-						m->mpc_apicaddr);
-					mp_apics [nr_ioapics] = *m;
-					if (++nr_ioapics > MAX_IO_APICS)
-						--nr_ioapics;
-				}
-				mpt+=sizeof(*m);
-				count+=sizeof(*m);
-				break;
-			}
-			case MP_INTSRC:
-			{
-				struct mpc_config_intsrc *m=
-					(struct mpc_config_intsrc *)mpt;
-
-				mp_irqs [mp_irq_entries] = *m;
-				if (++mp_irq_entries == MAX_IRQ_SOURCES) {
-					printk("Max irq sources exceeded!!\n");
-					printk("Skipping remaining sources.\n");
-					--mp_irq_entries;
-				}
-
-				mpt+=sizeof(*m);
-				count+=sizeof(*m);
-				break;
-			}
-			case MP_LINTSRC:
-			{
-				struct mpc_config_intlocal *m=
-					(struct mpc_config_intlocal *)mpt;
-				mpt+=sizeof(*m);
-				count+=sizeof(*m);
-				break;
-			}
-		}
-	}
-	if (ioapics > MAX_IO_APICS)
-	{
-		printk("Warning: Max I/O APICs exceeded (max %d, found %d).\n", MAX_IO_APICS, ioapics);
-		printk("Warning: switching to non APIC mode.\n");
-		skip_ioapic_setup=1;
-	}
-	return num_processors;
-}
-
-/*
- *	Scan the memory blocks for an SMP configuration block.
- */
-
-static int __init smp_scan_config(unsigned long base, unsigned long length)
-{
-	unsigned long *bp=phys_to_virt(base);
-	struct intel_mp_floating *mpf;
-
-	SMP_PRINTK(("Scan SMP from %p for %ld bytes.\n",
-		bp,length));
-	if (sizeof(*mpf)!=16)
-		printk("Error: MPF size\n");
-
-	while (length>0)
-	{
-		if (*bp==SMP_MAGIC_IDENT)
-		{
-			mpf=(struct intel_mp_floating *)bp;
-			if (mpf->mpf_length==1 &&
-				!mpf_checksum((unsigned char *)bp,16) &&
-				(mpf->mpf_specification == 1
-				 || mpf->mpf_specification == 4) )
-			{
-				printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
-				if (mpf->mpf_feature2&(1<<7))
-					printk("    IMCR and PIC compatibility mode.\n");
-				else
-					printk("    Virtual Wire compatibility mode.\n");
-				smp_found_config=1;
-				/*
-				 *	Now see if we need to read further.
-				 */
-				if (mpf->mpf_feature1!=0)
-				{
-					unsigned long cfg;
-
-					/* local APIC has default address */
-					mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-					/*
-					 *	We need to know what the local
-					 *	APIC id of the boot CPU is!
-					 */
-
-/*
- *
- *	HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK
- *
- *	It's not just a crazy hack.  ;-)
- */
-					/*
-					 *	Standard page mapping
-					 *	functions don't work yet.
-					 *	We know that page 0 is not
-					 *	used.  Steal it for now!
-					 */
-			
-					cfg=pg0[0];
-					pg0[0] = (mp_lapic_addr | _PAGE_RW | _PAGE_PRESENT);
-					local_flush_tlb();
-
-					boot_cpu_id = GET_APIC_ID(*((volatile unsigned long *) APIC_ID));
-
-					/*
-					 *	Give it back
-					 */
-
-					pg0[0]= cfg;
-					local_flush_tlb();
-
-/*
- *
- *	END OF HACK   END OF HACK   END OF HACK   END OF HACK   END OF HACK
- *
- */
-					/*
-					 *	2 CPUs, numbered 0 & 1.
-					 */
-					cpu_present_map=3;
-					num_processors=2;
-					printk("I/O APIC at 0xFEC00000.\n");
-
-					/*
-					 * Save the default type number, we
-					 * need it later to set the IO-APIC
-					 * up properly:
-					 */
-					mpc_default_type = mpf->mpf_feature1;
-
-					printk("Bus #0 is ");
-				}
-				switch(mpf->mpf_feature1)
-				{
-					case 1:
-					case 5:
-						printk("ISA\n");
-						break;
-					case 2:
-						printk("EISA with no IRQ8 chaining\n");
-						break;
-					case 6:
-					case 3:
-						printk("EISA\n");
-						break;
-					case 4:
-					case 7:
-						printk("MCA\n");
-						break;
-					case 0:
-						break;
-					default:
-						printk("???\nUnknown standard configuration %d\n",
-							mpf->mpf_feature1);
-						return 1;
-				}
-				if (mpf->mpf_feature1>4)
-				{
-					printk("Bus #1 is PCI\n");
-
-					/*
-					 *	Set local APIC version to
-					 *	the integrated form.
-					 *	It's initialized to zero
-					 *	otherwise, representing
-					 *	a discrete 82489DX.
-					 */
-					apic_version[0] = 0x10;
-					apic_version[1] = 0x10;
-				}
-				/*
-				 *	Read the physical hardware table.
-				 *	Anything here will override the
-				 *	defaults.
-				 */
-				if (mpf->mpf_physptr)
-					smp_read_mpc((void *)mpf->mpf_physptr);
-
-				__cpu_logical_map[0] = boot_cpu_id;
-				global_irq_holder = boot_cpu_id;
-				current->processor = boot_cpu_id;
-
-				printk("Processors: %d\n", num_processors);
-				/*
-				 *	Only use the first configuration found.
-				 */
-				return 1;
-			}
-		}
-		bp+=4;
-		length-=16;
-	}
-
-	return 0;
-}
-
-void __init init_intel_smp (void)
-{
-	/*
-	 * FIXME: Linux assumes you have 640K of base ram..
-	 * this continues the error...
-	 *
-	 * 1) Scan the bottom 1K for a signature
-	 * 2) Scan the top 1K of base RAM
-	 * 3) Scan the 64K of bios
-	 */
-	if (!smp_scan_config(0x0,0x400) &&
-	    !smp_scan_config(639*0x400,0x400) &&
-	    !smp_scan_config(0xF0000,0x10000)) {
-		/*
-		 * If it is an SMP machine we should know now, unless the
-		 * configuration is in an EISA/MCA bus machine with an
-		 * extended bios data area. 
-		 *
-		 * there is a real-mode segmented pointer pointing to the
-		 * 4K EBDA area at 0x40E, calculate and scan it here.
-		 *
-		 * NOTE! There are Linux loaders that will corrupt the EBDA
-		 * area, and as such this kind of SMP config may be less
-		 * trustworthy, simply because the SMP table may have been
-		 * stomped on during early boot. These loaders are buggy and
-		 * should be fixed.
-		 */
-		unsigned int address;
-
-		address = *(unsigned short *)phys_to_virt(0x40E);
-		address<<=4;
-		smp_scan_config(address, 0x1000);
-		if (smp_found_config)
-			printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n");
-	}
-}
-
-#else
-
-/*
- * The Visual Workstation is Intel MP compliant in the hardware
- * sense, but it doesnt have a BIOS(-configuration table).
- * No problem for Linux.
- */
-void __init init_visws_smp(void)
-{
-	smp_found_config = 1;
-
-	cpu_present_map |= 2; /* or in id 1 */
-	apic_version[1] |= 0x10; /* integrated APIC */
-	apic_version[0] |= 0x10;
-
-	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-} 
-
-#endif
-
-/*
- * - Intel MP Configuration Table
- * - or SGI Visual Workstation configuration
- */
-void __init init_smp_config (void)
-{
-#ifndef CONFIG_VISWS
-	init_intel_smp();
-#else
-	init_visws_smp();
-#endif
-}
-
-
-
-/*
- *	Trampoline 80x86 program as an array.
- */
-
-extern unsigned char trampoline_data [];
-extern unsigned char trampoline_end  [];
-static unsigned char *trampoline_base;
-
-/*
- *	Currently trivial. Write the real->protected mode
- *	bootstrap into the page concerned. The caller
- *	has made sure it's suitably aligned.
- */
-
-static unsigned long __init setup_trampoline(void)
-{
-	memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
-	return virt_to_phys(trampoline_base);
-}
-
-/*
- *	We are called very early to get the low memory for the
- *	SMP bootup trampoline page.
- */
-unsigned long __init smp_alloc_memory(unsigned long mem_base)
-{
-	if (virt_to_phys((void *)mem_base) >= 0x9F000)
-		panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.", mem_base);
-	trampoline_base = (void *)mem_base;
-	return mem_base + PAGE_SIZE;
-}
-
-/*
- *	The bootstrap kernel entry code has set these up. Save them for
- *	a given CPU
- */
-
-void __init smp_store_cpu_info(int id)
-{
-	struct cpuinfo_x86 *c=&cpu_data[id];
-
-	*c = boot_cpu_data;
-	c->pte_quick = 0;
-	c->pgd_quick = 0;
-	c->pgtable_cache_sz = 0;
-	identify_cpu(c);
-	/*
-	 *	Mask B, Pentium, but not Pentium MMX
-	 */
-	if (c->x86_vendor == X86_VENDOR_INTEL &&
-	    c->x86 == 5 &&
-	    c->x86_mask >= 1 && c->x86_mask <= 4 &&
-	    c->x86_model <= 3)
-		smp_b_stepping=1;		/* Remember we have B step Pentia with bugs */
-}
-
-/*
- *	Architecture specific routine called by the kernel just before init is
- *	fired off. This allows the BP to have everything in order [we hope].
- *	At the end of this all the APs will hit the system scheduling and off
- *	we go. Each AP will load the system gdt's and jump through the kernel
- *	init into idle(). At this point the scheduler will one day take over
- * 	and give them jobs to do. smp_callin is a standard routine
- *	we use to track CPUs as they power up.
- */
-
-static atomic_t smp_commenced = ATOMIC_INIT(0);
-
-void __init smp_commence(void)
-{
-	/*
-	 *	Lets the callins below out of their loop.
-	 */
-	SMP_PRINTK(("Setting commenced=1, go go go\n"));
-
-	wmb();
-	atomic_set(&smp_commenced,1);
-}
-
-void __init enable_local_APIC(void)
-{
-	unsigned long value;
-
- 	value = apic_read(APIC_SPIV);
- 	value |= (1<<8);		/* Enable APIC (bit==1) */
-#if 0
- 	value &= ~(1<<9);		/* Enable focus processor (bit==0) */
-#else
-	value |= (1<<9);		/* Disable focus processor (bit==1) */
-#endif
-	value |= 0xff;			/* Set spurious IRQ vector to 0xff */
- 	apic_write(APIC_SPIV,value);
-
-	/*
-	 * Set Task Priority to 'accept all'
-	 */
- 	value = apic_read(APIC_TASKPRI);
- 	value &= ~APIC_TPRI_MASK;
- 	apic_write(APIC_TASKPRI,value);
-
-	/*
-	 * Clear the logical destination ID, just to be safe.
-	 * also, put the APIC into flat delivery mode.
-	 */
- 	value = apic_read(APIC_LDR);
-	value &= ~APIC_LDR_MASK;
- 	apic_write(APIC_LDR,value);
-
- 	value = apic_read(APIC_DFR);
-	value |= SET_APIC_DFR(0xf);
- 	apic_write(APIC_DFR, value);
-
-	udelay(100);			/* B safe */
-}
-
-unsigned long __init init_smp_mappings(unsigned long memory_start)
-{
-	unsigned long apic_phys;
-
-	memory_start = PAGE_ALIGN(memory_start);
-	if (smp_found_config) {
-		apic_phys = mp_lapic_addr;
-	} else {
-		/*
-		 * set up a fake all zeroes page to simulate the
-		 * local APIC and another one for the IO-APIC. We
-		 * could use the real zero-page, but it's safer
-		 * this way if some buggy code writes to this page ...
-		 */
-		apic_phys = __pa(memory_start);
-		memset((void *)memory_start, 0, PAGE_SIZE);
-		memory_start += PAGE_SIZE;
-	}
-	set_fixmap(FIX_APIC_BASE,apic_phys);
-	printk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
-
-#ifdef CONFIG_X86_IO_APIC
-	{
-		unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
-		int i;
-
-		for (i = 0; i < nr_ioapics; i++) {
-			if (smp_found_config) {
-				ioapic_phys = mp_apics[i].mpc_apicaddr;
-			} else {
-				ioapic_phys = __pa(memory_start);
-				memset((void *)memory_start, 0, PAGE_SIZE);
-				memory_start += PAGE_SIZE;
-			}
-			set_fixmap(idx,ioapic_phys);
-			printk("mapped IOAPIC to %08lx (%08lx)\n",
-					__fix_to_virt(idx), ioapic_phys);
-			idx++;
-		}
-	}
-#endif
-
-	return memory_start;
-}
-
-extern void calibrate_delay(void);
-
-void __init smp_callin(void)
-{
-	int cpuid;
-	unsigned long timeout;
-
-	/*
-	 * (This works even if the APIC is not enabled.)
-	 */
-	cpuid = GET_APIC_ID(apic_read(APIC_ID));
-
-	SMP_PRINTK(("CPU#%d waiting for CALLOUT\n", cpuid));
-
-	/*
-	 * STARTUP IPIs are fragile beasts as they might sometimes
-	 * trigger some glue motherboard logic. Complete APIC bus
-	 * silence for 1 second, this overestimates the time the
-	 * boot CPU is spending to send the up to 2 STARTUP IPIs
-	 * by a factor of two. This should be enough.
-	 */
-
-	/*
-	 * Waiting 2s total for startup (udelay is not yet working)
-	 */
-	timeout = jiffies + 2*HZ;
-	while (time_before(jiffies,timeout))
-	{
-		/*
-		 * Has the boot CPU finished it's STARTUP sequence?
-		 */
-		if (test_bit(cpuid, (unsigned long *)&cpu_callout_map[0]))
-			break;
-	}
-
-	while (!time_before(jiffies,timeout)) {
-		printk("BUG: CPU%d started up but did not get a callout!\n",
-			cpuid);
-		stop_this_cpu();
-	}
-
-	/*
-	 * the boot CPU has finished the init stage and is spinning
-	 * on callin_map until we finish. We are free to set up this
-	 * CPU, first the APIC. (this is probably redundant on most
-	 * boards)
-	 */
-	
-	SMP_PRINTK(("CALLIN, before enable_local_APIC().\n"));
-	enable_local_APIC();
-
-	/*
-	 * Set up our APIC timer.
-	 */
-	setup_APIC_clock();
-
- 	__sti();
-
-#ifdef CONFIG_MTRR
-	/*  Must be done before calibration delay is computed  */
-	mtrr_init_secondary_cpu ();
-#endif
-	/*
-	 *	Get our bogomips.
-	 */
-	calibrate_delay();
-	SMP_PRINTK(("Stack at about %p\n",&cpuid));
-
-	/*
-	 *	Save our processor parameters
-	 */
- 	smp_store_cpu_info(cpuid);
-
-	/*
-	 *	Allow the master to continue.
-	 */
-	set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]);
-}
-
-int cpucount = 0;
-
-extern int cpu_idle(void);
-
-/*
- *	Activate a secondary processor.
- */
-int __init start_secondary(void *unused)
-{
-	/*
-	 * Dont put anything before smp_callin(), SMP
-	 * booting is too fragile that we want to limit the
-	 * things done here to the most necessary things.
-	 */
-	cpu_init();
-	smp_callin();
-	while (!atomic_read(&smp_commenced))
-		/* nothing */ ;
-	return cpu_idle();
-}
-
-/*
- * Everything has been set up for the secondary
- * CPUs - they just need to reload everything
- * from the task structure
- * This function must not return.
- */
-void __init initialize_secondary(void)
-{
-	/*
-	 * We don't actually need to load the full TSS,
-	 * basically just the stack pointer and the eip.
-	 */
-
-	asm volatile(
-		"movl %0,%%esp\n\t"
-		"jmp *%1"
-		:
-		:"r" (current->thread.esp),"r" (current->thread.eip));
-}
-
-extern struct {
-	void * esp;
-	unsigned short ss;
-} stack_start;
-
-static int __init fork_by_hand(void)
-{
-	struct pt_regs regs;
-	/* don't care about the eip and regs settings since we'll never
-	   reschedule the forked task. */
-	return do_fork(CLONE_VM|CLONE_PID, 0, &regs);
-}
-
-static void __init do_boot_cpu(int i)
-{
-	unsigned long cfg;
-	pgd_t maincfg;
-	struct task_struct *idle;
-	unsigned long send_status, accept_status;
-	int timeout, num_starts, j;
-	unsigned long start_eip;
-
-	cpucount++;
-	/* We can't use kernel_thread since we must _avoid_ to reschedule
-	   the child. */
-	if (fork_by_hand() < 0)
-		panic("failed fork for CPU %d", i);
-
-	/*
-	 * We remove it from the pidhash and the runqueue
-	 * once we got the process:
-	 */
-	idle = init_task.prev_task;
-	if (!idle)
-		panic("No idle process for CPU %d", i);
-
-	idle->processor = i;
-	__cpu_logical_map[cpucount] = i;
-	cpu_number_map[i] = cpucount;
-	idle->has_cpu = 1; /* we schedule the first task manually */
-	idle->thread.eip = (unsigned long) start_secondary;
-
-	del_from_runqueue(idle);
-	unhash_process(idle);
-	init_tasks[cpucount] = idle;
-
-	/* start_eip had better be page-aligned! */
-	start_eip = setup_trampoline();
-
-	printk("Booting processor %d eip %lx\n", i, start_eip);	/* So we see what's up   */
-	stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
-
-	/*
-	 *	This grunge runs the startup process for
-	 *	the targeted processor.
-	 */
-
-	SMP_PRINTK(("Setting warm reset code and vector.\n"));
-
-	CMOS_WRITE(0xa, 0xf);
-	local_flush_tlb();
-	SMP_PRINTK(("1.\n"));
-	*((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4;
-	SMP_PRINTK(("2.\n"));
-	*((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;
-	SMP_PRINTK(("3.\n"));
-
-	maincfg=swapper_pg_dir[0];
-	((unsigned long *)swapper_pg_dir)[0]=0x102007;
-
-	/*
-	 *	Be paranoid about clearing APIC errors.
-	 */
-
-	if ( apic_version[i] & 0xF0 )
-	{
-		apic_write(APIC_ESR, 0);
-		accept_status = (apic_read(APIC_ESR) & 0xEF);
-	}
-
-	/*
-	 *	Status is now clean
-	 */
-	
-	send_status = 	0;
-	accept_status = 0;
-
-	/*
-	 *	Starting actual IPI sequence...
-	 */
-
-	SMP_PRINTK(("Asserting INIT.\n"));
-
-	/*
-	 *	Turn INIT on
-	 */
-			
-	cfg=apic_read(APIC_ICR2);
-	cfg&=0x00FFFFFF;
-	apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); 			/* Target chip     	*/
-	cfg=apic_read(APIC_ICR);
-	cfg&=~0xCDFFF;								/* Clear bits 		*/
-	cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
-	apic_write(APIC_ICR, cfg);						/* Send IPI */
-
-	udelay(200);
-	SMP_PRINTK(("Deasserting INIT.\n"));
-
-	cfg=apic_read(APIC_ICR2);
-	cfg&=0x00FFFFFF;
-	apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i));			/* Target chip     	*/
-	cfg=apic_read(APIC_ICR);
-	cfg&=~0xCDFFF;								/* Clear bits 		*/
-	cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_DM_INIT);
-	apic_write(APIC_ICR, cfg);						/* Send IPI */
-
-	/*
-	 *	Should we send STARTUP IPIs ?
-	 *
-	 *	Determine this based on the APIC version.
-	 *	If we don't have an integrated APIC, don't
-	 *	send the STARTUP IPIs.
-	 */
-
-	if ( apic_version[i] & 0xF0 )
-		num_starts = 2;
-	else
-		num_starts = 0;
-
-	/*
-	 *	Run STARTUP IPI loop.
-	 */
-
-	for (j = 1; !(send_status || accept_status)
-		    && (j <= num_starts) ; j++)
-	{
-		SMP_PRINTK(("Sending STARTUP #%d.\n",j));
-		apic_write(APIC_ESR, 0);
-		SMP_PRINTK(("After apic_write.\n"));
-
-		/*
-		 *	STARTUP IPI
-		 */
-
-		cfg=apic_read(APIC_ICR2);
-		cfg&=0x00FFFFFF;
-		apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i));			/* Target chip     	*/
-		cfg=apic_read(APIC_ICR);
-		cfg&=~0xCDFFF;								/* Clear bits 		*/
-		cfg |= (APIC_DEST_DM_STARTUP | (start_eip >> 12));						/* Boot on the stack 	*/
-		SMP_PRINTK(("Before start apic_write.\n"));
-		apic_write(APIC_ICR, cfg);						/* Kick the second 	*/
-
-		SMP_PRINTK(("Startup point 1.\n"));
-
-		timeout = 0;
-		SMP_PRINTK(("Waiting for send to finish...\n"));
-		do {
-			SMP_PRINTK(("+"));
-			udelay(100);
-			send_status = apic_read(APIC_ICR) & 0x1000;
-		} while (send_status && (timeout++ < 1000));
-
-		/*
-		 * Give the other CPU some time to accept the IPI.
-		 */
-		udelay(200);
-		accept_status = (apic_read(APIC_ESR) & 0xEF);
-	}
-	SMP_PRINTK(("After Startup.\n"));
-
-	if (send_status)		/* APIC never delivered?? */
-		printk("APIC never delivered???\n");
-	if (accept_status)		/* Send accept error */
-		printk("APIC delivery error (%lx).\n", accept_status);
-
-	if ( !(send_status || accept_status) )
-	{
-		/*
-		 * allow APs to start initializing.
-		 */
-		SMP_PRINTK(("Before Callout %d.\n", i));
-		set_bit(i, (unsigned long *)&cpu_callout_map[0]);
-		SMP_PRINTK(("After Callout %d.\n", i));
-
-		for(timeout=0;timeout<50000;timeout++)
-		{
-			if (cpu_callin_map[0]&(1<<i))
-				break;				/* It has booted */
-			udelay(100);				/* Wait 5s total for a response */
-		}
-		if (cpu_callin_map[0]&(1<<i))
-		{
-			/* number CPUs logically, starting from 1 (BSP is 0) */
-#if 0
-			cpu_number_map[i] = cpucount;
-			__cpu_logical_map[cpucount] = i;
-#endif
-			printk("OK.\n");
-			printk("CPU%d: ", i);
-			print_cpu_info(&cpu_data[i]);
-		}
-		else
-		{
-			if (*((volatile unsigned char *)phys_to_virt(8192))==0xA5)
-				printk("Stuck ??\n");
-			else
-				printk("Not responding.\n");
-		}
-	SMP_PRINTK(("CPU has booted.\n"));
-	}
-	else
-	{
-		__cpu_logical_map[cpucount] = -1;
-		cpu_number_map[i] = -1;
-		cpucount--;
-	}
-
-	swapper_pg_dir[0]=maincfg;
-	local_flush_tlb();
-
-	/* mark "stuck" area as not stuck */
-	*((volatile unsigned long *)phys_to_virt(8192)) = 0;
-}
-
-cycles_t cacheflush_time;
-extern unsigned long cpu_hz;
-
-static void smp_tune_scheduling (void)
-{
-	unsigned long cachesize;
-	/*
-	 * Rough estimation for SMP scheduling, this is the number of
-	 * cycles it takes for a fully memory-limited process to flush
-	 * the SMP-local cache.
-	 *
-	 * (For a P5 this pretty much means we will choose another idle
-	 *  CPU almost always at wakeup time (this is due to the small
-	 *  L1 cache), on PIIs it's around 50-100 usecs, depending on
-	 *  the cache size)
-	 */
-
-	if (!cpu_hz) {
-		/*
-		 * this basically disables processor-affinity
-		 * scheduling on SMP without a TSC.
-		 */
-		cacheflush_time = 0;
-		return;
-	} else {
-		cachesize = boot_cpu_data.x86_cache_size;
-		if (cachesize == -1)
-			cachesize = 8; /* Pentiums */
+ *	This code is released under the GNU public license version 2 or
+ *	later.
+ */
 
-		cacheflush_time = cpu_hz/1024*cachesize/5000;
-	}
+#include <linux/config.h>
+#include <linux/init.h>
 
-	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
-		(long)cacheflush_time/(cpu_hz/1000000),
-		((long)cacheflush_time*100/(cpu_hz/1000000)) % 100);
-}
+#include <linux/mm.h>
+#include <linux/kernel_stat.h>
+#include <linux/smp_lock.h>
+#include <linux/irq.h>
 
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_old_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
+#include <linux/delay.h>
+#include <linux/mc146818rtc.h>
+#include <asm/mtrr.h>
 
 /*
- *	Cycle through the processors sending APIC IPIs to boot each.
+ *	Some notes on processor bugs:
+ *
+ *	Pentium, Pentium Pro, II, III (and all CPUs) have bugs.
+ *	The Linux implications for SMP are handled as follows:
+ *
+ *	Pentium III / [Xeon]
+ *		None of the E1AP-E3AP erratas are visible to the user.
+ *
+ *	E1AP.	see PII A1AP
+ *	E2AP.	see PII A2AP
+ *	E3AP.	see PII A3AP
+ *
+ *	Pentium II / [Xeon]
+ *		None of the A1AP-A3AP erratas are visible to the user.
+ *
+ *	A1AP.	see PPro 1AP
+ *	A2AP.	see PPro 2AP
+ *	A3AP.	see PPro 7AP
+ *
+ *	Pentium Pro
+ *		None of 1AP-9AP erratas are visible to the normal user,
+ *	except occasional delivery of 'spurious interrupt' as trap #15.
+ *	This is very rare and a non-problem.
+ *
+ *	1AP.	Linux maps APIC as non-cacheable
+ *	2AP.	worked around in hardware
+ *	3AP.	fixed in C0 and above steppings microcode update.
+ *		Linux does not use excessive STARTUP_IPIs.
+ *	4AP.	worked around in hardware
+ *	5AP.	symmetric IO mode (normal Linux operation) not affected.
+ *		'noapic' mode has vector 0xf filled out properly.
+ *	6AP.	'noapic' mode might be affected - fixed in later steppings
+ *	7AP.	We do not assume writes to the LVT deassering IRQs
+ *	8AP.	We do not enable low power mode (deep sleep) during MP bootup
+ *	9AP.	We do not use mixed mode
+ *
+ *	Pentium
+ *		There is a marginal case where REP MOVS on 100MHz SMP
+ *	machines with B stepping processors can fail. XXX should provide
+ *	an L1cache=Writethrough or L1cache=off option.
+ *
+ *		B stepping CPUs may hang. There are hardware work arounds
+ *	for this. We warn about it in case your board doesnt have the work
+ *	arounds. Basically thats so I can tell anyone with a B stepping
+ *	CPU and SMP problems "tough".
+ *
+ *	Specific items [From Pentium Processor Specification Update]
+ *
+ *	1AP.	Linux doesn't use remote read
+ *	2AP.	Linux doesn't trust APIC errors
+ *	3AP.	We work around this
+ *	4AP.	Linux never generated 3 interrupts of the same priority
+ *		to cause a lost local interrupt.
+ *	5AP.	Remote read is never used
+ *	6AP.	not affected - worked around in hardware
+ *	7AP.	not affected - worked around in hardware
+ *	8AP.	worked around in hardware - we get explicit CS errors if not
+ *	9AP.	only 'noapic' mode affected. Might generate spurious
+ *		interrupts, we log only the first one and count the
+ *		rest silently.
+ *	10AP.	not affected - worked around in hardware
+ *	11AP.	Linux reads the APIC between writes to avoid this, as per
+ *		the documentation. Make sure you preserve this as it affects
+ *		the C stepping chips too.
+ *	12AP.	not affected - worked around in hardware
+ *	13AP.	not affected - worked around in hardware
+ *	14AP.	we always deassert INIT during bootup
+ *	15AP.	not affected - worked around in hardware
+ *	16AP.	not affected - worked around in hardware
+ *	17AP.	not affected - worked around in hardware
+ *	18AP.	not affected - worked around in hardware
+ *	19AP.	not affected - worked around in BIOS
+ *
+ *	If this sounds worrying believe me these bugs are either ___RARE___,
+ *	or are signal timing bugs worked around in hardware and there's
+ *	about nothing of note with C stepping upwards.
  */
 
-void __init smp_boot_cpus(void)
-{
-	int i;
-
-#ifdef CONFIG_MTRR
-	/*  Must be done before other processors booted  */
-	mtrr_init_boot_cpu ();
-#endif
-	/*
-	 *	Initialize the logical to physical CPU number mapping
-	 *	and the per-CPU profiling counter/multiplier
-	 */
-
-	for (i = 0; i < NR_CPUS; i++) {
-		cpu_number_map[i] = -1;
-		prof_counter[i] = 1;
-		prof_old_multiplier[i] = 1;
-		prof_multiplier[i] = 1;
-	}
-
-	/*
-	 *	Setup boot CPU information
-	 */
-
-	smp_store_cpu_info(boot_cpu_id);			/* Final full version of the data */
-	smp_tune_scheduling();
-	printk("CPU%d: ", boot_cpu_id);
-	print_cpu_info(&cpu_data[boot_cpu_id]);
-
-	/*
-	 * not necessary because the MP table should list the boot
-	 * CPU too, but we do it for the sake of robustness anyway.
-	 * (and for the case when a non-SMP board boots an SMP kernel)
-	 */
-	cpu_present_map |= (1 << hard_smp_processor_id());
-
-	cpu_number_map[boot_cpu_id] = 0;
-
-	init_idle();
-
-	/*
-	 * If we couldnt find an SMP configuration at boot time,
-	 * get out of here now!
-	 */
-
-	if (!smp_found_config)
-	{
-		printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n");
-#ifndef CONFIG_VISWS
-		io_apic_irqs = 0;
-#endif
-		cpu_online_map = cpu_present_map;
-		smp_num_cpus = 1;
-		goto smp_done;
-	}
-
-	/*
-	 *	If SMP should be disabled, then really disable it!
-	 */
-
-	if (!max_cpus)
-	{
-		smp_found_config = 0;
-		printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
-	}
-
-#ifdef SMP_DEBUG
-	{
-		int reg;
-
-		/*
-		 *	This is to verify that we're looking at
-		 *	a real local APIC.  Check these against
-		 *	your board if the CPUs aren't getting
-		 *	started for no apparent reason.
-		 */
-
-		reg = apic_read(APIC_VERSION);
-		SMP_PRINTK(("Getting VERSION: %x\n", reg));
-
-		apic_write(APIC_VERSION, 0);
-		reg = apic_read(APIC_VERSION);
-		SMP_PRINTK(("Getting VERSION: %x\n", reg));
-
-		/*
-		 *	The two version reads above should print the same
-		 *	NON-ZERO!!! numbers.  If the second one is zero,
-		 *	there is a problem with the APIC write/read
-		 *	definitions.
-		 *
-		 *	The next two are just to see if we have sane values.
-		 *	They're only really relevant if we're in Virtual Wire
-		 *	compatibility mode, but most boxes are anymore.
-		 */
-
-
-		reg = apic_read(APIC_LVT0);
-		SMP_PRINTK(("Getting LVT0: %x\n", reg));
-
-		reg = apic_read(APIC_LVT1);
-		SMP_PRINTK(("Getting LVT1: %x\n", reg));
-	}
-#endif
-
-	enable_local_APIC();
-
-	/*
-	 * Set up our local APIC timer:
-	 */
-	setup_APIC_clock ();
-
-	/*
-	 *	Now scan the CPU present map and fire up the other CPUs.
-	 */
-
-	/*
-	 * Add all detected CPUs. (later on we can down individual
-	 * CPUs which will change cpu_online_map but not necessarily
-	 * cpu_present_map. We are pretty much ready for hot-swap CPUs.)
-	 */
-	cpu_online_map = cpu_present_map;
-	mb();
-
-	SMP_PRINTK(("CPU map: %lx\n", cpu_present_map));
-
-	for(i=0;i<NR_CPUS;i++)
-	{
-		/*
-		 *	Don't even attempt to start the boot CPU!
-		 */
-		if (i == boot_cpu_id)
-			continue;
-
-		if ((cpu_online_map & (1 << i))
-		    && (max_cpus < 0 || max_cpus > cpucount+1))
-		{
-			do_boot_cpu(i);
-		}
-
-		/*
-		 *	Make sure we unmap all failed CPUs
-		 */
-		
-		if (cpu_number_map[i] == -1 && (cpu_online_map & (1 << i))) {
-			printk("CPU #%d not responding. Removing from cpu_online_map.\n",i);
-			cpu_online_map &= ~(1 << i);
-                }
-        }
-
-	/*
-	 *	Cleanup possible dangling ends...
-	 */
-
-#ifndef CONFIG_VISWS
-	{
-		unsigned long cfg;
-
-		/*
-		 *	Install writable page 0 entry.
-		 */
-		cfg = pg0[0];
-		pg0[0] = _PAGE_RW | _PAGE_PRESENT;	/* writeable, present, addr 0 */
-		local_flush_tlb();
-	
-		/*
-		 *	Paranoid:  Set warm reset code and vector here back
-		 *	to default values.
-		 */
-
-		CMOS_WRITE(0, 0xf);
-
-		*((volatile long *) phys_to_virt(0x467)) = 0;
-
-		/*
-		 *	Restore old page 0 entry.
-		 */
-
-		pg0[0] = cfg;
-		local_flush_tlb();
-	}
-#endif
-
-	/*
-	 *	Allow the user to impress friends.
-	 */
-
-	SMP_PRINTK(("Before bogomips.\n"));
-	if (!cpucount) {
-		printk(KERN_ERR "Error: only one processor found.\n");
-		cpu_online_map = (1<<hard_smp_processor_id());
-	} else {
-		unsigned long bogosum = 0;
-		for(i = 0; i < 32; i++)
-			if (cpu_online_map&(1<<i))
-				bogosum+=cpu_data[i].loops_per_sec;
-		printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
-			cpucount+1,
-			(bogosum+2500)/500000,
-			((bogosum+2500)/5000)%100);
-		SMP_PRINTK(("Before bogocount - setting activated=1.\n"));
-		smp_activated = 1;
-	}
-	smp_num_cpus = cpucount + 1;
-
-	if (smp_b_stepping)
-		printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
-	SMP_PRINTK(("Boot done.\n"));
-
-	cache_APIC_registers();
-#ifndef CONFIG_VISWS
-	/*
-	 * Here we can be sure that there is an IO-APIC in the system. Let's
-	 * go and set it up:
-	 */
-	if (!skip_ioapic_setup) 
-		setup_IO_APIC();
-#endif
-
-smp_done:
-	/*
-	 * now we know the other CPUs have fired off and we know our
-	 * APIC ID, so we can go init the TSS and stuff:
-	 */
-	cpu_init();
-}
+/* The 'big kernel lock' */
+spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 
+volatile unsigned long smp_invalidate_needed;
 
 /*
  * the following functions deal with sending IPIs between CPUs.
@@ -1429,17 +110,6 @@
  * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
  */
 
-
-/*
- * Silly serialization to work around CPU bug in P5s.
- * We can safely turn it off on a 686.
- */
-#ifdef CONFIG_X86_GOOD_APIC
-# define FORCE_APIC_SERIALIZATION 0
-#else
-# define FORCE_APIC_SERIALIZATION 1
-#endif
-
 static unsigned int cached_APIC_ICR;
 static unsigned int cached_APIC_ICR2;
 
@@ -1462,7 +132,7 @@
 
 static inline unsigned int __get_ICR (void)
 {
-#if FORCE_APIC_SERIALIZATION
+#if FORCE_READ_AROUND_WRITE
 	/*
 	 * Wait for the APIC to become ready - this should never occur. It's
 	 * a debugging check really.
@@ -1473,11 +143,11 @@
 	while (count < 1000)
 	{
 		cfg = slow_ICR;
-		if (!(cfg&(1<<12))) {
-			if (count)
-				atomic_add(count, (atomic_t*)&ipi_count);
+		if (!(cfg&(1<<12)))
 			return cfg;
-		}
+		printk("CPU #%d: ICR still busy [%08x]\n",
+					smp_processor_id(), cfg);
+		irq_err_count++;
 		count++;
 		udelay(10);
 	}
@@ -1491,19 +161,25 @@
 
 static inline unsigned int __get_ICR2 (void)
 {
-#if FORCE_APIC_SERIALIZATION
+#if FORCE_READ_AROUND_WRITE
 	return slow_ICR2;
 #else
 	return cached_APIC_ICR2;
 #endif
 }
 
+#define LOGICAL_DELIVERY 1
+
 static inline int __prepare_ICR (unsigned int shortcut, int vector)
 {
 	unsigned int cfg;
 
 	cfg = __get_ICR();
-	cfg |= APIC_DEST_DM_FIXED|shortcut|vector;
+	cfg |= APIC_DEST_DM_FIXED|shortcut|vector
+#if LOGICAL_DELIVERY
+		|APIC_DEST_LOGICAL
+#endif
+		;
 
 	return cfg;
 }
@@ -1513,7 +189,11 @@
 	unsigned int cfg;
 
 	cfg = __get_ICR2();
+#if LOGICAL_DELIVERY
+	cfg |= SET_APIC_DEST_FIELD((1<<dest));
+#else
 	cfg |= SET_APIC_DEST_FIELD(dest);
+#endif
 
 	return cfg;
 }
@@ -1526,7 +206,7 @@
  * have to lock out interrupts to be safe. Otherwise it's just one
  * single atomic write to the APIC, no need for cli/sti.
  */
-#if FORCE_APIC_SERIALIZATION
+#if FORCE_READ_AROUND_WRITE
 	unsigned long flags;
 
 	__save_flags(flags);
@@ -1536,21 +216,26 @@
 	/*
 	 * No need to touch the target chip field
 	 */
-
 	cfg = __prepare_ICR(shortcut, vector);
 
 	/*
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
 	apic_write(APIC_ICR, cfg);
-#if FORCE_APIC_SERIALIZATION
+#if FORCE_READ_AROUND_WRITE
 	__restore_flags(flags);
 #endif
 }
 
 static inline void send_IPI_allbutself(int vector)
 {
-	__send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
+	/*
+	 * if there are no other CPUs in the system then
+	 * we get an APIC send error if we try to broadcast.
+	 * thus we have to avoid sending IPIs in this case.
+	 */
+	if (smp_num_cpus > 1)
+		__send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
 }
 
 static inline void send_IPI_all(int vector)
@@ -1566,7 +251,7 @@
 static inline void send_IPI_single(int dest, int vector)
 {
 	unsigned long cfg;
-#if FORCE_APIC_SERIALIZATION
+#if FORCE_READ_AROUND_WRITE
 	unsigned long flags;
 
 	__save_flags(flags);
@@ -1589,7 +274,7 @@
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
 	apic_write(APIC_ICR, cfg);
-#if FORCE_APIC_SERIALIZATION
+#if FORCE_READ_AROUND_WRITE
 	__restore_flags(flags);
 #endif
 }
@@ -1715,200 +400,97 @@
 }
 
 /*
- * this function sends a 'stop' IPI to all other CPUs in the system.
- * it goes straight through.
- */
-
-void smp_send_stop(void)
-{
-	send_IPI_allbutself(STOP_CPU_VECTOR);
-}
-
-/* Structure and data for smp_call_function(). This is designed to minimise
+ * Structure and data for smp_call_function(). This is designed to minimise
  * static memory requirements. It also looks cleaner.
  */
-struct smp_call_function_struct {
+static volatile struct call_data_struct {
 	void (*func) (void *info);
 	void *info;
-	atomic_t unstarted_count;
-	atomic_t unfinished_count;
+	atomic_t started;
+	atomic_t finished;
 	int wait;
-};
-static volatile struct smp_call_function_struct *smp_call_function_data = NULL;
+} *call_data = NULL;
 
 /*
  * this function sends a 'generic call function' IPI to all other CPUs
  * in the system.
  */
 
-int smp_call_function (void (*func) (void *info), void *info, int retry,
-		       int wait)
-/*  [SUMMARY] Run a function on all other CPUs.
-    <func> The function to run. This must be fast and non-blocking.
-    <info> An arbitrary pointer to pass to the function.
-    <retry> If true, keep retrying until ready.
-    <wait> If true, wait until function has completed on other CPUs.
-    [RETURNS] 0 on success, else a negative status code. Does not return until
-    remote CPUs are nearly ready to execute <<func>> or are or have executed.
-*/
-{
-	unsigned long timeout;
-	struct smp_call_function_struct data;
-	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
-
-	if (retry) {
-		while (1) {
-			if (smp_call_function_data) {
-				schedule ();  /*  Give a mate a go  */
-				continue;
-			}
-			spin_lock (&lock);
-			if (smp_call_function_data) {
-				spin_unlock (&lock);  /*  Bad luck  */
-				continue;
-			}
-			/*  Mine, all mine!  */
-			break;
-		}
-	}
-	else {
-		if (smp_call_function_data) return -EBUSY;
-		spin_lock (&lock);
-		if (smp_call_function_data) {
-			spin_unlock (&lock);
-			return -EBUSY;
-		}
-	}
-	smp_call_function_data = &data;
-	spin_unlock (&lock);
-	data.func = func;
-	data.info = info;
-	atomic_set (&data.unstarted_count, smp_num_cpus - 1);
-	data.wait = wait;
-	if (wait) atomic_set (&data.unfinished_count, smp_num_cpus - 1);
-	/*  Send a message to all other CPUs and wait for them to respond  */
-	send_IPI_allbutself (CALL_FUNCTION_VECTOR);
-	/*  Wait for response  */
-	timeout = jiffies + JIFFIE_TIMEOUT;
-	while ( (atomic_read (&data.unstarted_count) > 0) &&
-		time_before (jiffies, timeout) )
-		barrier ();
-	if (atomic_read (&data.unstarted_count) > 0) {
-		smp_call_function_data = NULL;
-		return -ETIMEDOUT;
-	}
-	if (wait)
-		while (atomic_read (&data.unfinished_count) > 0)
-			barrier ();
-	smp_call_function_data = NULL;
-	return 0;
-}
-
-static unsigned int calibration_result;
-
-void setup_APIC_timer(unsigned int clocks);
-
+int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+			int wait)
 /*
- * Local timer interrupt handler. It does both profiling and
- * process statistics/rescheduling.
- *
- * We do profiling in every local tick, statistics/rescheduling
- * happen only every 'profiling multiplier' ticks. The default
- * multiplier is 1 and it can be changed by writing the new multiplier
- * value into /proc/profile.
+ * [SUMMARY] Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <nonatomic> If true, we might schedule away to lock the mutex
+ * <wait> If true, wait (atomically) until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code. Does not return until
+ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
  */
-
-void smp_local_timer_interrupt(struct pt_regs * regs)
 {
-	int user = (user_mode(regs) != 0);
-	int cpu = smp_processor_id();
-
-	/*
-	 * The profiling function is SMP safe. (nothing can mess
-	 * around with "current", and the profiling counters are
-	 * updated with atomic operations). This is especially
-	 * useful with a profiling multiplier != 1
-	 */
-	if (!user)
-		x86_do_profile(regs->eip);
+	struct call_data_struct data;
+	int ret, cpus = smp_num_cpus-1;
+	static DECLARE_MUTEX(lock);
+	unsigned long timeout;
 
-	if (!--prof_counter[cpu]) {
-		int system = 1 - user;
-		struct task_struct * p = current;
+	if (nonatomic)
+		down(&lock);
+	else
+		if (down_trylock(&lock))
+			return -EBUSY;
 
-		/*
-		 * The multiplier may have changed since the last time we got
-		 * to this point as a result of the user writing to
-		 * /proc/profile.  In this case we need to adjust the APIC
-		 * timer accordingly.
-		 *
-		 * Interrupts are already masked off at this point.
-		 */
-               prof_counter[cpu] = prof_multiplier[cpu];
-               if (prof_counter[cpu] != prof_old_multiplier[cpu]) {
-                       setup_APIC_timer(calibration_result/prof_counter[cpu]);
-                       prof_old_multiplier[cpu] = prof_counter[cpu];
-               }
+	if (call_data) // temporary debugging check
+		BUG();
 
-		/*
-		 * After doing the above, we need to make like
-		 * a normal interrupt - otherwise timer interrupts
-		 * ignore the global interrupt lock, which is the
-		 * WrongThing (tm) to do.
-		 */
+	call_data = &data;
+	data.func = func;
+	data.info = info;
+	atomic_set(&data.started, 0);
+	data.wait = wait;
+	if (wait)
+		atomic_set(&data.finished, 0);
+	mb();
 
- 		irq_enter(cpu, 0);
-		update_one_process(p, 1, user, system, cpu);
-		if (p->pid) {
-			p->counter -= 1;
-			if (p->counter <= 0) {
-				p->counter = 0;
-				p->need_resched = 1;
-			}
-			if (p->priority < DEF_PRIORITY) {
-				kstat.cpu_nice += user;
-				kstat.per_cpu_nice[cpu] += user;
-			} else {
-				kstat.cpu_user += user;
-				kstat.per_cpu_user[cpu] += user;
-			}
-			kstat.cpu_system += system;
-			kstat.per_cpu_system[cpu] += system;
+	/* Send a message to all other CPUs and wait for them to respond */
+	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
 
-		}
-		irq_exit(cpu, 0);
-	}
+	/* Wait for response */
+	timeout = jiffies + HZ;
+	while ((atomic_read(&data.started) != cpus)
+			&& time_before(jiffies, timeout))
+		barrier();
+	ret = -ETIMEDOUT;
+	if (atomic_read(&data.started) != cpus)
+		goto out;
+	ret = 0;
+	if (wait)
+		while (atomic_read(&data.finished) != cpus)
+			barrier();
+out:
+	call_data = NULL;
+	up(&lock);
+	return 0;
+}
 
+static void stop_this_cpu (void * dummy)
+{
 	/*
-	 * We take the 'long' return path, and there every subsystem
-	 * grabs the apropriate locks (kernel lock/ irq lock).
-	 *
-	 * we might want to decouple profiling from the 'long path',
-	 * and do the profiling totally in assembly.
-	 *
-	 * Currently this isn't too much of an issue (performance wise),
-	 * we can take more than 100K local irqs per second on a 100 MHz P5.
+	 * Remove this CPU:
 	 */
+	clear_bit(smp_processor_id(), &cpu_online_map);
+
+	if (cpu_data[smp_processor_id()].hlt_works_ok)
+		for(;;) __asm__("hlt");
+	for (;;);
 }
 
 /*
- * Local APIC timer interrupt. This is the most natural way for doing
- * local interrupts, but local timer interrupts can be emulated by
- * broadcast interrupts too. [in case the hw doesnt support APIC timers]
- *
- * [ if a single-CPU system runs an SMP kernel then we call the local
- *   interrupt as well. Thus we cannot inline the local irq ... ]
+ * this function calls the 'stop' function on all other CPUs in the system.
  */
-void smp_apic_timer_interrupt(struct pt_regs * regs)
+
+void smp_send_stop(void)
 {
-	/*
-	 * NOTE! We'd better ACK the irq immediately,
-	 * because timer handling can be slow, and we
-	 * want to be able to accept NMI tlb invalidates
-	 * during this time.
-	 */
-	ack_APIC_irq();
-	smp_local_timer_interrupt(regs);
+        smp_call_function(stop_this_cpu, NULL, 1, 0);
 }
 
 /*
@@ -1944,39 +526,24 @@
 
 }
 
-static void stop_this_cpu (void)
+asmlinkage void smp_call_function_interrupt(void)
 {
+	void (*func) (void *info) = call_data->func;
+	void *info = call_data->info;
+	int wait = call_data->wait;
+
+	ack_APIC_irq();
 	/*
-	 * Remove this CPU:
+	 * Notify initiating CPU that I've grabbed the data and am
+	 * about to execute the function
 	 */
-	clear_bit(smp_processor_id(), &cpu_online_map);
-
-	if (cpu_data[smp_processor_id()].hlt_works_ok)
-		for(;;) __asm__("hlt");
-	for (;;);
-}
-
-/*
- *	CPU halt call-back
- */
-asmlinkage void smp_stop_cpu_interrupt(void)
-{
-	stop_this_cpu();
-}
-
-asmlinkage void smp_call_function_interrupt(void)
-{
-	void (*func) (void *info) = smp_call_function_data->func;
-	void *info = smp_call_function_data->info;
-	int wait = smp_call_function_data->wait;
-
-	ack_APIC_irq ();
-	/*  Notify initiating CPU that I've grabbed the data and am about to
-	    execute the function  */
-	atomic_dec (&smp_call_function_data->unstarted_count);
-	/*  At this point the structure may be out of scope unless wait==1  */
-	(*func) (info);
-	if (wait) atomic_dec (&smp_call_function_data->unfinished_count);
+	atomic_inc(&call_data->started);
+	/*
+	 * At this point the structure may be out of scope unless wait==1
+	 */
+	(*func)(info);
+	if (wait)
+		atomic_inc(&call_data->finished);
 }
 
 /*
@@ -1991,6 +558,34 @@
 }
 
 /*
+ * This interrupt should never happen with our APIC/SMP architecture
+ */
+
+static spinlock_t err_lock;
+
+asmlinkage void smp_error_interrupt(void)
+{
+	unsigned long v;
+
+	spin_lock(&err_lock);
+
+	v = apic_read(APIC_ESR);
+	printk("APIC error interrupt on CPU#%d, should never happen.\n",
+			smp_processor_id());
+	printk("... APIC ESR0: %08lx\n", v);
+
+	apic_write(APIC_ESR, 0);
+	v = apic_read(APIC_ESR);
+	printk("... APIC ESR1: %08lx\n", v);
+
+	ack_APIC_irq();
+
+	irq_err_count++;
+
+	spin_unlock(&err_lock);
+}
+
+/*
  * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts
  * per second. We assume that the caller has already set up the local
  * APIC.
@@ -1999,6 +594,10 @@
  * closely follows bus clocks.
  */
 
+int prof_multiplier[NR_CPUS] = { 1, };
+int prof_old_multiplier[NR_CPUS] = { 1, };
+int prof_counter[NR_CPUS] = { 1, };
+
 /*
  * The timer chip is already set up at HZ interrupts per second here,
  * but we do not accept timer interrupts yet. We only allow the BP
@@ -2015,66 +614,102 @@
 	return count;
 }
 
+void __init wait_8254_wraparound(void)
+{
+	unsigned int curr_count, prev_count=~0;
+	int delta;
+
+	curr_count = get_8254_timer_count();
+
+	do {
+		prev_count = curr_count;
+		curr_count = get_8254_timer_count();
+		delta = curr_count-prev_count;
+
+	/*
+	 * This limit for delta seems arbitrary, but it isn't, it's
+	 * slightly above the level of error a buggy Mercury/Neptune
+	 * chipset timer can cause.
+	 */
+
+	} while (delta<300);
+}
+
 /*
  * This function sets up the local APIC timer, with a timeout of
  * 'clocks' APIC bus clock. During calibration we actually call
- * this function twice, once with a bogus timeout value, second
- * time for real. The other (noncalibrating) CPUs call this
- * function only once, with the real value.
- *
- * We are strictly in irqs off mode here, as we do not want to
- * get an APIC interrupt go off accidentally.
+ * this function twice on the boot CPU, once with a bogus timeout
+ * value, second time for real. The other (noncalibrating) CPUs
+ * call this function only once, with the real, calibrated value.
  *
  * We do reads before writes even if unnecessary, to get around the
- * APIC double write bug.
+ * P5 APIC double write bug.
  */
 
 #define APIC_DIVISOR 16
 
-void setup_APIC_timer(unsigned int clocks)
+void __setup_APIC_LVTT(unsigned int clocks)
 {
-	unsigned long lvtt1_value;
-	unsigned int tmp_value;
+	unsigned int lvtt1_value, tmp_value;
 
-	/*
-	 * Unfortunately the local APIC timer cannot be set up into NMI
-	 * mode. With the IO APIC we can re-route the external timer
-	 * interrupt and broadcast it as an NMI to all CPUs, so no pain.
-	 */
 	tmp_value = apic_read(APIC_LVTT);
-	lvtt1_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
-	apic_write(APIC_LVTT , lvtt1_value);
+	lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) |
+			APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
+	apic_write(APIC_LVTT, lvtt1_value);
 
 	/*
 	 * Divide PICLK by 16
 	 */
 	tmp_value = apic_read(APIC_TDCR);
-	apic_write(APIC_TDCR , (tmp_value & ~APIC_TDR_DIV_1 )
-				 | APIC_TDR_DIV_16);
+	apic_write(APIC_TDCR, (tmp_value
+				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
+				| APIC_TDR_DIV_16);
 
 	tmp_value = apic_read(APIC_TMICT);
 	apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
 }
 
-void __init wait_8254_wraparound(void)
+void setup_APIC_timer(void * data)
 {
-	unsigned int curr_count, prev_count=~0;
+	unsigned int clocks = (unsigned int) data, slice, t0, t1, nr;
+	unsigned long flags;
 	int delta;
 
-	curr_count = get_8254_timer_count();
-
-	do {
-		prev_count = curr_count;
-		curr_count = get_8254_timer_count();
-		delta = curr_count-prev_count;
+	__save_flags(flags);
+	__sti();
+	/*
+	 * ok, Intel has some smart code in their APIC that knows
+	 * if a CPU was in 'hlt' lowpower mode, and this increases
+	 * its APIC arbitration priority. To avoid the external timer
+	 * IRQ APIC event being in synchron with the APIC clock we
+	 * introduce an interrupt skew to spread out timer events.
+	 *
+	 * The number of slices within a 'big' timeslice is smp_num_cpus+1
+	 */
 
+	slice = clocks / (smp_num_cpus+1);
+	nr = cpu_number_map[smp_processor_id()] + 1;
+	printk("cpu: %d, clocks: %d, slice: %d, nr: %d.\n",
+		smp_processor_id(), clocks, slice, nr);
 	/*
-	 * This limit for delta seems arbitrary, but it isn't, it's
-	 * slightly above the level of error a buggy Mercury/Neptune
-	 * chipset timer can cause.
+	 * Wait for IRQ0's slice:
 	 */
+	wait_8254_wraparound();
 
-	} while (delta<300);
+	__setup_APIC_LVTT(clocks);
+
+	t0 = apic_read(APIC_TMCCT)*APIC_DIVISOR;
+	do {
+		t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR;
+		delta = (int)(t0 - t1 - slice*nr);
+	} while (delta < 0);
+
+	__setup_APIC_LVTT(clocks);
+
+	printk("CPU%d<C0:%d,C:%d,D:%d,S:%d,C:%d>\n",
+			smp_processor_id(), t0, t1, delta, slice, clocks);
+
+	__restore_flags(flags);
 }
 
 /*
@@ -2092,10 +727,11 @@
 
 int __init calibrate_APIC_clock(void)
 {
-	unsigned long long t1,t2;
-	long tt1,tt2;
-	long calibration_result;
+	unsigned long long t1 = 0, t2 = 0;
+	long tt1, tt2;
+	long result;
 	int i;
+	const int LOOPS = HZ/10;
 
 	printk("calibrating APIC timer ... ");
 
@@ -2104,7 +740,7 @@
 	 * value into the APIC clock, we just want to get the
 	 * counter running for calibration.
 	 */
-	setup_APIC_timer(1000000000);
+	__setup_APIC_LVTT(1000000000);
 
 	/*
 	 * The timer chip counts down to zero. Let's wait
@@ -2112,23 +748,24 @@
 	 * (the current tick might have been already half done)
 	 */
 
-	wait_8254_wraparound ();
+	wait_8254_wraparound();
 
 	/*
 	 * We wrapped around just now. Let's start:
 	 */
-	rdtscll(t1);
-	tt1=apic_read(APIC_TMCCT);
+	if (cpu_has_tsc)
+		rdtscll(t1);
+	tt1 = apic_read(APIC_TMCCT);
 
-#define LOOPS (HZ/10)
 	/*
 	 * Let's wait LOOPS wraprounds:
 	 */
-	for (i=0; i<LOOPS; i++)
-		wait_8254_wraparound ();
+	for (i = 0; i < LOOPS; i++)
+		wait_8254_wraparound();
 
-	tt2=apic_read(APIC_TMCCT);
-	rdtscll(t2);
+	tt2 = apic_read(APIC_TMCCT);
+	if (cpu_has_tsc)
+		rdtscll(t2);
 
 	/*
 	 * The APIC bus clock counter is 32 bits only, it
@@ -2138,71 +775,37 @@
 	 * underflown to be exact, as the timer counts down ;)
 	 */
 
-	calibration_result = (tt1-tt2)*APIC_DIVISOR/LOOPS;
-
-	SMP_PRINTK(("\n..... %ld CPU clocks in 1 timer chip tick.",
-			 (unsigned long)(t2-t1)/LOOPS));
+	result = (tt1-tt2)*APIC_DIVISOR/LOOPS;
 
-	SMP_PRINTK(("\n..... %ld APIC bus clocks in 1 timer chip tick.",
-			 calibration_result));
+	if (cpu_has_tsc)
+		printk("\n..... CPU clock speed is %ld.%04ld MHz.\n",
+			((long)(t2-t1)/LOOPS)/(1000000/HZ),
+			((long)(t2-t1)/LOOPS)%(1000000/HZ));
+
+	printk("..... host bus clock speed is %ld.%04ld MHz.\n",
+		result/(1000000/HZ),
+		result%(1000000/HZ));
 
-
-	printk("\n..... CPU clock speed is %ld.%04ld MHz.\n",
-		((long)(t2-t1)/LOOPS)/(1000000/HZ),
-		((long)(t2-t1)/LOOPS)%(1000000/HZ)  );
-
-	printk("..... system bus clock speed is %ld.%04ld MHz.\n",
-		calibration_result/(1000000/HZ),
-		calibration_result%(1000000/HZ)  );
-#undef LOOPS
-
-	return calibration_result;
+	return result;
 }
 
-void __init setup_APIC_clock(void)
+static unsigned int calibration_result;
+
+void __init setup_APIC_clocks(void)
 {
 	unsigned long flags;
 
-	static volatile int calibration_lock;
-
 	__save_flags(flags);
 	__cli();
 
-	SMP_PRINTK(("setup_APIC_clock() called.\n"));
-
-	/*
-	 * [ setup_APIC_clock() is called from all CPUs, but we want
-	 *   to do this part of the setup only once ... and it fits
-	 *   here best ]
-	 */
-	if (!test_and_set_bit(0,&calibration_lock)) {
-
-		calibration_result=calibrate_APIC_clock();
-		/*
-	 	 * Signal completion to the other CPU[s]:
-	 	 */
-		calibration_lock = 3;
-
-	} else {
-		/*
-		 * Other CPU is calibrating, wait for finish:
-		 */
-		SMP_PRINTK(("waiting for other CPU calibrating APIC ... "));
-		while (calibration_lock == 1);
-		SMP_PRINTK(("done, continuing.\n"));
-	}
-
-/*
- * Now set up the timer for real.
- */
+	calibration_result = calibrate_APIC_clock();
 
-	setup_APIC_timer (calibration_result);
+	smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1);
 
 	/*
-	 * We ACK the APIC, just in case there is something pending.
+	 * Now set up the timer for real.
 	 */
-
-	ack_APIC_irq ();
+	setup_APIC_timer((void *)calibration_result);
 
 	__restore_flags(flags);
 }
@@ -2224,9 +827,9 @@
 		return -EINVAL;
 
 	/* 
-	 * Set the new multiplier for each CPU.  CPUs don't start using the
+	 * Set the new multiplier for each CPU. CPUs don't start using the
 	 * new values until the next timer interrupt in which they do process
-	 * accounting.  At that time they also adjust their APIC timers
+	 * accounting. At that time they also adjust their APIC timers
 	 * accordingly.
 	 */
 	for (i = 0; i < NR_CPUS; ++i)
@@ -2236,4 +839,112 @@
 }
 
 #undef APIC_DIVISOR
+
+/*
+ * Local timer interrupt handler. It does both profiling and
+ * process statistics/rescheduling.
+ *
+ * We do profiling in every local tick, statistics/rescheduling
+ * happen only every 'profiling multiplier' ticks. The default
+ * multiplier is 1 and it can be changed by writing the new multiplier
+ * value into /proc/profile.
+ */
+
+inline void smp_local_timer_interrupt(struct pt_regs * regs)
+{
+	int user = (user_mode(regs) != 0);
+	int cpu = smp_processor_id();
+
+	/*
+	 * The profiling function is SMP safe. (nothing can mess
+	 * around with "current", and the profiling counters are
+	 * updated with atomic operations). This is especially
+	 * useful with a profiling multiplier != 1
+	 */
+	if (!user)
+		x86_do_profile(regs->eip);
+
+	if (--prof_counter[cpu] <= 0) {
+		int system = 1 - user;
+		struct task_struct * p = current;
+
+		/*
+		 * The multiplier may have changed since the last time we got
+		 * to this point as a result of the user writing to
+		 * /proc/profile. In this case we need to adjust the APIC
+		 * timer accordingly.
+		 *
+		 * Interrupts are already masked off at this point.
+		 */
+		prof_counter[cpu] = prof_multiplier[cpu];
+		if (prof_counter[cpu] != prof_old_multiplier[cpu]) {
+			__setup_APIC_LVTT(calibration_result/prof_counter[cpu]);
+			prof_old_multiplier[cpu] = prof_counter[cpu];
+		}
+
+		/*
+		 * After doing the above, we need to make like
+		 * a normal interrupt - otherwise timer interrupts
+		 * ignore the global interrupt lock, which is the
+		 * WrongThing (tm) to do.
+		 */
+
+ 		irq_enter(cpu, 0);
+		update_one_process(p, 1, user, system, cpu);
+		if (p->pid) {
+			p->counter -= 1;
+			if (p->counter <= 0) {
+				p->counter = 0;
+				p->need_resched = 1;
+			}
+			if (p->priority < DEF_PRIORITY) {
+				kstat.cpu_nice += user;
+				kstat.per_cpu_nice[cpu] += user;
+			} else {
+				kstat.cpu_user += user;
+				kstat.per_cpu_user[cpu] += user;
+			}
+			kstat.cpu_system += system;
+			kstat.per_cpu_system[cpu] += system;
+
+		}
+		irq_exit(cpu, 0);
+	}
+
+	/*
+	 * We take the 'long' return path, and there every subsystem
+	 * grabs the apropriate locks (kernel lock/ irq lock).
+	 *
+	 * we might want to decouple profiling from the 'long path',
+	 * and do the profiling totally in assembly.
+	 *
+	 * Currently this isn't too much of an issue (performance wise),
+	 * we can take more than 100K local irqs per second on a 100 MHz P5.
+	 */
+}
+
+/*
+ * Local APIC timer interrupt. This is the most natural way for doing
+ * local interrupts, but local timer interrupts can be emulated by
+ * broadcast interrupts too. [in case the hw doesnt support APIC timers]
+ *
+ * [ if a single-CPU system runs an SMP kernel then we call the local
+ *   interrupt as well. Thus we cannot inline the local irq ... ]
+ */
+unsigned int apic_timer_irqs [NR_CPUS] = { 0, };
+
+void smp_apic_timer_interrupt(struct pt_regs * regs)
+{
+	/*
+	 * the NMI deadlock-detector uses this.
+	 */
+	apic_timer_irqs[smp_processor_id()]++;
+
+	/*
+	 * NOTE! We'd better ACK the irq immediately,
+	 * because timer handling can be slow.
+	 */
+	ack_APIC_irq();
+	smp_local_timer_interrupt(regs);
+}
 
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c
--- v2.3.19/linux/arch/i386/kernel/smpboot.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/kernel/smpboot.c	Thu Oct  7 10:17:08 1999
@@ -0,0 +1,1650 @@
+/*
+ *	Intel MP v1.1/v1.4 specification compliant parsing routines.
+ *
+ *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
+ *	(c) 1998, 1999 Ingo Molnar <mingo@redhat.com>
+ *
+ *	Much of the core SMP work is based on previous work by Thomas Radke, to
+ *	whom a great many thanks are extended.
+ *
+ *	Thanks to Intel for making available several different Pentium,
+ *	Pentium Pro and Pentium-II/Xeon MP machines.
+ *	Original development of Linux SMP code supported by Caldera.
+ *
+ *	This code is released under the GNU public license version 2 or
+ *	later.
+ *
+ *	Fixes
+ *		Felix Koop	:	NR_CPUS used properly
+ *		Jose Renau	:	Handle single CPU case.
+ *		Alan Cox	:	By repeated request 8) - Total BogoMIP report.
+ *		Greg Wright	:	Fix for kernel stacks panic.
+ *		Erich Boleyn	:	MP v1.4 and additional changes.
+ *	Matthias Sattler	:	Changes for 2.1 kernel map.
+ *	Michel Lespinasse	:	Changes for 2.1 kernel map.
+ *	Michael Chastain	:	Change trampoline.S to gnu as.
+ *		Alan Cox	:	Dumb bug: 'B' step PPro's are fine
+ *		Ingo Molnar	:	Added APIC timers, based on code
+ *					from Jose Renau
+ *		Alan Cox	:	Added EBDA scanning
+ *		Ingo Molnar	:	various cleanups and rewrites
+ *		Tigran Aivazian	:	fixed "0.00 in /proc/uptime on SMP" bug.
+ *	Maciej W. Rozycki	:	Bits for genuine 82489DX timers
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <linux/mm.h>
+#include <linux/kernel_stat.h>
+#include <linux/smp_lock.h>
+#include <linux/irq.h>
+
+#include <linux/delay.h>
+#include <linux/mc146818rtc.h>
+#include <asm/mtrr.h>
+
+/* Set if we find a B stepping CPU			*/
+static int smp_b_stepping = 0;
+
+/* Setup configured maximum number of CPUs to activate */
+static int max_cpus = -1;
+/* 1 if "noapic" boot option passed */
+int skip_ioapic_setup = 0;
+
+/* Total count of live CPUs */
+int smp_num_cpus = 0;
+/* Internal processor count */
+static unsigned int num_processors = 1;
+
+/* Have we found an SMP box */
+int smp_found_config = 0;
+
+/* Bitmask of physically existing CPUs */
+unsigned long cpu_present_map = 0;
+/* Bitmask of currently online CPUs */
+unsigned long cpu_online_map = 0;
+
+/* which CPU maps to which logical number */
+volatile int cpu_number_map[NR_CPUS];
+/* which logical number maps to which CPU */
+volatile int __cpu_logical_map[NR_CPUS];
+
+static volatile unsigned long cpu_callin_map = 0;
+static volatile unsigned long cpu_callout_map = 0;
+
+/* Per CPU bogomips and other parameters */
+struct cpuinfo_x86 cpu_data[NR_CPUS];
+/* Processor that is doing the boot up */
+static unsigned int boot_cpu_id = 0;
+
+/* Tripped once we need to start cross invalidating */
+static int smp_activated = 0;
+/* Set when the idlers are all forked */
+int smp_threads_ready = 0;
+
+/*
+ * Various Linux-internal data structures created from the
+ * MP-table.
+ */
+int apic_version [NR_CPUS];
+int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
+extern int nr_ioapics;
+extern struct mpc_config_ioapic mp_ioapics [MAX_IO_APICS];
+extern int mp_irq_entries;
+extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
+extern int mpc_default_type;
+int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, };
+int mp_current_pci_id = 0;
+unsigned long mp_lapic_addr = 0;
+int pic_mode;
+
+extern void cache_APIC_registers (void);
+
+#define SMP_DEBUG 1
+
+#if SMP_DEBUG
+#define dprintk(x...) printk(##x)
+#else
+#define dprintk(x...)
+#endif
+
+/*
+ * IA s/w dev Vol 3, Section 7.4
+ */
+#define APIC_DEFAULT_PHYS_BASE 0xfee00000
+
+/*
+ * Setup routine for controlling SMP activation
+ *
+ * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
+ * activation entirely (the MPS table probe still happens, though).
+ *
+ * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
+ * greater than 0, limits the maximum number of CPUs activated in
+ * SMP mode to <NUM>.
+ */
+
+static int __init nosmp(char *str)
+{
+	max_cpus = 0;
+	return 1;
+}
+
+__setup("nosmp", nosmp);
+
+static int __init maxcpus(char *str)
+{
+	get_option(&str, &max_cpus);
+	return 1;
+}
+
+__setup("maxcpus=", maxcpus);
+
+/*
+ * Intel MP BIOS table parsing routines:
+ */
+
+#ifndef CONFIG_X86_VISWS_APIC
+/*
+ * Checksum an MP configuration block.
+ */
+
+static int __init mpf_checksum(unsigned char *mp, int len)
+{
+	int sum=0;
+	while(len--)
+		sum+=*mp++;
+	return sum&0xFF;
+}
+
+/*
+ * Processor encoding in an MP configuration block
+ */
+
+static char __init *mpc_family(int family,int model)
+{
+	static char n[32];
+	static char *model_defs[]=
+	{
+		"80486DX","80486DX",
+		"80486SX","80486DX/2 or 80487",
+		"80486SL","80486SX/2",
+		"Unknown","80486DX/2-WB",
+		"80486DX/4","80486DX/4-WB"
+	};
+
+	switch (family) {
+		case 0x04:
+			if (model < 10)
+				return model_defs[model];
+			break;
+
+		case 0x05:
+			return("Pentium(tm)");
+
+		case 0x06:
+			return("Pentium(tm) Pro");
+
+		case 0x0F:
+			if (model == 0x0F)
+				return("Special controller");
+	}
+	sprintf(n,"Unknown CPU [%d:%d]",family, model);
+	return n;
+}
+
+static void __init MP_processor_info (struct mpc_config_processor *m)
+{
+	int ver;
+
+	if (!(m->mpc_cpuflag & CPU_ENABLED))
+		return;
+
+	printk("Processor #%d %s APIC version %d\n",
+		m->mpc_apicid,
+		mpc_family(	(m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 ,
+				(m->mpc_cpufeature & CPU_MODEL_MASK)>>4),
+		m->mpc_apicver);
+
+#ifdef SMP_DEBUG
+	if (m->mpc_featureflag&(1<<0))
+		printk("    Floating point unit present.\n");
+	if (m->mpc_featureflag&(1<<7))
+		printk("    Machine Exception supported.\n");
+	if (m->mpc_featureflag&(1<<8))
+		printk("    64 bit compare & exchange supported.\n");
+	if (m->mpc_featureflag&(1<<9))
+		printk("    Internal APIC present.\n");
+#endif
+
+	if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
+		dprintk("    Bootup CPU\n");
+		boot_cpu_id = m->mpc_apicid;
+	} else
+		/* Boot CPU already counted */
+		num_processors++;
+
+	if (m->mpc_apicid > NR_CPUS) {
+		printk("Processor #%d unused. (Max %d processors).\n",
+			m->mpc_apicid, NR_CPUS);
+		return;
+	}
+	ver = m->mpc_apicver;
+
+	cpu_present_map |= (1<<m->mpc_apicid);
+	/*
+	 * Validate version
+	 */
+	if (ver == 0x0) {
+		printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid);
+		ver = 0x10;
+	}
+	apic_version[m->mpc_apicid] = ver;
+}
+
+static void __init MP_bus_info (struct mpc_config_bus *m)
+{
+	char str[7];
+
+	memcpy(str, m->mpc_bustype, 6);
+	str[6] = 0;
+	dprintk("Bus #%d is %s\n", m->mpc_busid, str);
+
+	if (strncmp(str, "ISA", 3) == 0) {
+		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
+	} else {
+	if (strncmp(str, "EISA", 4) == 0) {
+		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
+	} else {
+	if (strncmp(str, "PCI", 3) == 0) {
+		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
+		mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
+		mp_current_pci_id++;
+	} else {
+		printk("Unknown bustype %s\n", str);
+		panic("cannot handle bus - mail to linux-smp@vger.rutgers.edu");
+	} } }
+}
+
+static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
+{
+	if (!(m->mpc_flags & MPC_APIC_USABLE))
+		return;
+
+	printk("I/O APIC #%d Version %d at 0x%lX.\n",
+		m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr);
+	if (nr_ioapics >= MAX_IO_APICS) {
+		printk("Max # of I/O APICs (%d) exceeded (found %d).\n",
+			MAX_IO_APICS, nr_ioapics);
+		panic("Recompile kernel with bigger MAX_IO_APICS!.\n");
+	}
+	mp_ioapics[nr_ioapics] = *m;
+	nr_ioapics++;
+}
+
+static void __init MP_intsrc_info (struct mpc_config_intsrc *m)
+{
+	mp_irqs [mp_irq_entries] = *m;
+	if (++mp_irq_entries == MAX_IRQ_SOURCES)
+		panic("Max # of irq sources exceeded!!\n");
+}
+
+static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m)
+{
+	/*
+	 * Well it seems all SMP boards in existence
+	 * use ExtINT/LVT1 == LINT0 and
+	 * NMI/LVT2 == LINT1 - the following check
+	 * will show us if this assumptions is false.
+	 * Until then we do not have to add baggage.
+	 */
+	if ((m->mpc_irqtype == mp_ExtINT) &&
+		(m->mpc_destapiclint != 0))
+			BUG();
+	if ((m->mpc_irqtype == mp_NMI) &&
+		(m->mpc_destapiclint != 1))
+			BUG();
+}
+
+/*
+ * Read/parse the MPC
+ */
+
+static int __init smp_read_mpc(struct mp_config_table *mpc)
+{
+	char str[16];
+	int count=sizeof(*mpc);
+	unsigned char *mpt=((unsigned char *)mpc)+count;
+
+	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4))
+	{
+		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
+			mpc->mpc_signature[0],
+			mpc->mpc_signature[1],
+			mpc->mpc_signature[2],
+			mpc->mpc_signature[3]);
+		return 1;
+	}
+	if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length))
+	{
+		panic("SMP mptable: checksum error!\n");
+		return 1;
+	}
+	if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04)
+	{
+		printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec);
+		return 1;
+	}
+	memcpy(str,mpc->mpc_oem,8);
+	str[8]=0;
+	printk("OEM ID: %s ",str);
+
+	memcpy(str,mpc->mpc_productid,12);
+	str[12]=0;
+	printk("Product ID: %s ",str);
+
+	printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
+
+	/* save the local APIC address, it might be non-default */
+	mp_lapic_addr = mpc->mpc_lapic;
+
+	/*
+	 *	Now process the configuration blocks.
+	 */
+	while (count < mpc->mpc_length) {
+		switch(*mpt) {
+			case MP_PROCESSOR:
+			{
+				struct mpc_config_processor *m=
+					(struct mpc_config_processor *)mpt;
+				MP_processor_info(m);
+				mpt += sizeof(*m);
+				count += sizeof(*m);
+				break;
+			}
+			case MP_BUS:
+			{
+				struct mpc_config_bus *m=
+					(struct mpc_config_bus *)mpt;
+				MP_bus_info(m);
+				mpt += sizeof(*m);
+				count += sizeof(*m);
+				break;
+			}
+			case MP_IOAPIC:
+			{
+				struct mpc_config_ioapic *m=
+					(struct mpc_config_ioapic *)mpt;
+				MP_ioapic_info(m);
+				mpt+=sizeof(*m);
+				count+=sizeof(*m);
+				break;
+			}
+			case MP_INTSRC:
+			{
+				struct mpc_config_intsrc *m=
+					(struct mpc_config_intsrc *)mpt;
+
+				MP_intsrc_info(m);
+				mpt+=sizeof(*m);
+				count+=sizeof(*m);
+				break;
+			}
+			case MP_LINTSRC:
+			{
+				struct mpc_config_lintsrc *m=
+					(struct mpc_config_lintsrc *)mpt;
+				MP_lintsrc_info(m);
+				mpt+=sizeof(*m);
+				count+=sizeof(*m);
+				break;
+			}
+		}
+	}
+	return num_processors;
+}
+
+/*
+ * Scan the memory blocks for an SMP configuration block.
+ */
+static int __init smp_get_mpf(struct intel_mp_floating *mpf)
+{
+	printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
+	if (mpf->mpf_feature2 & (1<<7)) {
+		printk("    IMCR and PIC compatibility mode.\n");
+		pic_mode = 1;
+	} else {
+		printk("    Virtual Wire compatibility mode.\n");
+		pic_mode = 0;
+	}
+	smp_found_config = 1;
+	/*
+	 * default CPU id - if it's different in the mptable
+	 * then we change it before first using it.
+	 */
+	boot_cpu_id = 0;
+	/*
+	 * Now see if we need to read further.
+	 */
+	if (mpf->mpf_feature1 != 0) {
+		/*
+		 * local APIC has default address
+		 */
+		mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+
+		/*
+		 * 2 CPUs, numbered 0 & 1.
+		 */
+		cpu_present_map = 3;
+		num_processors = 2;
+
+		nr_ioapics = 1;
+		mp_ioapics[0].mpc_apicaddr = 0xFEC00000;
+		/*
+		 * Save the default type number, we
+		 * need it later to set the IO-APIC
+		 * up properly:
+		 */
+		mpc_default_type = mpf->mpf_feature1;
+
+		printk("Bus #0 is ");
+	}
+
+	switch (mpf->mpf_feature1) {
+		case 1:
+		case 5:
+			printk("ISA\n");
+			break;
+		case 2:
+			printk("EISA with no IRQ0 and no IRQ13 DMA chaining\n");
+			break;
+		case 6:
+		case 3:
+			printk("EISA\n");
+			break;
+		case 4:
+		case 7:
+			printk("MCA\n");
+			break;
+		case 0:
+			if (!mpf->mpf_physptr)
+				BUG();
+			break;
+		default:
+			printk("???\nUnknown standard configuration %d\n",
+				mpf->mpf_feature1);
+			return 1;
+	}
+	if (mpf->mpf_feature1 > 4) {
+		printk("Bus #1 is PCI\n");
+
+		/*
+		 * Set local APIC version to the integrated form.
+		 * It's initialized to zero otherwise, representing
+		 * a discrete 82489DX.
+		 */
+		apic_version[0] = 0x10;
+		apic_version[1] = 0x10;
+	}
+	/*
+	 * Read the physical hardware table. Anything here will override the
+	 * defaults.
+	 */
+	if (mpf->mpf_physptr)
+		smp_read_mpc((void *)mpf->mpf_physptr);
+
+	__cpu_logical_map[0] = boot_cpu_id;
+	global_irq_holder = boot_cpu_id;
+	current->processor = boot_cpu_id;
+
+	printk("Processors: %d\n", num_processors);
+	/*
+	 * Only use the first configuration found.
+	 */
+	return 1;
+}
+
+static int __init smp_scan_config(unsigned long base, unsigned long length)
+{
+	unsigned long *bp = phys_to_virt(base);
+	struct intel_mp_floating *mpf;
+
+	dprintk("Scan SMP from %p for %ld bytes.\n", bp,length);
+	if (sizeof(*mpf) != 16)
+		printk("Error: MPF size\n");
+
+	while (length > 0) {
+		mpf = (struct intel_mp_floating *)bp;
+		if ((*bp == SMP_MAGIC_IDENT) &&
+			(mpf->mpf_length == 1) &&
+			!mpf_checksum((unsigned char *)bp, 16) &&
+			((mpf->mpf_specification == 1)
+				|| (mpf->mpf_specification == 4)) ) {
+
+			printk("found SMP MP-table at %08ld\n",
+						virt_to_phys(mpf));
+			smp_get_mpf(mpf);
+			return 1;
+		}
+		bp += 4;
+		length -= 16;
+	}
+	return 0;
+}
+
+void __init init_intel_smp (void)
+{
+	unsigned int address;
+
+	/*
+	 * FIXME: Linux assumes you have 640K of base ram..
+	 * this continues the error...
+	 *
+	 * 1) Scan the bottom 1K for a signature
+	 * 2) Scan the top 1K of base RAM
+	 * 3) Scan the 64K of bios
+	 */
+	if (smp_scan_config(0x0,0x400) ||
+		smp_scan_config(639*0x400,0x400) ||
+			smp_scan_config(0xF0000,0x10000))
+		return;
+	/*
+	 * If it is an SMP machine we should know now, unless the
+	 * configuration is in an EISA/MCA bus machine with an
+	 * extended bios data area.
+	 *
+	 * there is a real-mode segmented pointer pointing to the
+	 * 4K EBDA area at 0x40E, calculate and scan it here.
+	 *
+	 * NOTE! There are Linux loaders that will corrupt the EBDA
+	 * area, and as such this kind of SMP config may be less
+	 * trustworthy, simply because the SMP table may have been
+	 * stomped on during early boot. These loaders are buggy and
+	 * should be fixed.
+	 */
+
+	address = *(unsigned short *)phys_to_virt(0x40E);
+	address <<= 4;
+	smp_scan_config(address, 0x1000);
+	if (smp_found_config)
+		printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n");
+}
+
+#else
+
+/*
+ * The Visual Workstation is Intel MP compliant in the hardware
+ * sense, but it doesnt have a BIOS(-configuration table).
+ * No problem for Linux.
+ */
+void __init init_visws_smp(void)
+{
+	smp_found_config = 1;
+
+	cpu_present_map |= 2; /* or in id 1 */
+	apic_version[1] |= 0x10; /* integrated APIC */
+	apic_version[0] |= 0x10;
+
+	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+}
+
+#endif
+
+/*
+ * - Intel MP Configuration Table
+ * - or SGI Visual Workstation configuration
+ */
+void __init init_smp_config (void)
+{
+#ifndef CONFIG_VISWS
+	init_intel_smp();
+#else
+	init_visws_smp();
+#endif
+}
+
+
+
+/*
+ * Trampoline 80x86 program as an array.
+ */
+
+extern unsigned char trampoline_data [];
+extern unsigned char trampoline_end  [];
+static unsigned char *trampoline_base;
+
+/*
+ * Currently trivial. Write the real->protected mode
+ * bootstrap into the page concerned. The caller
+ * has made sure it's suitably aligned.
+ */
+
+static unsigned long __init setup_trampoline(void)
+{
+	memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
+	return virt_to_phys(trampoline_base);
+}
+
+/*
+ * We are called very early to get the low memory for the
+ * SMP bootup trampoline page.
+ */
+unsigned long __init smp_alloc_memory(unsigned long mem_base)
+{
+	if (virt_to_phys((void *)mem_base) >= 0x9F000)
+		BUG();
+	trampoline_base = (void *)mem_base;
+	return mem_base + PAGE_SIZE;
+}
+
+/*
+ * The bootstrap kernel entry code has set these up. Save them for
+ * a given CPU
+ */
+
+void __init smp_store_cpu_info(int id)
+{
+	struct cpuinfo_x86 *c=&cpu_data[id];
+
+	*c = boot_cpu_data;
+	c->pte_quick = 0;
+	c->pgd_quick = 0;
+	c->pgtable_cache_sz = 0;
+	identify_cpu(c);
+	/*
+	 * Mask B, Pentium, but not Pentium MMX
+	 */
+	if (c->x86_vendor == X86_VENDOR_INTEL &&
+	    c->x86 == 5 &&
+	    c->x86_mask >= 1 && c->x86_mask <= 4 &&
+	    c->x86_model <= 3)
+		/*
+		 * Remember we have B step Pentia with bugs
+		 */
+		smp_b_stepping = 1;
+}
+
+/*
+ * Architecture specific routine called by the kernel just before init is
+ * fired off. This allows the BP to have everything in order [we hope].
+ * At the end of this all the APs will hit the system scheduling and off
+ * we go. Each AP will load the system gdt's and jump through the kernel
+ * init into idle(). At this point the scheduler will one day take over
+ * and give them jobs to do. smp_callin is a standard routine
+ * we use to track CPUs as they power up.
+ */
+
+static atomic_t smp_commenced = ATOMIC_INIT(0);
+
+void __init smp_commence(void)
+{
+	/*
+	 * Lets the callins below out of their loop.
+	 */
+	dprintk("Setting commenced=1, go go go\n");
+
+	wmb();
+	atomic_set(&smp_commenced,1);
+}
+
+extern void __error_in_io_apic_c(void);
+
+
+int get_maxlvt(void)
+{
+	unsigned int v, ver, maxlvt;
+
+	v = apic_read(APIC_LVR);
+	ver = GET_APIC_VERSION(v);
+	/* 82489DXs do not report # of LVT entries. */
+	maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
+	return maxlvt;
+}
+
+void __init setup_local_APIC(void)
+{
+	unsigned long value, ver, maxlvt;
+
+	if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f)
+		__error_in_io_apic_c();
+
+ 	value = apic_read(APIC_SPIV);
+	value = 0xf;
+	/*
+	 * Enable APIC
+	 */
+ 	value |= (1<<8);
+#if 0
+	/* Enable focus processor (bit==0) */
+ 	value &= ~(1<<9);
+#else
+	/* Disable focus processor (bit==1) */
+	value |= (1<<9);
+#endif
+	/*
+	 * Set spurious IRQ vector
+	 */
+	value |= SPURIOUS_APIC_VECTOR;
+ 	apic_write(APIC_SPIV,value);
+
+	/*
+	 * Set up LVT0, LVT1:
+	 *
+	 * set up through-local-APIC on the BP's LINT0. This is not
+	 * strictly necessery in pure symmetric-IO mode, but sometimes
+	 * we delegate interrupts to the 8259A.
+	 */
+	if (hard_smp_processor_id() == boot_cpu_id) {
+		value = 0x00000700;
+		printk("enabled ExtINT on CPU#%d\n", hard_smp_processor_id());
+	} else {
+		value = 0x00010700;
+		printk("masked ExtINT on CPU#%d\n", hard_smp_processor_id());
+	}
+ 	apic_write_around(APIC_LVT0,value);
+
+	/*
+	 * only the BP should see the LINT1 NMI signal, obviously.
+	 */
+	if (hard_smp_processor_id() == boot_cpu_id)
+		value = 0x00000400;		// unmask NMI
+	else
+		value = 0x00010400;		// mask NMI
+ 	apic_write_around(APIC_LVT1,value);
+
+	value = apic_read(APIC_LVR);
+	ver = GET_APIC_VERSION(value);
+	if (APIC_INTEGRATED(ver)) {		/* !82489DX */
+		maxlvt = get_maxlvt();
+		/*
+		 * Due to the Pentium erratum 3AP.
+		 */
+		if (maxlvt > 3) {
+			apic_readaround(APIC_SPIV); // not strictly necessery
+			apic_write(APIC_ESR, 0);
+		}
+		value = apic_read(APIC_ESR);
+		printk("ESR value before enabling vector: %08lx\n", value);
+
+		value = apic_read(APIC_LVTERR);
+		value = ERROR_APIC_VECTOR;      // enables sending errors
+		apic_write(APIC_LVTERR,value);
+		/*
+		 * spec says clear errors after enabling vector.
+		 */
+		if (maxlvt != 3) {
+			apic_readaround(APIC_SPIV);
+			apic_write(APIC_ESR, 0);
+		}
+		value = apic_read(APIC_ESR);
+		printk("ESR value after enabling vector: %08lx\n", value);
+	} else
+		printk("No ESR for 82489DX.\n");
+
+	/*
+	 * Set Task Priority to 'accept all'. We never change this
+	 * later on.
+	 */
+ 	value = apic_read(APIC_TASKPRI);
+ 	value &= ~APIC_TPRI_MASK;
+ 	apic_write(APIC_TASKPRI,value);
+
+	/*
+	 * Set up the logical destination ID and put the
+	 * APIC into flat delivery mode.
+	 */
+ 	value = apic_read(APIC_LDR);
+	value &= ~APIC_LDR_MASK;
+	value |= (1<<(smp_processor_id()+24));
+ 	apic_write(APIC_LDR,value);
+
+ 	value = apic_read(APIC_DFR);
+	value |= SET_APIC_DFR(0xf);
+ 	apic_write(APIC_DFR, value);
+}
+
+unsigned long __init init_smp_mappings(unsigned long memory_start)
+{
+	unsigned long apic_phys;
+
+	memory_start = PAGE_ALIGN(memory_start);
+	if (smp_found_config) {
+		apic_phys = mp_lapic_addr;
+	} else {
+		/*
+		 * set up a fake all zeroes page to simulate the
+		 * local APIC and another one for the IO-APIC. We
+		 * could use the real zero-page, but it's safer
+		 * this way if some buggy code writes to this page ...
+		 */
+		apic_phys = __pa(memory_start);
+		memset((void *)memory_start, 0, PAGE_SIZE);
+		memory_start += PAGE_SIZE;
+	}
+	set_fixmap(FIX_APIC_BASE,apic_phys);
+	dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
+
+#ifdef CONFIG_X86_IO_APIC
+	{
+		unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
+		int i;
+
+		for (i = 0; i < nr_ioapics; i++) {
+			if (smp_found_config) {
+				ioapic_phys = mp_ioapics[i].mpc_apicaddr;
+			} else {
+				ioapic_phys = __pa(memory_start);
+				memset((void *)memory_start, 0, PAGE_SIZE);
+				memory_start += PAGE_SIZE;
+			}
+			set_fixmap(idx,ioapic_phys);
+			dprintk("mapped IOAPIC to %08lx (%08lx)\n",
+					__fix_to_virt(idx), ioapic_phys);
+			idx++;
+		}
+	}
+#endif
+
+	return memory_start;
+}
+
+/*
+ * TSC synchronization.
+ *
+ * We first check wether all CPUs have their TSC's synchronized,
+ * then we print a warning if not, and always resync.
+ */
+
+static atomic_t tsc_start_flag = ATOMIC_INIT(0);
+static atomic_t tsc_count_start = ATOMIC_INIT(0);
+static atomic_t tsc_count_stop = ATOMIC_INIT(0);
+static unsigned long long tsc_values[NR_CPUS] = { 0, };
+
+#define NR_LOOPS 5
+
+extern unsigned long fast_gettimeoffset_quotient;
+
+/*
+ * accurate 64-bit/32-bit division, expanded to 32-bit divisions and 64-bit
+ * multiplication. Not terribly optimized but we need it at boot time only
+ * anyway.
+ *
+ * result == a / b
+ *	== (a1 + a2*(2^32)) / b
+ *	== a1/b + a2*(2^32/b)
+ *	== a1/b + a2*((2^32-1)/b) + a2/b + (a2*((2^32-1) % b))/b
+ *		    ^---- (this multiplication can overflow)
+ */
+
+static unsigned long long div64 (unsigned long long a, unsigned long b0)
+{
+	unsigned int a1, a2;
+	unsigned long long res;
+
+	a1 = ((unsigned int*)&a)[0];
+	a2 = ((unsigned int*)&a)[1];
+
+	res = a1/b0 +
+		(unsigned long long)a2 * (unsigned long long)(0xffffffff/b0) +
+		a2 / b0 +
+		(a2 * (0xffffffff % b0)) / b0;
+
+	return res;
+}
+
+static void __init synchronize_tsc_bp (void)
+{
+	int i;
+	unsigned long long t0;
+	unsigned long long sum, avg;
+	long long delta;
+	unsigned long one_usec;
+	int buggy = 0;
+
+	printk("checking TSC synchronization across CPUs: ");
+
+	one_usec = ((1<<30)/fast_gettimeoffset_quotient)*(1<<2);
+
+	atomic_set(&tsc_start_flag, 1);
+	wmb();
+
+	/*
+	 * We loop a few times to get a primed instruction cache,
+	 * then the last pass is more or less synchronized and
+	 * the BP and APs set their cycle counters to zero all at
+	 * once. This reduces the chance of having random offsets
+	 * between the processors, and guarantees that the maximum
+	 * delay between the cycle counters is never bigger than
+	 * the latency of information-passing (cachelines) between
+	 * two CPUs.
+	 */
+	for (i = 0; i < NR_LOOPS; i++) {
+		/*
+		 * all APs synchronize but they loop on '== num_cpus'
+		 */
+		while (atomic_read(&tsc_count_start) != smp_num_cpus-1) mb();
+		atomic_set(&tsc_count_stop, 0);
+		wmb();
+		/*
+		 * this lets the APs save their current TSC:
+		 */
+		atomic_inc(&tsc_count_start);
+
+		rdtscll(tsc_values[smp_processor_id()]);
+		/*
+		 * We clear the TSC in the last loop:
+		 */
+		if (i == NR_LOOPS-1)
+			write_tsc(0, 0);
+
+		/*
+		 * Wait for all APs to leave the synchronization point:
+		 */
+		while (atomic_read(&tsc_count_stop) != smp_num_cpus-1) mb();
+		atomic_set(&tsc_count_start, 0);
+		wmb();
+		atomic_inc(&tsc_count_stop);
+	}
+
+	sum = 0;
+	for (i = 0; i < NR_CPUS; i++) {
+		if (!(cpu_online_map & (1 << i)))
+			continue;
+
+		t0 = tsc_values[i];
+		sum += t0;
+	}
+	avg = div64(sum, smp_num_cpus);
+
+	sum = 0;
+	for (i = 0; i < NR_CPUS; i++) {
+		if (!(cpu_online_map & (1 << i)))
+			continue;
+
+		delta = tsc_values[i] - avg;
+		if (delta < 0)
+			delta = -delta;
+		/*
+		 * We report bigger than 2 microseconds clock differences.
+		 */
+		if (delta > 2*one_usec) {
+			long realdelta;
+			if (!buggy) {
+				buggy = 1;
+				printk("\n");
+			}
+			realdelta = div64(delta, one_usec);
+			if (tsc_values[i] < avg)
+				realdelta = -realdelta;
+
+			printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n",
+				i, realdelta);
+		}
+
+		sum += delta;
+	}
+	if (!buggy)
+		printk("passed.\n");
+}
+
+static void __init synchronize_tsc_ap (void)
+{
+	int i;
+
+	/*
+	 * smp_num_cpus is not necessarily known at the time
+	 * this gets called, so we first wait for the BP to
+	 * finish SMP initialization:
+	 */
+	while (!atomic_read(&tsc_start_flag)) mb();
+
+	for (i = 0; i < NR_LOOPS; i++) {
+		atomic_inc(&tsc_count_start);
+		while (atomic_read(&tsc_count_start) != smp_num_cpus) mb();
+
+		rdtscll(tsc_values[smp_processor_id()]);
+		if (i == NR_LOOPS-1)
+			write_tsc(0, 0);
+
+		atomic_inc(&tsc_count_stop);
+		while (atomic_read(&tsc_count_stop) != smp_num_cpus) mb();
+	}
+}
+#undef NR_LOOPS
+
+extern void calibrate_delay(void);
+
+void __init smp_callin(void)
+{
+	int cpuid;
+	unsigned long timeout;
+
+	/*
+	 * (This works even if the APIC is not enabled.)
+	 */
+	cpuid = GET_APIC_ID(apic_read(APIC_ID));
+
+	dprintk("CPU#%d waiting for CALLOUT\n", cpuid);
+
+	/*
+	 * STARTUP IPIs are fragile beasts as they might sometimes
+	 * trigger some glue motherboard logic. Complete APIC bus
+	 * silence for 1 second, this overestimates the time the
+	 * boot CPU is spending to send the up to 2 STARTUP IPIs
+	 * by a factor of two. This should be enough.
+	 */
+
+	/*
+	 * Waiting 2s total for startup (udelay is not yet working)
+	 */
+	timeout = jiffies + 2*HZ;
+	while (time_before(jiffies, timeout)) {
+		/*
+		 * Has the boot CPU finished it's STARTUP sequence?
+		 */
+		if (test_bit(cpuid, &cpu_callout_map))
+			break;
+	}
+
+	if (!time_before(jiffies, timeout)) {
+		printk("BUG: CPU%d started up but did not get a callout!\n",
+			cpuid);
+		BUG();
+	}
+
+	/*
+	 * the boot CPU has finished the init stage and is spinning
+	 * on callin_map until we finish. We are free to set up this
+	 * CPU, first the APIC. (this is probably redundant on most
+	 * boards)
+	 */
+
+	dprintk("CALLIN, before setup_local_APIC().\n");
+	setup_local_APIC();
+
+	sti();
+
+#ifdef CONFIG_MTRR
+	/*
+	 * Must be done before calibration delay is computed
+	 */
+	mtrr_init_secondary_cpu ();
+#endif
+	/*
+	 * Get our bogomips.
+	 */
+	calibrate_delay();
+	dprintk("Stack at about %p\n",&cpuid);
+
+	/*
+	 * Save our processor parameters
+	 */
+ 	smp_store_cpu_info(cpuid);
+
+	/*
+	 * Allow the master to continue.
+	 */
+	set_bit(cpuid, &cpu_callin_map);
+
+	/*
+	 *      Synchronize the TSC with the BP
+	 */
+	if (cpu_has_tsc)
+		synchronize_tsc_ap ();
+}
+
+int cpucount = 0;
+
+extern int cpu_idle(void);
+
+/*
+ * Activate a secondary processor.
+ */
+int __init start_secondary(void *unused)
+{
+	/*
+	 * Dont put anything before smp_callin(), SMP
+	 * booting is too fragile that we want to limit the
+	 * things done here to the most necessary things.
+	 */
+	cpu_init();
+	smp_callin();
+	while (!atomic_read(&smp_commenced))
+		/* nothing */ ;
+	return cpu_idle();
+}
+
+/*
+ * Everything has been set up for the secondary
+ * CPUs - they just need to reload everything
+ * from the task structure
+ * This function must not return.
+ */
+void __init initialize_secondary(void)
+{
+	/*
+	 * We don't actually need to load the full TSS,
+	 * basically just the stack pointer and the eip.
+	 */
+
+	asm volatile(
+		"movl %0,%%esp\n\t"
+		"jmp *%1"
+		:
+		:"r" (current->thread.esp),"r" (current->thread.eip));
+}
+
+extern struct {
+	void * esp;
+	unsigned short ss;
+} stack_start;
+
+static int __init fork_by_hand(void)
+{
+	struct pt_regs regs;
+	/*
+	 * don't care about the eip and regs settings since
+	 * we'll never reschedule the forked task.
+	 */
+	return do_fork(CLONE_VM|CLONE_PID, 0, &regs);
+}
+
+static void __init do_boot_cpu(int i)
+{
+	unsigned long cfg;
+	pgd_t maincfg;
+	struct task_struct *idle;
+	unsigned long send_status, accept_status;
+	int timeout, num_starts, j;
+	unsigned long start_eip;
+
+	cpucount++;
+	/*
+	 * We can't use kernel_thread since we must avoid to
+	 * reschedule the child.
+	 */
+	if (fork_by_hand() < 0)
+		panic("failed fork for CPU %d", i);
+
+	/*
+	 * We remove it from the pidhash and the runqueue
+	 * once we got the process:
+	 */
+	idle = init_task.prev_task;
+	if (!idle)
+		panic("No idle process for CPU %d", i);
+
+	idle->processor = i;
+	__cpu_logical_map[cpucount] = i;
+	cpu_number_map[i] = cpucount;
+	idle->has_cpu = 1; /* we schedule the first task manually */
+	idle->thread.eip = (unsigned long) start_secondary;
+
+	del_from_runqueue(idle);
+	unhash_process(idle);
+	init_tasks[cpucount] = idle;
+
+	/* start_eip had better be page-aligned! */
+	start_eip = setup_trampoline();
+
+	/* So we see what's up   */
+	printk("Booting processor %d eip %lx\n", i, start_eip);
+	stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
+
+	/*
+	 * This grunge runs the startup process for
+	 * the targeted processor.
+	 */
+
+	dprintk("Setting warm reset code and vector.\n");
+
+	CMOS_WRITE(0xa, 0xf);
+	local_flush_tlb();
+	dprintk("1.\n");
+	*((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4;
+	dprintk("2.\n");
+	*((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;
+	dprintk("3.\n");
+
+	maincfg=swapper_pg_dir[0];
+	((unsigned long *)swapper_pg_dir)[0]=0x102007;
+
+	/*
+	 * Be paranoid about clearing APIC errors.
+	 */
+
+	if (APIC_INTEGRATED(apic_version[i])) {
+		apic_readaround(APIC_SPIV);
+		apic_write(APIC_ESR, 0);
+		accept_status = (apic_read(APIC_ESR) & 0xEF);
+	}
+
+	/*
+	 * Status is now clean
+	 */
+	send_status = 	0;
+	accept_status = 0;
+
+	/*
+	 * Starting actual IPI sequence...
+	 */
+
+	dprintk("Asserting INIT.\n");
+
+	/*
+	 * Turn INIT on
+	 */
+	cfg = apic_read(APIC_ICR2);
+	cfg &= 0x00FFFFFF;
+
+	/*
+	 * Target chip
+	 */
+	apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(i));
+
+	/*
+	 * Send IPI
+	 */
+	cfg = apic_read(APIC_ICR);
+	cfg &= ~0xCDFFF;
+	cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
+	apic_write(APIC_ICR, cfg);
+
+	udelay(200);
+	dprintk("Deasserting INIT.\n");
+
+	/* Target chip */
+	cfg = apic_read(APIC_ICR2);
+	cfg &= 0x00FFFFFF;
+	apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i));
+
+	/* Send IPI */
+	cfg = apic_read(APIC_ICR);
+	cfg &= ~0xCDFFF;
+	cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_DM_INIT);
+	apic_write(APIC_ICR, cfg);
+
+	/*
+	 * Should we send STARTUP IPIs ?
+	 *
+	 * Determine this based on the APIC version.
+	 * If we don't have an integrated APIC, don't
+	 * send the STARTUP IPIs.
+	 */
+
+	if (APIC_INTEGRATED(apic_version[i]))
+		num_starts = 2;
+	else
+		num_starts = 0;
+
+	/*
+	 * Run STARTUP IPI loop.
+	 */
+
+	for (j = 1; j <= num_starts; j++) {
+		dprintk("Sending STARTUP #%d.\n",j);
+		apic_readaround(APIC_SPIV);
+		apic_write(APIC_ESR, 0);
+		apic_read(APIC_ESR);
+		dprintk("After apic_write.\n");
+
+		/*
+		 * STARTUP IPI
+		 */
+
+		/* Target chip */
+		cfg = apic_read(APIC_ICR2);
+		cfg &= 0x00FFFFFF;
+		apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i));
+
+		/* Boot on the stack */
+		cfg = apic_read(APIC_ICR);
+		cfg &= ~0xCDFFF;
+		cfg |= (APIC_DEST_DM_STARTUP | (start_eip >> 12));
+
+		/* Kick the second */
+		apic_write(APIC_ICR, cfg);
+
+		dprintk("Startup point 1.\n");
+
+		dprintk("Waiting for send to finish...\n");
+		timeout = 0;
+		do {
+			dprintk("+");
+			udelay(100);
+			send_status = apic_read(APIC_ICR) & 0x1000;
+		} while (send_status && (timeout++ < 1000));
+
+		/*
+		 * Give the other CPU some time to accept the IPI.
+		 */
+		udelay(200);
+		accept_status = (apic_read(APIC_ESR) & 0xEF);
+		if (send_status || accept_status)
+			break;
+	}
+	dprintk("After Startup.\n");
+
+	if (send_status)
+		printk("APIC never delivered???\n");
+	if (accept_status)
+		printk("APIC delivery error (%lx).\n", accept_status);
+
+	if (!send_status && !accept_status) {
+		/*
+		 * allow APs to start initializing.
+		 */
+		dprintk("Before Callout %d.\n", i);
+		set_bit(i, &cpu_callout_map);
+		dprintk("After Callout %d.\n", i);
+
+		/*
+		 * Wait 5s total for a response
+		 */
+		for (timeout = 0; timeout < 50000; timeout++) {
+			if (test_bit(i, &cpu_callin_map))
+				break;	/* It has booted */
+			udelay(100);
+		}
+
+		if (test_bit(i, &cpu_callin_map)) {
+			/* number CPUs logically, starting from 1 (BSP is 0) */
+			printk("OK.\n");
+			printk("CPU%d: ", i);
+			print_cpu_info(&cpu_data[i]);
+		} else {
+			if (*((volatile unsigned char *)phys_to_virt(8192))
+					== 0xA5) /* trampoline code not run */
+				printk("Stuck ??\n");
+			else
+				printk("CPU booted but not responding.\n");
+		}
+		dprintk("CPU has booted.\n");
+	} else {
+		__cpu_logical_map[cpucount] = -1;
+		cpu_number_map[i] = -1;
+		cpucount--;
+	}
+
+	swapper_pg_dir[0]=maincfg;
+	local_flush_tlb();
+
+	/* mark "stuck" area as not stuck */
+	*((volatile unsigned long *)phys_to_virt(8192)) = 0;
+}
+
+cycles_t cacheflush_time;
+extern unsigned long cpu_hz;
+
+static void smp_tune_scheduling (void)
+{
+	unsigned long cachesize;
+	/*
+	 * Rough estimation for SMP scheduling, this is the number of
+	 * cycles it takes for a fully memory-limited process to flush
+	 * the SMP-local cache.
+	 *
+	 * (For a P5 this pretty much means we will choose another idle
+	 *  CPU almost always at wakeup time (this is due to the small
+	 *  L1 cache), on PIIs it's around 50-100 usecs, depending on
+	 *  the cache size)
+	 */
+
+	if (!cpu_hz) {
+		/*
+		 * this basically disables processor-affinity
+		 * scheduling on SMP without a TSC.
+		 */
+		cacheflush_time = 0;
+		return;
+	} else {
+		cachesize = boot_cpu_data.x86_cache_size;
+		if (cachesize == -1)
+			cachesize = 8; /* Pentiums */
+
+		cacheflush_time = cpu_hz/1024*cachesize/5000;
+	}
+
+	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
+		(long)cacheflush_time/(cpu_hz/1000000),
+		((long)cacheflush_time*100/(cpu_hz/1000000)) % 100);
+}
+
+/*
+ * Cycle through the processors sending APIC IPIs to boot each.
+ */
+
+extern int prof_multiplier[NR_CPUS];
+extern int prof_old_multiplier[NR_CPUS];
+extern int prof_counter[NR_CPUS];
+
+void __init smp_boot_cpus(void)
+{
+	int i;
+
+#ifdef CONFIG_MTRR
+	/*  Must be done before other processors booted  */
+	mtrr_init_boot_cpu ();
+#endif
+	/*
+	 * Initialize the logical to physical CPU number mapping
+	 * and the per-CPU profiling counter/multiplier
+	 */
+
+	for (i = 0; i < NR_CPUS; i++) {
+		cpu_number_map[i] = -1;
+		prof_counter[i] = 1;
+		prof_old_multiplier[i] = 1;
+		prof_multiplier[i] = 1;
+	}
+
+	/*
+	 * Setup boot CPU information
+	 */
+
+	smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */
+	smp_tune_scheduling();
+	printk("CPU%d: ", boot_cpu_id);
+	print_cpu_info(&cpu_data[boot_cpu_id]);
+
+	/*
+	 * not necessary because the MP table should list the boot
+	 * CPU too, but we do it for the sake of robustness anyway.
+	 * (and for the case when a non-SMP board boots an SMP kernel)
+	 */
+	cpu_present_map |= (1 << hard_smp_processor_id());
+
+	cpu_number_map[boot_cpu_id] = 0;
+
+	init_idle();
+
+	/*
+	 * If we couldnt find an SMP configuration at boot time,
+	 * get out of here now!
+	 */
+
+	if (!smp_found_config) {
+		printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n");
+#ifndef CONFIG_VISWS
+		io_apic_irqs = 0;
+#endif
+		cpu_online_map = cpu_present_map;
+		smp_num_cpus = 1;
+		goto smp_done;
+	}
+
+	/*
+	 * If SMP should be disabled, then really disable it!
+	 */
+
+	if (!max_cpus) {
+		smp_found_config = 0;
+		printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
+	}
+
+#ifdef SMP_DEBUG
+	{
+		int reg;
+
+		/*
+		 * This is to verify that we're looking at
+		 * a real local APIC.  Check these against
+		 * your board if the CPUs aren't getting
+		 * started for no apparent reason.
+		 */
+
+		reg = apic_read(APIC_LVR);
+		dprintk("Getting VERSION: %x\n", reg);
+
+		apic_write(APIC_LVR, 0);
+		reg = apic_read(APIC_LVR);
+		dprintk("Getting VERSION: %x\n", reg);
+
+		/*
+		 * The two version reads above should print the same
+		 * NON-ZERO!!! numbers.  If the second one is zero,
+		 * there is a problem with the APIC write/read
+		 * definitions.
+		 *
+		 * The next two are just to see if we have sane values.
+		 * They're only really relevant if we're in Virtual Wire
+		 * compatibility mode, but most boxes are anymore.
+		 */
+
+
+		reg = apic_read(APIC_LVT0);
+		dprintk("Getting LVT0: %x\n", reg);
+
+		reg = apic_read(APIC_LVT1);
+		dprintk("Getting LVT1: %x\n", reg);
+	}
+#endif
+
+	setup_local_APIC();
+
+	if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id)
+		BUG();
+
+	/*
+	 * Now scan the CPU present map and fire up the other CPUs.
+	 */
+
+	/*
+	 * Add all detected CPUs. (later on we can down individual
+	 * CPUs which will change cpu_online_map but not necessarily
+	 * cpu_present_map. We are pretty much ready for hot-swap CPUs.)
+	 */
+	cpu_online_map = cpu_present_map;
+	mb();
+
+	dprintk("CPU map: %lx\n", cpu_present_map);
+
+	for (i = 0; i < NR_CPUS; i++) {
+		/*
+		 * Don't even attempt to start the boot CPU!
+		 */
+		if (i == boot_cpu_id)
+			continue;
+
+		if ((cpu_online_map & (1 << i))
+		    && (max_cpus < 0 || max_cpus > cpucount+1)) {
+			do_boot_cpu(i);
+		}
+
+		/*
+		 * Make sure we unmap all failed CPUs
+		 */
+		if (cpu_number_map[i] == -1 && (cpu_online_map & (1 << i))) {
+			printk("CPU #%d not responding - cannot use it.\n",i);
+			cpu_online_map &= ~(1 << i);
+		}
+	}
+
+	/*
+	 * Cleanup possible dangling ends...
+	 */
+
+#ifndef CONFIG_VISWS
+	{
+		unsigned long cfg;
+
+		/*
+		 * Install writable page 0 entry to set BIOS data area.
+		 */
+		cfg = pg0[0];
+		/* writeable, present, addr 0 */
+		pg0[0] = _PAGE_RW | _PAGE_PRESENT | 0;
+		local_flush_tlb();
+
+		/*
+		 * Paranoid:  Set warm reset code and vector here back
+		 * to default values.
+		 */
+		CMOS_WRITE(0, 0xf);
+
+		*((volatile long *) phys_to_virt(0x467)) = 0;
+
+		/*
+		 * Restore old page 0 entry.
+		 */
+		pg0[0] = cfg;
+		local_flush_tlb();
+	}
+#endif
+
+	/*
+	 * Allow the user to impress friends.
+	 */
+
+	dprintk("Before bogomips.\n");
+	if (!cpucount) {
+		printk(KERN_ERR "Error: only one processor found.\n");
+		cpu_online_map = (1<<hard_smp_processor_id());
+	} else {
+		unsigned long bogosum = 0;
+		for(i = 0; i < 32; i++)
+			if (cpu_online_map&(1<<i))
+				bogosum+=cpu_data[i].loops_per_sec;
+		printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+			cpucount+1,
+			(bogosum+2500)/500000,
+			((bogosum+2500)/5000)%100);
+		dprintk("Before bogocount - setting activated=1.\n");
+		smp_activated = 1;
+	}
+	smp_num_cpus = cpucount + 1;
+
+	if (smp_b_stepping)
+		printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
+	dprintk("Boot done.\n");
+
+	cache_APIC_registers();
+#ifndef CONFIG_VISWS
+	/*
+	 * Here we can be sure that there is an IO-APIC in the system. Let's
+	 * go and set it up:
+	 */
+	if (!skip_ioapic_setup)
+		setup_IO_APIC();
+#endif
+
+smp_done:
+	/*
+	 * now we know the other CPUs have fired off and we know our
+	 * APIC ID, so we can go init the TSS and stuff:
+	 */
+	cpu_init();
+
+	/*
+	 * Set up all local APIC timers in the system:
+	 */
+	setup_APIC_clocks();
+
+	/*
+	 * Synchronize the TSC with the AP
+	 */
+	if (cpu_has_tsc && cpucount)
+		synchronize_tsc_bp();
+}
+
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.3.19/linux/arch/i386/kernel/time.c	Wed Aug 18 11:27:23 1999
+++ linux/arch/i386/kernel/time.c	Thu Oct  7 10:17:08 1999
@@ -74,7 +74,7 @@
  * Equal to 2^32 * (1 / (clocks per usec) ).
  * Initialized in time_init.
  */
-static unsigned long fast_gettimeoffset_quotient=0;
+unsigned long fast_gettimeoffset_quotient=0;
 
 extern rwlock_t xtime_lock;
 
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.3.19/linux/arch/i386/kernel/traps.c	Fri Sep 10 23:57:27 1999
+++ linux/arch/i386/kernel/traps.c	Thu Oct  7 10:17:08 1999
@@ -58,10 +58,17 @@
  */
 struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };
 
+extern int console_loglevel;
+
+static inline void console_silent(void)
+{
+	console_loglevel = 0;
+}
+
 static inline void console_verbose(void)
 {
-	extern int console_loglevel;
-	console_loglevel = 15;
+	if (console_loglevel)
+		console_loglevel = 15;
 }
 
 #define DO_ERROR(trapnr, signr, str, name, tsk) \
@@ -202,8 +209,6 @@
 	printk("%s: %04lx\n", str, err & 0xffff);
 	show_registers(regs);
 
-spin_lock_irq(&die_lock);
-
 	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
 }
@@ -292,7 +297,11 @@
 {
 	printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
 	printk("You probably have a hardware problem with your RAM chips\n");
-}	
+
+	/* Clear and disable the memory parity error line. */
+	reason = (reason & 0xf) | 4;
+	outb(reason, 0x61);
+}
 
 static void io_check_error(unsigned char reason, struct pt_regs * regs)
 {
@@ -301,8 +310,8 @@
 	printk("NMI: IOCK error (debug interrupt?)\n");
 	show_registers(regs);
 
-	/* Re-enable the IOCK line, wait for a few seconds */
-	reason |= 8;
+	/* Re-enable the IOCK line, wait for a few seconds */
+	reason = (reason & 0xf) | 8;
 	outb(reason, 0x61);
 	i = 2000;
 	while (--i) udelay(1000);
@@ -325,18 +334,107 @@
 	printk("Do you have a strange power saving mode enabled?\n");
 }
 
+atomic_t nmi_counter[NR_CPUS];
+
+#if CONFIG_SMP
+
+int nmi_watchdog = 1;
+
+static int __init setup_nmi_watchdog(char *str)
+{
+        get_option(&str, &nmi_watchdog);
+        return 1;
+}
+
+__setup("nmi_watchdog=", setup_nmi_watchdog);
+
+extern spinlock_t console_lock;
+static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
+
+inline void nmi_watchdog_tick(struct pt_regs * regs)
+{
+	/*
+	 * the best way to detect wether a CPU has a 'hard lockup' problem
+	 * is to check it's local APIC timer IRQ counts. If they are not
+	 * changing then that CPU has some problem.
+	 *
+	 * as these watchdog NMI IRQs are broadcasted to every CPU, here
+	 * we only have to check the current processor.
+	 *
+	 * since NMIs dont listen to _any_ locks, we have to be extremely
+	 * careful not to rely on unsafe variables. The printk might lock
+	 * up though, so we have to break up console_lock first ...
+	 * [when there will be more tty-related locks, break them up
+	 *  here too!]
+	 */
+
+	static unsigned int last_irq_sums [NR_CPUS] = { 0, },
+				alert_counter [NR_CPUS] = { 0, };
+
+	/*
+	 * Since current-> is always on the stack, and we always switch
+	 * the stack NMI-atomically, it's safe to use smp_processor_id().
+	 */
+	int sum, cpu = smp_processor_id();
+
+	sum = apic_timer_irqs[cpu];
+
+	if (last_irq_sums[cpu] == sum) {
+		/*
+		 * Ayiee, looks like this CPU is stuck ...
+		 * wait a few IRQs (5 seconds) before doing the oops ...
+		 */
+		alert_counter[cpu]++;
+		if (alert_counter[cpu] == 5*HZ) {
+			spin_lock(&nmi_print_lock);
+			spin_unlock(&console_lock); // we are in trouble anyway
+			printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu);
+			show_registers(regs);
+			printk("console shuts up ...\n");
+			console_silent();
+			spin_unlock(&nmi_print_lock);
+			do_exit(SIGSEGV);
+		}
+	} else {
+		last_irq_sums[cpu] = sum;
+		alert_counter[cpu] = 0;
+	}
+}
+#endif
+
 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
 {
 	unsigned char reason = inb(0x61);
-	extern atomic_t nmi_counter;
 
-	atomic_inc(&nmi_counter);
+	atomic_inc(nmi_counter+smp_processor_id());
+	if (!(reason & 0xc0)) {
+#if CONFIG_SMP
+		/*
+		 * Ok, so this is none of the documented NMI sources,
+		 * so it must be the NMI watchdog.
+		 */
+		if (nmi_watchdog) {
+			nmi_watchdog_tick(regs);
+			return;
+		} else
+			unknown_nmi_error(reason, regs);
+#else
+		unknown_nmi_error(reason, regs);
+#endif
+		return;
+	}
 	if (reason & 0x80)
 		mem_parity_error(reason, regs);
 	if (reason & 0x40)
 		io_check_error(reason, regs);
-	if (!(reason & 0xc0))
-		unknown_nmi_error(reason, regs);
+	/*
+	 * Reassert NMI in case it became active meanwhile
+	 * as it's edge-triggered.
+	 */
+	outb(0x8f, 0x70);
+	inb(0x71);		/* dummy */
+	outb(0x0f, 0x70);
+	inb(0x71);		/* dummy */
 }
 
 /*
@@ -455,6 +553,7 @@
 asmlinkage void math_state_restore(struct pt_regs regs)
 {
 	__asm__ __volatile__("clts");		/* Allow maths ops (or we recurse) */
+
 	if(current->used_math)
 		__asm__("frstor %0": :"m" (current->thread.i387));
 	else
@@ -489,7 +588,6 @@
 	pmd_t * pmd;
 	pte_t * pte;
 
-return;
 	/*
 	 * Allocate a new page in virtual address space, 
 	 * move the IDT into it and write protect this page.
@@ -658,7 +756,7 @@
 	 */
 	set_fixmap(FIX_APIC_BASE, APIC_PHYS_BASE);
 	printk("Local APIC ID %lx\n", apic_read(APIC_ID));
-	printk("Local APIC Version %lx\n", apic_read(APIC_VERSION));
+	printk("Local APIC Version %lx\n", apic_read(APIC_LVR));
 
 	set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
 	printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV));
@@ -679,7 +777,7 @@
 
 	set_trap_gate(0,&divide_error);
 	set_trap_gate(1,&debug);
-	set_trap_gate(2,&nmi);
+	set_intr_gate(2,&nmi);
 	set_system_gate(3,&int3);	/* int3-5 can be called from all */
 	set_system_gate(4,&overflow);
 	set_system_gate(5,&bounds);
diff -u --recursive --new-file v2.3.19/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.3.19/linux/arch/m68k/config.in	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/config.in	Thu Oct  7 10:17:08 1999
@@ -10,40 +10,31 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
-  bool 'Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
 comment 'Platform dependent setup'
 
 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  
+   bool '  Hades support' CONFIG_HADES
+   if [ "$CONFIG_HADES" = "y" ]; then
+      define_bool CONFIG_PCI y
+   fi  
 fi
 bool 'Macintosh support' CONFIG_MAC
 if [ "$CONFIG_MAC" = "y" ]; then
-  define_bool CONFIG_NUBUS y
-  define_bool CONFIG_M68K_L2_CACHE y
+   define_bool CONFIG_NUBUS y
+   define_bool CONFIG_M68K_L2_CACHE y
 fi
 bool 'Apollo support' CONFIG_APOLLO
 bool 'VME (Motorola and BVM) support' CONFIG_VME
 if [ "$CONFIG_VME" = "y" ]; then
-  bool 'MVME147 support' CONFIG_MVME147
-  bool 'MVME162, 166 and 167 support' CONFIG_MVME16x
-  bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
+   bool '  MVME147 support' CONFIG_MVME147
+   bool '  MVME162, 166 and 167 support' CONFIG_MVME16x
+   bool '  BVME4000 and BVME6000 support' CONFIG_BVME6000
 fi
 bool 'HP9000/300 support' CONFIG_HP300
 if [ "$CONFIG_HP300" = "y" ]; then
-  bool 'DIO bus support' CONFIG_DIO
+   bool '  DIO bus support' CONFIG_DIO
 fi
 bool 'Sun3x support' CONFIG_SUN3X
   
@@ -56,19 +47,19 @@
 bool '68040 support' CONFIG_M68040
 bool '68060 support' CONFIG_M68060
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'Math emulation support' CONFIG_M68KFPU_EMU
-  if [ "$CONFIG_M68KFPU_EMU" = "y" ]; then
-    bool 'Math emulation extra precision' CONFIG_M68KFPU_EMU_EXTRAPREC
-    bool 'Math emulation only kernel' CONFIG_M68KFPU_EMU_ONLY
-  fi
+   bool 'Math emulation support (EXPERIMENTAL)' CONFIG_M68KFPU_EMU
+   if [ "$CONFIG_M68KFPU_EMU" = "y" ]; then
+      bool '  Math emulation extra precision' CONFIG_M68KFPU_EMU_EXTRAPREC
+      bool '  Math emulation only kernel' CONFIG_M68KFPU_EMU_ONLY
+   fi
 fi
 bool 'Advanced configuration options' CONFIG_ADVANCED
 if [ "$CONFIG_ADVANCED" = "y" ]; then
-  bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
-  bool 'Use one physical chunk of memory only' CONFIG_SINGLE_MEMORY_CHUNK
-  if [ "$CONFIG_M68060" = "y" ]; then
-    bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH
-  fi
+   bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
+   bool 'Use one physical chunk of memory only' CONFIG_SINGLE_MEMORY_CHUNK
+   if [ "$CONFIG_M68060" = "y" ]; then
+      bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH
+   fi
 fi
 endmenu
 
@@ -86,55 +77,64 @@
 if [ "$CONFIG_AMIGA" = "y" ]; then
   bool 'Amiga Zorro (AutoConfig) bus support' CONFIG_ZORRO
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'Amiga 1200/600 PCMCIA support' CONFIG_AMIGA_PCMCIA
+     bool 'Amiga 1200/600 PCMCIA support (EXPERIMENTAL)' CONFIG_AMIGA_PCMCIA
   fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
-  bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP
-  bool 'ST-RAM statistics in /proc' CONFIG_STRAM_PROC
+   bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP
+   bool 'ST-RAM statistics in /proc' CONFIG_STRAM_PROC
 fi
 if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
-  bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
+   bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
 else
   if [ "$CONFIG_HP300" = "y" ]; then
-# We have a dedicated heartbeat LED. :-)
-  define_bool CONFIG_HEARTBEAT y
+     # We have a dedicated heartbeat LED. :-)
+     define_bool CONFIG_HEARTBEAT y
   fi
 fi
 bool '/proc/hardware support' CONFIG_PROC_HARDWARE
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Parallel port support (EXPERIMENTAL)' CONFIG_PARPORT
-  if [ "$CONFIG_PARPORT" != "n" ]; then
-    if [ "$CONFIG_AMIGA" != "n" ]; then
-      dep_tristate '   Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
-      if [ "$CONFIG_ZORRO" != "n" ]; then
-        dep_tristate '    Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+   tristate 'Parallel port support (EXPERIMENTAL)' CONFIG_PARPORT
+   if [ "$CONFIG_PARPORT" != "n" ]; then
+      if [ "$CONFIG_AMIGA" != "n" ]; then
+         dep_tristate '   Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+	 if [ "$CONFIG_ZORRO" != "n" ]; then
+            dep_tristate '    Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+	 fi
       fi
-    fi
-    if [ "$CONFIG_Q40" != "n" ]; then
-       tristate '    Q40 Parallel port' CONFIG_PARPORT
-       if [ "$CONFIG_PARPORT" != "n" ]; then
-         define_bool CONFIG_PARPORT_PC y
-       fi
-    fi
-  fi
-  if [ "$CONFIG_ATARI" == "y" ]; then
-    dep_tristate '    Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
-  fi
-  dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
-  if [ "$CONFIG_PRINTER" != "n" ]; then
-    bool '  Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
-  fi
+      if [ "$CONFIG_Q40" != "n" ]; then
+	 tristate '    Q40 Parallel port' CONFIG_PARPORT
+	 if [ "$CONFIG_PARPORT" != "n" ]; then
+	    define_bool CONFIG_PARPORT_PC y
+	 fi
+      fi
+   fi
+   if [ "$CONFIG_ATARI" = "y" ]; then
+      dep_tristate '  Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
+   fi
+   dep_tristate '  Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+   if [ "$CONFIG_PRINTER" != "n" ]; then
+      bool '    Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+   fi
 fi
 
 
 endmenu
 
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+   bool '  Set version information on all symbols for modules' CONFIG_MODVERSIONS
+   bool '  Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
 source drivers/block/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
+   source net/Config.in
 fi
 
 mainmenu_option next_comment
@@ -144,154 +144,154 @@
 
 if [ "$CONFIG_SCSI" != "n" ]; then
 
-comment 'SCSI support type (disk, tape, CD-ROM)'
-
-dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
-dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
-dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
-if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
-  bool '  Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
-fi
-dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
-
-comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
-
-bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
-
-bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
-bool 'SCSI logging facility' CONFIG_SCSI_LOGGING
+   comment 'SCSI support type (disk, tape, CD-ROM)'
 
-mainmenu_option next_comment
-comment 'SCSI low-level drivers'
-
-if [ "$CONFIG_AMIGA" = "y" ]; then
-  dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'A4000T SCSI support' CONFIG_A4000T_SCSI
-  fi
-fi
-if [ "$CONFIG_ZORRO" = "y" ]; then
-  dep_tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI
-  dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI
-  dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI
-  dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI
-  dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI
-  dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI
-  dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'A4091 SCSI support' CONFIG_A4091_SCSI
-    bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
-    bool 'Blizzard PowerUP 603e+ SCSI' CONFIG_BLZ603EPLUS_SCSI
-    dep_tristate 'BSC Oktagon SCSI support' CONFIG_OKTAGON_SCSI $CONFIG_SCSI
-    bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
-#    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
-  fi
-fi
-if [ "$CONFIG_ATARI" = "y" ]; then
-  dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI
-  if [ "$CONFIG_ATARI_SCSI" != "n" ]; then
-    bool '  Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY
-    bool '  Reset SCSI-devices at boottime' CONFIG_ATARI_SCSI_RESET_BOOT
-    if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then
-      bool '  Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL
-    fi
-  fi
-fi
-if [ "$CONFIG_MAC" = "y" ]; then
-  bool 'Macintosh NCR5380 SCSI' CONFIG_MAC_SCSI
-  dep_tristate 'Macintosh NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI
-fi
-#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
-
-if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
-  bool 'WD33C93 SCSI driver for MVME147' CONFIG_MVME147_SCSI
-fi
-
-if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
-  bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI
-fi
+   dep_tristate '  SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
+   dep_tristate '  SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
+   dep_tristate '  SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
+   if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
+      bool '    Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
+   fi
+   dep_tristate '  SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
+
+   comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
+
+   bool '  Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
+
+   bool '  Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
+   bool '  SCSI logging facility' CONFIG_SCSI_LOGGING
+
+   mainmenu_option next_comment
+   comment 'SCSI low-level drivers'
+
+   if [ "$CONFIG_AMIGA" = "y" ]; then
+      dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 bool 'A4000T SCSI support (EXPERIMENTAL)' CONFIG_A4000T_SCSI
+      fi
+   fi
+   if [ "$CONFIG_ZORRO" = "y" ]; then
+      dep_tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI
+      dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI
+      dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI
+      dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI
+      dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI
+      dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI
+      dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 bool 'A4091 SCSI support (EXPERIMENTAL)' CONFIG_A4091_SCSI
+	 bool 'WarpEngine SCSI support (EXPERIMENTAL)' CONFIG_WARPENGINE_SCSI
+	 bool 'Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)' CONFIG_BLZ603EPLUS_SCSI
+	 dep_tristate 'BSC Oktagon SCSI support (EXPERIMENTAL)' CONFIG_OKTAGON_SCSI $CONFIG_SCSI
+	 bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI
+#	 bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI
+      fi
+   fi
+   if [ "$CONFIG_ATARI" = "y" ]; then
+      dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI
+      if [ "$CONFIG_ATARI_SCSI" != "n" ]; then
+	 bool '  Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+	 bool '  Reset SCSI-devices at boottime' CONFIG_ATARI_SCSI_RESET_BOOT
+	 if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then
+	    bool '  Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL
+	 fi
+      fi
+   fi
+   if [ "$CONFIG_MAC" = "y" ]; then
+      bool 'Macintosh NCR5380 SCSI' CONFIG_MAC_SCSI
+      dep_tristate 'Macintosh NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI
+   fi
+#   dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+
+   if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
+      bool 'WD33C93 SCSI driver for MVME147' CONFIG_MVME147_SCSI
+   fi
+
+   if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
+      bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI
+   fi
+
+   if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
+      bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI
+   fi
+
+   if [ "$CONFIG_SUN3X" = "y" ]; then
+      bool 'ESP SCSI driver' CONFIG_SUN3X_ESP
+   fi
 
-if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
-  bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI
-fi
-
-if [ "$CONFIG_SUN3X" = "y" ]; then
-  bool 'ESP SCSI driver' CONFIG_SUN3X_ESP
-fi
-
-endmenu
+   endmenu
 
 fi
 endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
 
-mainmenu_option next_comment
-comment 'Network device support'
+   mainmenu_option next_comment
+   comment 'Network device support'
 
-bool 'Network device support' CONFIG_NETDEVICES
-if [ "$CONFIG_NETDEVICES" = "y" ]; then
-#
-# Network device configuration
-#
-tristate 'Dummy net driver support' CONFIG_DUMMY
-tristate 'SLIP (serial line) support' CONFIG_SLIP
-if [ "$CONFIG_SLIP" != "n" ]; then
-  bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
-  bool ' Keepalive and linefill' CONFIG_SLIP_SMART
-  bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
-fi
-tristate 'PPP (point-to-point) support' CONFIG_PPP
-if [ ! "$CONFIG_PPP" = "n" ]; then
-  comment 'CCP compressors for PPP are only built as modules.'
-fi
-tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
-if [ "$CONFIG_ZORRO" = "y" ]; then
-  tristate 'Ariadne support' CONFIG_ARIADNE
-  tristate 'Ariadne II support' CONFIG_ARIADNE2
-  tristate 'A2065 support' CONFIG_A2065
-  tristate 'Hydra support' CONFIG_HYDRA
-fi
-if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
-  tristate 'PCMCIA NE2000 support' CONFIG_APNE
-fi
-if [ "$CONFIG_APOLLO" = "y" ] ; then
-  tristate 'Apollo 3c505 support' CONFIG_APOLLO_ELPLUS
-fi
-if [ "$CONFIG_MAC" = "y" ]; then
-  bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT
-#  bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
-  bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
-fi
-if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
-  tristate 'MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET
-fi
-if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
-  tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET
-fi
-if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
-  tristate 'BVME6000 Ethernet support' CONFIG_BVME6000_NET
-fi
-if [ "$CONFIG_ATARI" = "y" ]; then
-  tristate 'Atari Lance support' CONFIG_ATARILANCE
-  if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
-    tristate 'BioNet-100 support' CONFIG_ATARI_BIONET
-    tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET
-  fi
-fi
-if [ "$CONFIG_SUN3X" = "y" ]; then
-  bool 'Sun3x Lance support' CONFIG_SUNLANCE
-fi
-if [ "$CONFIG_HP300" = "y" ]; then
-  bool 'HP on-board LANCE support' CONFIG_HPLANCE
-fi
-if [ "$CONFIG_Q40" = "y" ]; then
-  if [ ! "$CONFIG_PARPORT" = "n" ]; then
-    dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
-  fi
-fi
-fi
-endmenu
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      #
+      # Network device configuration
+      #
+      tristate '  Dummy net driver support' CONFIG_DUMMY
+      tristate '  SLIP (serial line) support' CONFIG_SLIP
+      if [ "$CONFIG_SLIP" != "n" ]; then
+	 bool '    CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
+	 bool '    Keepalive and linefill' CONFIG_SLIP_SMART
+	 bool '    Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
+      fi
+      tristate '  PPP (point-to-point) support' CONFIG_PPP
+      if [ ! "$CONFIG_PPP" = "n" ]; then
+	 comment 'CCP compressors for PPP are only built as modules.'
+      fi
+      tristate '  EQL (serial line load balancing) support' CONFIG_EQUALIZER
+      if [ "$CONFIG_ZORRO" = "y" ]; then
+	 tristate '  Ariadne support' CONFIG_ARIADNE
+	 tristate '  Ariadne II support' CONFIG_ARIADNE2
+	 tristate '  A2065 support' CONFIG_A2065
+	 tristate '  Hydra support' CONFIG_HYDRA
+      fi
+      if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
+	 tristate '  PCMCIA NE2000 support' CONFIG_APNE
+      fi
+      if [ "$CONFIG_APOLLO" = "y" ]; then
+	 tristate '  Apollo 3c505 support' CONFIG_APOLLO_ELPLUS
+      fi
+      if [ "$CONFIG_MAC" = "y" ]; then
+	 bool '  Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT
+#	 bool '  Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
+	 bool '  Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
+      fi
+      if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
+	 tristate '  MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET
+      fi
+      if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
+	 tristate '  MVME16x Ethernet support' CONFIG_MVME16x_NET
+      fi
+      if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
+	 tristate '  BVME6000 Ethernet support' CONFIG_BVME6000_NET
+      fi
+      if [ "$CONFIG_ATARI" = "y" ]; then
+	 tristate '  Atari Lance support' CONFIG_ATARILANCE
+	 if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
+	    tristate '  BioNet-100 support' CONFIG_ATARI_BIONET
+	    tristate '  PAMsNet support' CONFIG_ATARI_PAMSNET
+	 fi
+      fi
+      if [ "$CONFIG_SUN3X" = "y" ]; then
+	 bool '  Sun3x Lance support' CONFIG_SUNLANCE
+      fi
+      if [ "$CONFIG_HP300" = "y" ]; then
+	 bool '  HP on-board LANCE support' CONFIG_HPLANCE
+      fi
+      if [ "$CONFIG_Q40" = "y" ]; then
+	 if [ ! "$CONFIG_PARPORT" = "n" ]; then
+	    dep_tristate '  PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
+	 fi
+      fi
+   fi
+   endmenu
 
 fi
 
@@ -303,85 +303,85 @@
 fi
 
 if [ "$CONFIG_SERIAL" = "y" ]; then
-   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
-   bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
+   bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE
+   bool '  Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
 fi
 
 if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
-   bool '   Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
-   bool '   Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
-#   bool '   Autodetect IRQ - do not yet enable !!' CONFIG_SERIAL_DETECT_IRQ
-   bool '   Support special multiport boards' CONFIG_SERIAL_MULTIPORT
-   bool '   Support the Bell Technologies HUB6 card' CONFIG_HUB6
+   bool '    Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
+   bool '    Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
+#   bool '    Autodetect IRQ - do not yet enable !!' CONFIG_SERIAL_DETECT_IRQ
+   bool '    Support special multiport boards' CONFIG_SERIAL_MULTIPORT
+   bool '    Support the Bell Technologies HUB6 card' CONFIG_HUB6
 fi
 
 if [ "$CONFIG_VME" = "n" ]; then
-  define_bool CONFIG_VT y
-  if [ "$CONFIG_VT" = "y" ]; then
-    bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
-  fi
+   define_bool CONFIG_VT y
+   if [ "$CONFIG_VT" = "y" ]; then
+      bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
+   fi
 fi
 
 if [ "$CONFIG_ATARI" = "y" ]; then
-  define_bool CONFIG_NVRAM y
+   define_bool CONFIG_NVRAM y
 fi
 
 if [ "$CONFIG_AMIGA" = "y" ]; then
-  tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
-  if [ "$CONFIG_AMIGAMOUSE" != "n" ]; then
-    define_bool CONFIG_BUSMOUSE y
-  fi
+   tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
+   if [ "$CONFIG_AMIGAMOUSE" != "n" ]; then
+      define_bool CONFIG_BUSMOUSE y
+   fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
-  tristate 'Atari mouse support' CONFIG_ATARIMOUSE
-  if [ "$CONFIG_ATARIMOUSE" != "n" ]; then
-    define_bool CONFIG_BUSMOUSE y
-  fi
+   tristate 'Atari mouse support' CONFIG_ATARIMOUSE
+   if [ "$CONFIG_ATARIMOUSE" != "n" ]; then
+      define_bool CONFIG_BUSMOUSE y
+   fi
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
    bool 'Mac ADB mouse support' CONFIG_ADBMOUSE
-  if [ "$CONFIG_ADBMOUSE" != "n" ]; then
-    define_bool CONFIG_BUSMOUSE y
-  fi
+   if [ "$CONFIG_ADBMOUSE" != "n" ]; then
+      define_bool CONFIG_BUSMOUSE y
+   fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
-  tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER
-  tristate 'Atari SCC serial support' CONFIG_ATARI_SCC
-  if [ "$CONFIG_ATARI_SCC" = "y" -o "$CONFIG_ATARI_SCC" = "m" ]; then
-    bool 'Atari SCC serial DMA support' CONFIG_ATARI_SCC_DMA
-  fi
-  tristate 'Atari MIDI serial support' CONFIG_ATARI_MIDI
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    tristate 'Atari DSP56k support (EXPERIMENTAL)' CONFIG_ATARI_DSP56K
-  fi
+   tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER
+   tristate 'Atari SCC serial support' CONFIG_ATARI_SCC
+   if [ "$CONFIG_ATARI_SCC" = "y" -o "$CONFIG_ATARI_SCC" = "m" ]; then
+      bool '  Atari SCC serial DMA support' CONFIG_ATARI_SCC_DMA
+   fi
+   tristate 'Atari MIDI serial support' CONFIG_ATARI_MIDI
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'Atari DSP56k support (EXPERIMENTAL)' CONFIG_ATARI_DSP56K
+   fi
 fi
 if [ "$CONFIG_AMIGA" = "y" ]; then
-  tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
-  if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
-    tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL
-  fi
+   tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
+   if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
+      tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL
+   fi
 fi
 if [ "$CONFIG_PARPORT" = "n" ]; then
-  if [ "$CONFIG_ZORRO" = "y" ]; then
-    tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
-    dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
-    dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
-    tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
-  fi
+   if [ "$CONFIG_ZORRO" = "y" ]; then
+      tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
+      dep_tristate '  GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
+      dep_tristate '  GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
+      tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+   fi
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
-  bool 'Mac SCC serial support' CONFIG_MAC_SCC
+   bool 'Mac SCC serial support' CONFIG_MAC_SCC
 fi
 if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
-  tristate 'HP DCA serial support' CONFIG_HPDCA
+   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
+   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
@@ -391,43 +391,43 @@
 if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
      "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" -o \
      "$CONFIG_SUN3X" = "y" ]; then
-  if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
-       "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
-       "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
-       "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
-       "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" ]; then
-    bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
-  fi
+   if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
+        "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
+        "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
+        "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
+        "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" ]; then
+      bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
+   fi
 fi
 if [ "$CONFIG_VME" = "y" ]; then
-  define_bool CONFIG_SERIAL_CONSOLE y
-  if [ "$CONFIG_MVME147" = "y" ]; then
-    bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC
-  fi
-  if [ "$CONFIG_MVME16x" = "y" ]; then
-    bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
-    bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
-  fi
-  if [ "$CONFIG_BVME6000" = "y" ]; then
-    bool 'SCC support for BVME6000 serial ports' CONFIG_BVME6000_SCC
-  fi
+   define_bool CONFIG_SERIAL_CONSOLE y
+   if [ "$CONFIG_MVME147" = "y" ]; then
+      bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC
+   fi
+   if [ "$CONFIG_MVME16x" = "y" ]; then
+      bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
+      bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
+   fi
+   if [ "$CONFIG_BVME6000" = "y" ]; then
+      bool 'SCC support for BVME6000 serial ports' CONFIG_BVME6000_SCC
+   fi
 fi
 if [ "$CONFIG_APOLLO" = "y" ]; then
-  bool 'Support for DN serial port (dummy)' CONFIG_SERIAL
-  bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
+   bool 'Support for DN serial port (dummy)' CONFIG_SERIAL
+   bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
 fi 
 bool 'Support for user serial device modules' CONFIG_USERIAL
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
-  bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
-  bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
+   bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
+   bool '  Software Watchdog' CONFIG_SOFT_WATCHDOG
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
-  bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+   bool 'Enhanced Real Time Clock Support' CONFIG_RTC
 fi
 bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
 if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
-  int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+   int '  Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
 fi
 
 endmenu
@@ -437,22 +437,22 @@
 
 tristate 'Sound support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
-  dep_tristate 'Amiga or Atari DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND
+   dep_tristate '  Amiga or Atari DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND
 fi
 endmenu
 
 source fs/Config.in
 
 if [ "$CONFIG_VME" = "n" ]; then
-  mainmenu_option next_comment
-  comment 'Console drivers'
-  if [ "$CONFIG_HP300" = "y" ]; then
-    bool 'Frame buffer support' CONFIG_FB
-  else
-    define_bool CONFIG_FB y
-  fi
-  source drivers/video/Config.in
-  endmenu
+   mainmenu_option next_comment
+   comment 'Console drivers'
+   if [ "$CONFIG_HP300" = "y" ]; then
+      bool 'Frame buffer support' CONFIG_FB
+   else
+      define_bool CONFIG_FB y
+   fi
+   source drivers/video/Config.in
+   endmenu
 fi
 
 mainmenu_option next_comment
diff -u --recursive --new-file v2.3.19/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.3.19/linux/arch/mips/config.in	Thu Aug 26 13:05:34 1999
+++ linux/arch/mips/config.in	Thu Oct  7 10:17:08 1999
@@ -13,9 +13,9 @@
 comment 'Machine selection'
 bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'Support for Algorithmics P4032' CONFIG_ALGOR_P4032
-  bool 'Support for BAGET MIPS series' CONFIG_BAGET_MIPS
-  bool 'Support for DECstations' CONFIG_DECSTATION
+   bool 'Support for Algorithmics P4032 (EXPERIMENTAL)' CONFIG_ALGOR_P4032
+   bool 'Support for BAGET MIPS series (EXPERIMENTAL)' CONFIG_BAGET_MIPS
+   bool 'Support for DECstations (EXPERIMENTAL)' CONFIG_DECSTATION
 fi
 bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000
 bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700
@@ -30,19 +30,19 @@
 unset CONFIG_VIDEO_G364
 
 if [ "$CONFIG_ALGOR_P4032" = "y" ]; then
-	define_bool CONFIG_PCI y
+   define_bool CONFIG_PCI y
 fi
 if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
      "$CONFIG_OLIVETTI_M700" = "y" ]; then
-	define_bool CONFIG_MIPS_JAZZ y
-	define_bool CONFIG_FB y
-	define_bool CONFIG_FB_G364 y	
+   define_bool CONFIG_MIPS_JAZZ y
+   define_bool CONFIG_FB y
+   define_bool CONFIG_FB_G364 y	
 fi
 if [ "$CONFIG_ACER_PICA_61" = "y" ]; then
-	define_bool CONFIG_MIPS_JAZZ y
+   define_bool CONFIG_MIPS_JAZZ y
 fi
 if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
-	define_bool CONFIG_PCI y
+   define_bool CONFIG_PCI y
 fi
 endmenu
 
@@ -64,16 +64,16 @@
 comment 'General setup'
 
 if [ "$CONFIG_DECSTATION" = "y" ]; then
-  define_bool CONFIG_CPU_LITTLE_ENDIAN y
+   define_bool CONFIG_CPU_LITTLE_ENDIAN y
 else
-  bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
+   bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
 fi
 
 define_bool CONFIG_ELF_KERNEL y
 
 if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
-  define_bool CONFIG_BINFMT_IRIX y
-  define_bool CONFIG_FORWARD_KEYBOARD y
+   define_bool CONFIG_BINFMT_IRIX y
+   define_bool CONFIG_FORWARD_KEYBOARD y
 fi
 define_bool CONFIG_BINFMT_AOUT n
 define_bool CONFIG_BINFMT_ELF y
@@ -85,7 +85,7 @@
 bool 'Sysctl support' CONFIG_SYSCTL
 
 if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
-source drivers/parport/Config.in
+   source drivers/parport/Config.in
 fi
 endmenu
 
@@ -93,24 +93,20 @@
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
-  bool 'Kernel module loader' CONFIG_KMOD
-fi
-
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB
+   bool '  Set version information on all symbols for modules' CONFIG_MODVERSIONS
+   bool '  Kernel module loader' CONFIG_KMOD
 fi
 
 endmenu
 
 if [ "$CONFIG_DECSTATION" = "y" ]; then
-	mainmenu_option next_comment
-	comment 'TURBOchannel support'
-		bool 'TURBOchannel support' CONFIG_TC
-#		if [ "$CONFIG_TC" = "y" ]; then
-# 			tristate 'MAGMA Parallel port support' CONFIG_PARPORT
-#		fi
-	endmenu
+   mainmenu_option next_comment
+   comment 'TURBOchannel support'
+   bool 'TURBOchannel support' CONFIG_TC
+#   if [ "$CONFIG_TC" = "y" ]; then
+#      tristate '  MAGMA Parallel port support' CONFIG_PARPORT
+#   fi
+   endmenu
 fi
 
 source drivers/i2o/Config.in
@@ -120,7 +116,7 @@
 source drivers/block/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
+   source net/Config.in
 fi
 
 mainmenu_option next_comment
@@ -129,125 +125,125 @@
 tristate 'SCSI support' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
-	if [ "$CONFIG_SGI" = "y" -o "$CONFIG_DECSTATION" = "y" ]; then
-		comment 'SCSI support type (disk, tape, CDrom)'
+   if [ "$CONFIG_SGI" = "y" -o "$CONFIG_DECSTATION" = "y" ]; then
+      comment '  SCSI support type (disk, tape, CDrom)'
 
-		dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
-		dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
-		dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
-		dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
-
-		comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
-
-		bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
-
-		bool 'Verbose SCSI error reporting' CONFIG_SCSI_CONSTANTS
-
-		#mainmenu_option next_comment
-		comment 'SCSI low-level drivers'
-		if [ "$CONFIG_SGI" = "y" ]; then
-		dep_tristate 'SGI wd93 Scsi Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI
-	else
-			if [ "$CONFIG_TC" = "y" ]; then
-				dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI
-			fi
-			dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI
-		fi
-	else
-		source drivers/scsi/Config.in
-	fi
+      dep_tristate '  SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
+      dep_tristate '  SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
+      dep_tristate '  SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
+      dep_tristate '  SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
+
+      comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
+
+      bool '  Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
+
+      bool '  Verbose SCSI error reporting' CONFIG_SCSI_CONSTANTS
+
+      #mainmenu_option next_comment
+      comment 'SCSI low-level drivers'
+      if [ "$CONFIG_SGI" = "y" ]; then
+	 dep_tristate 'SGI wd93 Scsi Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI
+      else
+	 if [ "$CONFIG_TC" = "y" ]; then
+	    dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI
+	 fi
+	 dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI
+      fi
+   else
+      source drivers/scsi/Config.in
+   fi
 fi
 endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'Network device support'
+   mainmenu_option next_comment
+   comment 'Network device support'
 
-  bool 'Network device support' CONFIG_NETDEVICES
-  if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
-	source drivers/net/Config.in
-    else
-	tristate 'Dummy net driver support' CONFIG_DUMMY
-	tristate 'SLIP (serial line) support' CONFIG_SLIP
-	if [ "$CONFIG_SLIP" != "n" ]; then
-	  bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
-	  bool ' Keepalive and linefill' CONFIG_SLIP_SMART
-	fi
-	tristate 'PPP (point-to-point) support' CONFIG_PPP
-	if [ ! "$CONFIG_PPP" = "n" ]; then
-	  comment 'CCP compressors for PPP are only built as modules.'
-	fi
-        if [ "$CONFIG_SGI" = "y" ]; then
-	bool 'SGI Seeq ethernet controller support' CONFIG_SGISEEQ
-    fi
-	if [ "$CONFIG_DECSTATION" = "y" ]; then
-          bool 'DEC LANCE ethernet controller support' CONFIG_DECLANCE
-        fi
-	if [ "$CONFIG_BAGET_MIPS" = "y" ]; then
-	  tristate 'Baget AMD LANCE support' CONFIG_BAGETLANCE
-	  tristate 'Baget Backplane Shared Memory support' CONFIG_BAGETBSM
-	fi
-    fi
-  fi
-  endmenu
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
+	 source drivers/net/Config.in
+      else
+	 tristate '  Dummy net driver support' CONFIG_DUMMY
+	 tristate '  SLIP (serial line) support' CONFIG_SLIP
+	 if [ "$CONFIG_SLIP" != "n" ]; then
+	    bool '    CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
+	    bool '    Keepalive and linefill' CONFIG_SLIP_SMART
+	 fi
+	 tristate '  PPP (point-to-point) support' CONFIG_PPP
+	 if [ ! "$CONFIG_PPP" = "n" ]; then
+	    comment '    CCP compressors for PPP are only built as modules.'
+	 fi
+         if [ "$CONFIG_SGI" = "y" ]; then
+	 bool '  SGI Seeq ethernet controller support' CONFIG_SGISEEQ
+      fi
+	 if [ "$CONFIG_DECSTATION" = "y" ]; then
+            bool '  DEC LANCE ethernet controller support' CONFIG_DECLANCE
+         fi
+	 if [ "$CONFIG_BAGET_MIPS" = "y" ]; then
+	    tristate '  Baget AMD LANCE support' CONFIG_BAGETLANCE
+	    tristate '  Baget Backplane Shared Memory support' CONFIG_BAGETBSM
+	 fi
+      fi
+   fi
+   endmenu
 fi
 
 if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
-  source drivers/net/hamradio/Config.in
+   source drivers/net/hamradio/Config.in
 
 
-  mainmenu_option next_comment
-  comment 'ISDN subsystem'
+   mainmenu_option next_comment
+   comment 'ISDN subsystem'
 
-  if [ "$CONFIG_NET" != "n" ]; then
-    tristate 'ISDN support' CONFIG_ISDN
-    if [ "$CONFIG_ISDN" != "n" ]; then
-      source drivers/isdn/Config.in
-    fi
-  fi
-  endmenu
+   if [ "$CONFIG_NET" != "n" ]; then
+      tristate 'ISDN support' CONFIG_ISDN
+      if [ "$CONFIG_ISDN" != "n" ]; then
+	 source drivers/isdn/Config.in
+      fi
+   fi
+   endmenu
 
 
-  mainmenu_option next_comment
-  comment comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+   mainmenu_option next_comment
+   comment comment 'Old CD-ROM drivers (not SCSI, not IDE)'
 
-  bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
-  if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-    source drivers/cdrom/Config.in
-  fi
-  endmenu
+   bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
+   if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+      source drivers/cdrom/Config.in
+   fi
+   endmenu
 fi
 
 if [ "$CONFIG_DECSTATION" != "y" ]; then
-  source drivers/char/Config.in
+   source drivers/char/Config.in
 else
-  mainmenu_option next_comment
-  comment 'DECstation Character devices'
+   mainmenu_option next_comment
+   comment 'DECstation Character devices'
 
-  bool 'Virtual terminal' CONFIG_VT
-  if [ "$CONFIG_VT" = "y" ]; then
-    bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
-  fi
-  tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
-  if [ "$CONFIG_SGI" = "y" ]; then
-    bool 'SGI PROM Console Support' CONFIG_SGI_PROM_CONSOLE
-  fi
-  if [ "$CONFIG_SERIAL" = "y" ]; then
-    bool 'DZ11 Serial Support' CONFIG_DZ
-    if [ "$CONFIG_TC" = "y" ]; then
-      bool 'Z85C30 Serial Support' CONFIG_ZS
-    fi
-    bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
-  fi
-  bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
-  if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
-    int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
-  fi
-  bool 'Keyboard Support' CONFIG_KEYBOARD
-  bool 'Mouse Support' CONFIG_MOUSE
-#    bool 'Enhanced Real Time Clock Support' CONFIG_RTC
-  endmenu
+   bool 'Virtual terminal' CONFIG_VT
+   if [ "$CONFIG_VT" = "y" ]; then
+      bool '  Support for console on virtual terminal' CONFIG_VT_CONSOLE
+   fi
+   if [ "$CONFIG_SGI" = "y" ]; then
+      bool 'SGI PROM Console Support' CONFIG_SGI_PROM_CONSOLE
+   fi
+   tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
+   if [ "$CONFIG_SERIAL" = "y" ]; then
+      bool '  DZ11 Serial Support' CONFIG_DZ
+      if [ "$CONFIG_TC" = "y" ]; then
+	 bool '  Z85C30 Serial Support' CONFIG_ZS
+      fi
+      bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE
+   fi
+   bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
+   if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+      int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+   fi
+   bool 'Keyboard Support' CONFIG_KEYBOARD
+   bool 'Mouse Support' CONFIG_MOUSE
+#   bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+   endmenu
 fi
 
 source drivers/usb/Config.in
@@ -255,36 +251,36 @@
 source fs/Config.in
 
 if [ "$CONFIG_VT" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'Console drivers'
-  if [ "$CONFIG_SGI" = "y" ]; then
-    tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE
-    if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then
-      define_bool CONFIG_DUMMY_CONSOLE y
-    fi
-  else
-    if [ "$CONFIG_DECSTATION" != "y" ]; then
-    bool 'VGA text console' CONFIG_VGA_CONSOLE
-    fi
-    bool 'Support for frame buffer devices' CONFIG_FB
-    source drivers/video/Config.in
-  fi
-  endmenu
+   mainmenu_option next_comment
+   comment 'Console drivers'
+   if [ "$CONFIG_SGI" = "y" ]; then
+      tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE
+      if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then
+         define_bool CONFIG_DUMMY_CONSOLE y
+      fi
+   else
+      if [ "$CONFIG_DECSTATION" != "y" ]; then
+	 bool 'VGA text console' CONFIG_VGA_CONSOLE
+      fi
+      bool 'Support for frame buffer devices' CONFIG_FB
+	 source drivers/video/Config.in
+      fi
+   endmenu
 fi
 
 if [ "$CONFIG_DECSTATION" != "y" ]; then
-  mainmenu_option next_comment
-  comment 'Sound'
+   mainmenu_option next_comment
+   comment 'Sound'
 
-  tristate 'Sound card support' CONFIG_SOUND
-  if [ "$CONFIG_SOUND" != "n" ]; then
-  source drivers/sound/Config.in
-  fi
-  endmenu
+   tristate 'Sound card support' CONFIG_SOUND
+   if [ "$CONFIG_SOUND" != "n" ]; then
+      source drivers/sound/Config.in
+   fi
+   endmenu
 fi
 
 if [ "$CONFIG_SGI" = "y" ]; then
-  source drivers/sgi/Config.in
+   source drivers/sgi/Config.in
 fi
 
 mainmenu_option next_comment
@@ -293,10 +289,10 @@
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
 bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
 if [ "$CONFIG_MODULES" = "y" ]; then
-  bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE
+   bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE
 fi
 if [ "$CONFIG_SERIAL" = "y" ]; then
-  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
+   bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
 fi
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
diff -u --recursive --new-file v2.3.19/linux/arch/mips/kernel/pci.c linux/arch/mips/kernel/pci.c
--- v2.3.19/linux/arch/mips/kernel/pci.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/mips/kernel/pci.c	Thu Oct  7 12:23:21 1999
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/types.h>
-#include <asm/pci.h>
 
 #ifdef CONFIG_PCI
 
diff -u --recursive --new-file v2.3.19/linux/arch/mips/sni/pci.c linux/arch/mips/sni/pci.c
--- v2.3.19/linux/arch/mips/sni/pci.c	Fri Jun 25 17:40:13 1999
+++ linux/arch/mips/sni/pci.c	Thu Oct  7 12:23:21 1999
@@ -13,7 +13,6 @@
 #include <linux/pci.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
-#include <asm/pci.h>
 #include <asm/sni.h>
 
 #ifdef CONFIG_PCI
diff -u --recursive --new-file v2.3.19/linux/arch/mips/sni/setup.c linux/arch/mips/sni/setup.c
--- v2.3.19/linux/arch/mips/sni/setup.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/mips/sni/setup.c	Thu Oct  7 12:23:21 1999
@@ -31,7 +31,6 @@
 #include <asm/processor.h>
 #include <asm/reboot.h>
 #include <asm/sni.h>
-#include <asm/pci.h>
 
 /*
  * Initial irq handlers.
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/8xx_io/Config.in linux/arch/ppc/8xx_io/Config.in
--- v2.3.19/linux/arch/ppc/8xx_io/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/8xx_io/Config.in	Thu Oct  7 10:17:08 1999
@@ -0,0 +1,16 @@
+#
+# MPC8xx Communication options
+#
+if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
+  mainmenu_option next_comment
+  comment 'MPC8xx Communication Options'
+  bool 'CPM SCC Ethernet' CONFIG_SCC_ENET
+  if [ "$CONFIG_SCC_ENET" = "y" ]; then
+  bool 'Ethernet on SCC1' CONFIG_SCC1_ENET
+    if [ "$CONFIG_SCC1_ENET" != "y" ]; then
+      bool 'Ethernet on SCC2' CONFIG_SCC2_ENET
+    fi
+  fi
+  bool '860T FEC Ethernet' CONFIG_FEC_ENET
+  endmenu
+fi
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/8xx_io/Makefile linux/arch/ppc/8xx_io/Makefile
--- v2.3.19/linux/arch/ppc/8xx_io/Makefile	Wed Sep 30 10:14:16 1998
+++ linux/arch/ppc/8xx_io/Makefile	Thu Oct  7 10:17:08 1999
@@ -9,11 +9,12 @@
 
 O_TARGET := 8xx_io.a
 O_OBJS	= commproc.o uart.o
-ifdef CONFIG_MBX
-O_OBJS += enet.o
-endif
-ifdef CONFIG_FADS
+
+ifdef CONFIG_FEC_ENET
 O_OBJS += fec.o
+endif
+ifdef CONFIG_SCC_ENET
+O_OBJS += enet.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/8xx_io/commproc.c linux/arch/ppc/8xx_io/commproc.c
--- v2.3.19/linux/arch/ppc/8xx_io/commproc.c	Fri Mar 19 10:50:03 1999
+++ linux/arch/ppc/8xx_io/commproc.c	Thu Oct  7 10:17:08 1999
@@ -30,12 +30,7 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <asm/irq.h>
-#ifdef CONFIG_MBX
-#include <asm/mbx.h>
-#endif
-#ifdef CONFIG_FADS
-#include <asm/fads.h>
-#endif
+#include <asm/mpc8xx.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/8xx_immap.h>
@@ -95,32 +90,36 @@
 	*/
 	dp_alloc_base = CPM_DATAONLY_BASE;
 	dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE;
+
 	/* Set the host page for allocation.
 	*/
 	host_buffer = host_page_addr;	/* Host virtual page address */
 	host_end = host_page_addr + PAGE_SIZE;
-	pte = va_to_pte(&init_task, host_page_addr);
+	pte = find_pte(&init_mm, host_page_addr);
 	pte_val(*pte) |= _PAGE_NO_CACHE;
 	flush_tlb_page(current->mm->mmap, host_buffer);
 
 	/* Tell everyone where the comm processor resides.
 	*/
 	cpmp = (cpm8xx_t *)commproc;
+}
 
+/* This is called during init_IRQ.  We used to do it above, but this
+ * was too early since init_IRQ was not yet called.
+ */
+void
+cpm_interrupt_init(void)
+{
 	/* Initialize the CPM interrupt controller.
 	*/
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr =
 	    (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
-		(((5)/2) << 13) | CICR_HP_MASK;
-	/* I hard coded the CPM interrupt to 5 above
-	 * since the CPM_INTERRUPT define is relative to
-	 * the linux irq structure not what the hardware
-	 * belives. -- Cort
-	 */
+		((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0;
+
 	/* Set our interrupt handler with the core CPU.
 	*/
-	if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0)
+	if (request_8xxirq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0)
 		panic("Could not allocate CPM IRQ!");
 
 	/* Install our own error handler.
@@ -178,6 +177,16 @@
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec);
 }
 
+/* Free a CPM interrupt handler.
+*/
+void
+cpm_free_handler(int vec)
+{
+	cpm_vecs[vec].handler = NULL;
+	cpm_vecs[vec].dev_id = NULL;
+	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+}
+
 /* Allocate some memory from the dual ported ram.  We may want to
  * enforce alignment restrictions, but right now everyone is a good
  * citizen.
@@ -218,7 +227,7 @@
  * The internal baud rate clock is the system clock divided by 16.
  * This assumes the baudrate is 16x oversampled by the uart.
  */
-#define BRG_INT_CLK	(((bd_t *)res)->bi_intfreq * 1000000)
+#define BRG_INT_CLK	(((bd_t *)__res)->bi_intfreq * 1000000)
 #define BRG_UART_CLK	(BRG_INT_CLK/16)
 
 void
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/8xx_io/commproc.h linux/arch/ppc/8xx_io/commproc.h
--- v2.3.19/linux/arch/ppc/8xx_io/commproc.h	Wed Sep 30 10:14:16 1998
+++ linux/arch/ppc/8xx_io/commproc.h	Thu Oct  7 10:17:08 1999
@@ -32,6 +32,7 @@
 #define CPM_CR_INIT_TRX		((ushort)0x0000)
 #define CPM_CR_INIT_RX		((ushort)0x0001)
 #define CPM_CR_INIT_TX		((ushort)0x0002)
+#define CPM_CR_HUNT_MODE	((ushort)0x0003)
 #define CPM_CR_STOP_TX		((ushort)0x0004)
 #define CPM_CR_RESTART_TX	((ushort)0x0006)
 #define CPM_CR_SET_GADDR	((ushort)0x0008)
@@ -78,6 +79,7 @@
 #define BD_SC_READY	((ushort)0x8000)	/* Transmit is ready */
 #define BD_SC_WRAP	((ushort)0x2000)	/* Last buffer descriptor */
 #define BD_SC_INTRPT	((ushort)0x1000)	/* Interrupt on change */
+#define BD_SC_LAST	((ushort)0x0800)	/* Last buffer in frame */
 #define BD_SC_CM	((ushort)0x0200)	/* Continous mode */
 #define BD_SC_ID	((ushort)0x0100)	/* Rec'd too many idles */
 #define BD_SC_P		((ushort)0x0100)	/* xmt preamble */
@@ -90,6 +92,7 @@
 /* Parameter RAM offsets.
 */
 #define PROFF_SCC1	((uint)0x0000)
+#define PROFF_IIC	((uint)0x0080)
 #define PROFF_SCC2	((uint)0x0100)
 #define PROFF_SCC3	((uint)0x0200)
 #define PROFF_SMC1	((uint)0x0280)
@@ -97,6 +100,7 @@
 #define PROFF_SMC2	((uint)0x0380)
 
 /* Define enough so I can at least use the serial port as a UART.
+ * The MBX uses SMC1 as the host serial port.
  */
 typedef struct smc_uart {
 	ushort	smc_rbase;	/* Rx Buffer descriptor base address */
@@ -136,11 +140,54 @@
 #define SMCMR_SM_TRANS	((ushort)0x0030)
 #define SMCMR_SM_MASK	((ushort)0x0030)
 #define SMCMR_PM_EVEN	((ushort)0x0100)	/* Even parity, else odd */
+#define SMCMR_REVD	SMCMR_PM_EVEN
 #define SMCMR_PEN	((ushort)0x0200)	/* Parity enable */
+#define SMCMR_BS	SMCMR_PEN
 #define SMCMR_SL	((ushort)0x0400)	/* Two stops, else one */
 #define SMCR_CLEN_MASK	((ushort)0x7800)	/* Character length */
 #define smcr_mk_clen(C)	(((C) << 11) & SMCR_CLEN_MASK)
 
+/* SMC2 as Centronics parallel printer.  It is half duplex, in that
+ * it can only receive or transmit.  The parameter ram values for
+ * each direction are either unique or properly overlap, so we can
+ * include them in one structure.
+ */
+typedef struct smc_centronics {
+	ushort	scent_rbase;
+	ushort	scent_tbase;
+	u_char	scent_cfcr;
+	u_char	scent_smask;
+	ushort	scent_mrblr;
+	uint	scent_rstate;
+	uint	scent_r_ptr;
+	ushort	scent_rbptr;
+	ushort	scent_r_cnt;
+	uint	scent_rtemp;
+	uint	scent_tstate;
+	uint	scent_t_ptr;
+	ushort	scent_tbptr;
+	ushort	scent_t_cnt;
+	uint	scent_ttemp;
+	ushort	scent_max_sl;
+	ushort	scent_sl_cnt;
+	ushort	scent_character1;
+	ushort	scent_character2;
+	ushort	scent_character3;
+	ushort	scent_character4;
+	ushort	scent_character5;
+	ushort	scent_character6;
+	ushort	scent_character7;
+	ushort	scent_character8;
+	ushort	scent_rccm;
+	ushort	scent_rccr;
+} smc_cent_t;
+
+/* Centronics Status Mask Register.
+*/
+#define SMC_CENT_F	((u_char)0x08)
+#define SMC_CENT_PE	((u_char)0x04)
+#define SMC_CENT_S	((u_char)0x02)
+
 /* SMC Event and Mask register.
 */
 #define	SMCM_TXE	((unsigned char)0x10)
@@ -329,6 +376,7 @@
 	ushort	sen_taddrl;	/* temp address (LSB) */
 } scc_enet_t;
 
+#ifdef CONFIG_MBX
 /* Bits in parallel I/O port registers that have to be set/cleared
  * to configure the pins for SCC1 use.  The TCLK and RCLK seem unique
  * to the MBX860 board.  Any two of the four available clocks could be
@@ -348,6 +396,65 @@
  */
 #define SICR_ENET_MASK	((uint)0x000000ff)
 #define SICR_ENET_CLKRT	((uint)0x0000003d)
+#endif
+
+#ifdef CONFIG_RPXLITE
+/* This ENET stuff is for the MPC850 with ethernet on SCC2.  Some of
+ * this may be unique to the RPX-Lite configuration.
+ * Note TENA is on Port B.
+ */
+#define PA_ENET_RXD	((ushort)0x0004)
+#define PA_ENET_TXD	((ushort)0x0008)
+#define PA_ENET_TCLK	((ushort)0x0200)
+#define PA_ENET_RCLK	((ushort)0x0800)
+#define PB_ENET_TENA	((uint)0x00002000)
+#define PC_ENET_CLSN	((ushort)0x0040)
+#define PC_ENET_RENA	((ushort)0x0080)
+
+#define SICR_ENET_MASK	((uint)0x0000ff00)
+#define SICR_ENET_CLKRT	((uint)0x00003d00)
+#endif
+
+#ifdef CONFIG_BSEIP
+/* This ENET stuff is for the MPC823 with ethernet on SCC2.
+ * This is unique to the BSE ip-Engine board.
+ */
+#define PA_ENET_RXD	((ushort)0x0004)
+#define PA_ENET_TXD	((ushort)0x0008)
+#define PA_ENET_TCLK	((ushort)0x0100)
+#define PA_ENET_RCLK	((ushort)0x0200)
+#define PB_ENET_TENA	((uint)0x00002000)
+#define PC_ENET_CLSN	((ushort)0x0040)
+#define PC_ENET_RENA	((ushort)0x0080)
+
+/* BSE uses port B and C bits for PHY control also.
+*/
+#define PB_BSE_POWERUP	((uint)0x00000004)
+#define PB_BSE_FDXDIS	((uint)0x00008000)
+#define PC_BSE_LOOPBACK	((ushort)0x0800)
+
+#define SICR_ENET_MASK	((uint)0x0000ff00)
+#define SICR_ENET_CLKRT	((uint)0x00002c00)
+#endif
+
+#ifdef CONFIG_RPXCLASSIC
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD	((ushort)0x0001)
+#define PA_ENET_TXD	((ushort)0x0002)
+#define PA_ENET_TCLK	((ushort)0x0200)
+#define PA_ENET_RCLK	((ushort)0x0800)
+#define PB_ENET_TENA	((uint)0x00001000)
+#define PC_ENET_CLSN	((ushort)0x0010)
+#define PC_ENET_RENA	((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK	((uint)0x000000ff)
+#define SICR_ENET_CLKRT	((uint)0x0000003d)
+#endif
 
 /* SCC Event register as used by Ethernet.
 */
@@ -475,6 +582,30 @@
 	uint	st_cpres;	/* Preset CRC */
 	uint	st_cmask;	/* Constant mask for CRC */
 } scc_trans_t;
+
+#define BD_SCC_TX_LAST		((ushort)0x0800)
+
+/* IIC parameter RAM.
+*/
+typedef struct iic {
+	ushort	iic_rbase;	/* Rx Buffer descriptor base address */
+	ushort	iic_tbase;	/* Tx Buffer descriptor base address */
+	u_char	iic_rfcr;	/* Rx function code */
+	u_char	iic_tfcr;	/* Tx function code */
+	ushort	iic_mrblr;	/* Max receive buffer length */
+	uint	iic_rstate;	/* Internal */
+	uint	iic_rdp;	/* Internal */
+	ushort	iic_rbptr;	/* Internal */
+	ushort	iic_rbc;	/* Internal */
+	uint	iic_rxtmp;	/* Internal */
+	uint	iic_tstate;	/* Internal */
+	uint	iic_tdp;	/* Internal */
+	ushort	iic_tbptr;	/* Internal */
+	ushort	iic_tbc;	/* Internal */
+	uint	iic_txtmp;	/* Internal */
+} iic_t;
+
+#define BD_IIC_START		((ushort)0x0400)
 
 /* CPM interrupts.  There are nearly 32 interrupts generated by CPM
  * channels or devices.  All of these are presented to the PPC core
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c
--- v2.3.19/linux/arch/ppc/8xx_io/enet.c	Wed Aug 18 11:39:01 1999
+++ linux/arch/ppc/8xx_io/enet.c	Thu Oct  7 10:17:08 1999
@@ -4,12 +4,13 @@
  *
  * I copied the basic skeleton from the lance driver, because I did not
  * know how to write the Linux driver, but I did know how the LANCE worked.
- * This version of the driver is specific to the MBX implementation,
- * since the board contains control registers external to the processor
- * for the control of the MC68160 SIA/transceiver.  The MPC860 manual
- * describes connections using the internal parallel port I/O.
  *
- * The MBX860 uses the CPM SCC1 serial port for the Ethernet interface.
+ * This version of the driver is somewhat selectable for the different
+ * processor/board combinations.  It works for the boards I know about
+ * now, and should be easily modified to include others.  Some of the
+ * configuration information is contained in "commproc.h" and the
+ * remainder is here.
+ *
  * Buffer descriptors are kept in the CPM dual port RAM, and the frame
  * buffers are in the host memory.
  *
@@ -21,7 +22,6 @@
  * small packets.
  *
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -39,7 +39,7 @@
 
 #include <asm/8xx_immap.h>
 #include <asm/pgtable.h>
-#include <asm/fads.h>
+#include <asm/mpc8xx.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include "commproc.h"
@@ -164,16 +164,17 @@
 */
 /*static	ushort	my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };*/
 
-/* Right now, only the boards with an 860 use SCC1 for the Ethernet.
- * All others use SCC2.  We may need to make this board specific someday.
+/* Typically, 860(T) boards use SCC1 for Ethernet, and other 8xx boards
+ * use SCC2.  This is easily extended if necessary.
  */
-#ifndef CONFIG_MPC860
-/*static	ushort	my_enet_addr[] = { 0x2700, 0x00ec, 0x1000 };*/
+#ifdef CONFIG_SCC2_ENET
 #define CPM_CR_ENET	CPM_CR_CH_SCC2
 #define PROFF_ENET	PROFF_SCC2
 #define SCC_ENET	1		/* Index, not number! */
 #define CPMVEC_ENET	CPMVEC_SCC2
-#else
+#endif
+
+#ifdef CONFIG_SCC1_ENET
 #define CPM_CR_ENET CPM_CR_CH_SCC1
 #define PROFF_ENET	PROFF_SCC1
 #define SCC_ENET	0
@@ -326,7 +327,7 @@
 static void
 cpm_enet_interrupt(void *dev_id)
 {
-	struct net_device *dev = dev_id;
+	struct	net_device *dev = dev_id;
 	volatile struct	cpm_enet_private *cep;
 	volatile cbd_t	*bdp;
 	ushort	int_events;
@@ -357,43 +358,10 @@
 	 * I don't know if "normally" implies TXB is set when the buffer
 	 * descriptor is closed.....trial and error :-).
 	 */
-#if 0
-	if (int_events & SCCE_ENET_TXE) {
-
-		/* Transmission errors.
-		*/
-		bdp = cep->dirty_tx;
-#ifndef final_version
-		printk("CPM ENET xmit error %x\n", bdp->cbd_sc);
-		if (bdp->cbd_sc & BD_ENET_TX_READY)
-			printk("HEY! Enet xmit interrupt and TX_READY.\n");
-#endif
-		if (bdp->cbd_sc & BD_ENET_TX_HB)	/* No heartbeat */
-			cep->stats.tx_heartbeat_errors++;
-		if (bdp->cbd_sc & BD_ENET_TX_LC)	/* Late collision */
-			cep->stats.tx_window_errors++;
-		if (bdp->cbd_sc & BD_ENET_TX_RL)	/* Retrans limit */
-			cep->stats.tx_aborted_errors++;
-		if (bdp->cbd_sc & BD_ENET_TX_UN)	/* Underrun */
-			cep->stats.tx_fifo_errors++;
-		if (bdp->cbd_sc & BD_ENET_TX_CSL)	/* Carrier lost */
-			cep->stats.tx_carrier_errors++;
-
-		cep->stats.tx_errors++;
-
-		/* No heartbeat or Lost carrier are not really bad errors.
-		 * The others require a restart transmit command.
-		 */
-		if (bdp->cbd_sc &
-		    (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN))
-			must_restart = 1;
-	}
-#endif
 
 	/* Transmit OK, or non-fatal error.  Update the buffer descriptors.
 	*/
 	if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) {
-#if 1
 	    bdp = cep->dirty_tx;
 	    while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) {
 		if ((bdp==cep->cur_tx) && (cep->tx_full == 0))
@@ -421,13 +389,7 @@
 		}
 
 		cep->stats.tx_packets++;
-#else
-		bdp = cep->dirty_tx;
-#if 1
-		if (bdp->cbd_sc & BD_ENET_TX_READY)
-			printk("HEY! Enet xmit interrupt and TX_READY.\n");
-#endif
-#endif
+
 		/* Deferred means some collisions occurred during transmit,
 		 * but we eventually sent the packet OK.
 		 */
@@ -697,9 +659,7 @@
  * transmit and receive to make sure we don't catch the CPM with some
  * inconsistent control information.
  */
-/* until this gets cleared up -- Cort */
-int __init cpm_enet_init() { m8xx_enet_init(); }
-int __init m8xx_enet_init(void)
+int __init cpm_enet_init(void)
 {
 	struct net_device *dev;
 	struct cpm_enet_private *cep;
@@ -718,7 +678,7 @@
 
 	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */
 
-	bd = (bd_t *)res;
+	bd = (bd_t *)__res;
 
 	/* Allocate some private information.
 	*/
@@ -830,8 +790,8 @@
 	ep->sen_maxflr = PKT_MAXBUF_SIZE;   /* maximum frame length register */
 	ep->sen_minflr = PKT_MINBUF_SIZE;  /* minimum frame length register */
 
-	ep->sen_maxd1 = PKT_MAXBUF_SIZE;	/* maximum DMA1 length */
-	ep->sen_maxd2 = PKT_MAXBUF_SIZE;	/* maximum DMA2 length */
+	ep->sen_maxd1 = PKT_MAXBLR_SIZE;	/* maximum DMA1 length */
+	ep->sen_maxd2 = PKT_MAXBLR_SIZE;	/* maximum DMA2 length */
 
 	/* Clear hash tables.
 	*/
@@ -849,6 +809,9 @@
 	 * If we performed a MBX diskless boot, the Ethernet controller
 	 * has been initialized and we copy the address out into our
 	 * own structure.
+	 *
+	 * All other types of boards supply the address in the board
+	 * information structure, so we copy that into the controller.
 	 */
 	eap = (unsigned char *)&(ep->sen_paddrh);
 #ifndef CONFIG_MBX
@@ -891,7 +854,7 @@
 
 		/* Make it uncached.
 		*/
-		pte = va_to_pte(&init_task, mem_addr);
+		pte = find_pte(&init_mm, mem_addr);
 		pte_val(*pte) |= _PAGE_NO_CACHE;
 		flush_tlb_page(current->mm->mmap, mem_addr);
 
@@ -983,7 +946,9 @@
 
 	dev->base_addr = (unsigned long)ep;
 	dev->priv = cep;
+#if 0
 	dev->name = "CPM_ENET";
+#endif
 
 	/* The CPM Ethernet specific entries in the device structure. */
 	dev->open = cpm_enet_open;
@@ -996,7 +961,7 @@
 	*/
 	sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 
-	printk("CPM ENET Version 0.1, ");
+	printk("%s: CPM ENET Version 0.2, ", dev->name);
 	for (i=0; i<5; i++)
 		printk("%02x:", dev->dev_addr[i]);
 	printk("%02x\n", dev->dev_addr[5]);
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c
--- v2.3.19/linux/arch/ppc/8xx_io/fec.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/8xx_io/fec.c	Thu Oct  7 10:17:08 1999
@@ -33,7 +33,7 @@
 
 #include <asm/8xx_immap.h>
 #include <asm/pgtable.h>
-#include <asm/fads.h>
+#include <asm/mpc8xx.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
@@ -123,7 +123,7 @@
  */
 typedef struct mii_list {
 	uint	mii_regval;
-	void	(*mii_func)(uint val);
+	void	(*mii_func)(int val);
 	struct	mii_list *mii_next;
 } mii_list_t;
 
@@ -244,7 +244,7 @@
 	/* Push the data cache so the CPM does not get stale memory
 	 * data.
 	 */
-	/*flush_dcache_range(skb->data, skb->data + skb->len);*/
+	flush_dcache_range(skb->data, skb->data + skb->len);
 
 	/* Send it on its way.  Tell CPM its ready, interrupt when done,
 	 * its the last BD of the frame, and to put the CRC on the end.
@@ -282,7 +282,7 @@
 static	void
 fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
 {
-	struct net_device *dev = dev_id;
+	struct	net_device *dev = dev_id;
 	struct	fec_enet_private *fep;
 	volatile cbd_t	*bdp;
 	volatile fec_t	*ep;
@@ -600,6 +600,9 @@
 		else
 			printk(", Half-Duplex\n");
 	}
+	if (((mii_reg >> 18) & 0x1f) == 0x1f) {
+		printk("fec: %x\n", mii_reg);
+	}
 }
 
 static	void
@@ -609,6 +612,7 @@
 	/* Read status registers to clear any pending interrupt.
 	*/
 	mii_queue(mk_mii_read(1), mii_status);
+#ifndef CONFIG_RPXCLASSIC
 	mii_queue(mk_mii_read(18), mii_status);
 
 	/* Read extended chip status register.
@@ -616,8 +620,23 @@
 	mii_queue(mk_mii_read(0x14), mii_status);
 
 	/* Enable Link status change interrupts.
+	*/
 	mii_queue(mk_mii_write(0x11, 0x0002), NULL);
+
+#ifdef CONFIG_FADS
+	/* FADS uses the TRSTE in the BCSR, which is kind of weird.
+	 * This really controls the startup default configuration.
+	 * Changing the state of TRSTE once powered up doesn't do
+	 * anything, you have to whack the control register.
+	 * This of course screws up any autoconfig that was done.......
+	 */
+	mii_queue(mk_mii_write(0, 0x1000), NULL);
+#endif
+#else
+	/* Experimenting with the QS6612 PHY....not done yet.
 	*/
+	mii_queue(mk_mii_read(31), mii_status);
+#endif
 }
 
 /* This supports the mii_link interrupt below.
@@ -676,7 +695,7 @@
 static	void
 mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
 {
-	struct net_device *dev = dev_id;
+	struct	net_device *dev = dev_id;
 	struct	fec_enet_private *fep;
 	volatile fec_t	*ep;
 
@@ -691,8 +710,19 @@
 	 * as part of the "normal" processing.
 	 */
 	mii_queue(mk_mii_read(1), mii_relink);
+#ifndef CONFIG_RPXCLASSIC
+	
+	/* Unique to LevelOne PHY.
+	*/
 	mii_queue(mk_mii_read(18), mii_relink);
 	mii_queue(mk_mii_read(20), mii_relink);
+#else
+
+	/* Unique to QS6612 PHY.
+	*/
+	mii_queue(mk_mii_read(6), mii_relink);
+	mii_queue(mk_mii_read(31), mii_relink);
+#endif
 }
 
 static int
@@ -788,9 +818,9 @@
 	}
 }
 
-/* Initialize the FECC Ethernet on 860T.
+/* Initialize the FEC Ethernet on 860T.
  */
-int __init m8xx_enet_init(void)
+int __init fec_enet_init(void)
 {
 	struct net_device *dev;
 	struct fec_enet_private *fep;
@@ -802,7 +832,10 @@
 	cbd_t		*cbd_base;
 	volatile	immap_t	*immap;
 	volatile	fec_t	*fecp;
-	unsigned char	rtc_save_cfg, rtc_val;
+	unsigned char	*iap;
+	bd_t		*bd;
+
+	bd = (bd_t *)__res;
 
 	immap = (immap_t *)IMAP_ADDR;	/* pointer to internal registers */
 
@@ -833,15 +866,27 @@
 
 	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
 
+	/* Right now, all of the boards supply the ethernet address in
+	 * the board descriptor.  If someone doesn't we can just use
+	 * the hard coded address in this driver for testing (this is
+	 * a Motorola address for a board I have, so it is unlikely to
+	 * be used elsewhere).
+	 */
+	eap = (unsigned char *)&my_enet_addr[0];
+#if 1
+	iap = bd->bi_enetaddr;
+	for (i=0; i<6; i++)
+		dev->dev_addr[i] = *eap++ = *iap++;
+#else
+	for (i=0; i<6; i++)
+		dev->dev_addr[i] = *eap++;
+#endif
+
 	/* Set station address.
 	*/
 	fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1];
 	fecp->fec_addr_high = my_enet_addr[2];
 
-	eap = (unsigned char *)&my_enet_addr[0];
-	for (i=0; i<6; i++)
-		dev->dev_addr[i] = *eap++;
-
 	/* Reset all multicast.
 	*/
 	fecp->fec_hash_table_high = 0;
@@ -855,8 +900,8 @@
 	/* Allocate memory for buffer descriptors.
 	*/
 	if (((RX_RING_SIZE + TX_RING_SIZE) * sizeof(cbd_t)) > PAGE_SIZE) {
-		printk("FECC init error.  Need more space.\n");
-		printk("FECC initialization failed.\n");
+		printk("FEC init error.  Need more space.\n");
+		printk("FEC initialization failed.\n");
 		return 1;
 	}
 	mem_addr = __get_free_page(GFP_KERNEL);
@@ -864,7 +909,7 @@
 
 	/* Make it uncached.
 	*/
-	pte = va_to_pte(&init_task, (int)mem_addr);
+	pte = find_pte(&init_mm, (int)mem_addr);
 	pte_val(*pte) |= _PAGE_NO_CACHE;
 	flush_tlb_page(current->mm->mmap, mem_addr);
 
@@ -891,7 +936,7 @@
 
 		/* Make it uncached.
 		*/
-		pte = va_to_pte(&init_task, mem_addr);
+		pte = find_pte(&init_mm, mem_addr);
 		pte_val(*pte) |= _PAGE_NO_CACHE;
 		flush_tlb_page(current->mm->mmap, mem_addr);
 
@@ -948,9 +993,9 @@
 	/* Install our interrupt handlers.  The 860T FADS board uses
 	 * IRQ2 for the MII interrupt.
 	 */
-	if (request_irq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
+	if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
 		panic("Could not allocate FEC IRQ!");
-	if (request_irq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0)
+	if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0)
 		panic("Could not allocate MII IRQ!");
 
 	dev->base_addr = (unsigned long)fecp;
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c
--- v2.3.19/linux/arch/ppc/8xx_io/uart.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/8xx_io/uart.c	Thu Oct  7 10:17:08 1999
@@ -38,13 +38,7 @@
 #include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <asm/8xx_immap.h>
-
-#ifdef CONFIG_MBX
-#include <asm/mbx.h>
-#endif
-#ifdef CONFIG_FADS
-#include <asm/fads.h>
-#endif
+#include <asm/mpc8xx.h>
 #include "commproc.h"
 
 #ifdef CONFIG_SERIAL_CONSOLE
@@ -101,18 +95,40 @@
  * The SMCs do not support any modem control signals.
  */
 #define smc_scc_num	hub6
-#define SCC_NUM_BASE	2
 
-/* The index into the CPM registers for the first SCC in the table.
+/* SMC2 is sometimes used for low performance TDM interfaces.  Define
+ * this as 1 if you want SMC2 as a serial port UART managed by this driver.
+ * Define this as 0 if you wish to use SMC2 for something else.
+ */
+#define USE_SMC2 1
+
+/* Define SCC to ttySx mapping.
 */
-#define SCC_IDX_BASE	1
+#define SCC_NUM_BASE	(USE_SMC2 + 1)	/* SCC base tty "number" */
 
+/* Define which SCC is the first one to use for a serial port.  These
+ * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
+ * for Ethernet, and the first available SCC for serial UART is SCC2.
+ * NOTE:  IF YOU CHANGE THIS, you have to change the PROFF_xxx and
+ * interrupt vectors in the table below to match.
+ */
+#define SCC_IDX_BASE	1	/* table index */
+
+/* Processors other than the 860 only get SMCs configured by default.
+ * Either they don't have SCCs or they are allocated somewhere else.
+ * Of course, there are now 860s without some SCCs, so we will need to
+ * address that someday.
+ */
 static struct serial_state rs_table[] = {
 	/* UART CLK   PORT          IRQ      FLAGS  NUM   */
 	{ 0,     0, PROFF_SMC1, CPMVEC_SMC1,   0,    0 },    /* SMC1 ttyS0 */
-	{ 0,     0, PROFF_SMC2, CPMVEC_SMC2,   0,    1 },    /* SMC1 ttyS0 */
-	{ 0,     0, PROFF_SCC2, CPMVEC_SCC2,   0,    2 },    /* SCC2 ttyS2 */
-	{ 0,     0, PROFF_SCC3, CPMVEC_SCC3,   0,    3 },    /* SCC3 ttyS3 */
+#if USE_SMC2
+	{ 0,     0, PROFF_SMC2, CPMVEC_SMC2,   0,    1 },    /* SMC2 ttyS1 */
+#endif
+#if defined(CONFIG_MPC860) || defined(CONFIG_MPC860T)
+	{ 0,     0, PROFF_SCC2, CPMVEC_SCC2,   0, SCC_NUM_BASE},    /* SCC2 ttyS2 */
+	{ 0,     0, PROFF_SCC3, CPMVEC_SCC3,   0, SCC_NUM_BASE + 1},    /* SCC3 ttyS3 */
+#endif
 };
 
 #define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
@@ -820,15 +836,10 @@
 
 	/* Determine divisor based on baud rate */
 	i = cflag & CBAUD;
-	if (i & CBAUDEX) {
-		i &= ~CBAUDEX;
-		if (i < 1 || i > 4) 
-			info->tty->termios->c_cflag &= ~CBAUDEX;
-		else
-			i += 15;
-	}
-
-	baud_rate = baud_table[i];
+	if (i >= (sizeof(baud_table)/sizeof(int)))
+		baud_rate = 9600;
+	else
+		baud_rate = baud_table[i];
 
 	info->timeout = (TX_BUF_SIZE*HZ*bits);
 	info->timeout += HZ/50;		/* Add .02 seconds of slop */
@@ -1692,7 +1703,7 @@
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
-		if (timeout && time_after(jiffies, orig_jiffies + timeout))
+		if (timeout && ((orig_jiffies + timeout) < jiffies))
 			break;
 		bdp = info->tx_cur;
 	} while (bdp->cbd_sc & BD_SC_READY);
@@ -2251,6 +2262,13 @@
 
 #endif
 
+/* This will be used for all boards when the MBX board information
+ * is modified to include a default baud rate.
+ */
+#ifndef CONFIG_MBX
+static	int	baud_idx;
+#endif
+
 /*
  * The serial driver boot-time initialization code!
  */
@@ -2291,7 +2309,11 @@
 	serial_driver.subtype = SERIAL_TYPE_NORMAL;
 	serial_driver.init_termios = tty_std_termios;
 	serial_driver.init_termios.c_cflag =
+#ifndef CONFIG_MBX
+		baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
+#else
 		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+#endif
 	serial_driver.flags = TTY_DRIVER_REAL_RAW;
 	serial_driver.refcount = &serial_refcount;
 	serial_driver.table = serial_table;
@@ -2337,12 +2359,21 @@
 
 	/* Configure SMCs Tx/Rx instead of port B parallel I/O.
 	*/
+#if USE_SMC2
 	cp->cp_pbpar |= 0x00000cc0;
 	cp->cp_pbdir &= ~0x00000cc0;
 	cp->cp_pbodr &= ~0x00000cc0;
+#else
+	/* This will only enable SMC1 if you want SMC2 for something else.
+	*/
+	cp->cp_pbpar |= 0x000000c0;
+	cp->cp_pbdir &= ~0x000000c0;
+	cp->cp_pbodr &= ~0x000000c0;
+#endif
 
 	/* Configure SCC2 and SCC3 instead of port A parallel I/O.
 	 */
+#if defined(CONFIG_MPC860) || defined(CONFIG_MPC860T)
 #ifndef CONFIG_MBX
 	/* The "standard" configuration through the 860.
 	*/
@@ -2366,15 +2397,16 @@
 	immap->im_ioport.iop_pcdir |= 0x03c6;
 	immap->im_ioport.iop_pcpar &= ~0x03c6;
 
-	/* Wire BRG1 to SMC1 and BRG2 to SMC2.
-	*/
-	cp->cp_simode = 0x10000000;
-
 	/* Connect SCC2 and SCC3 to NMSI.  Connect BRG3 to SCC2 and
 	 * BRG4 to SCC3.
 	 */
 	cp->cp_sicr &= ~0x00ffff00;
 	cp->cp_sicr |= 0x001b1200;
+#endif
+
+	/* Wire BRG1 to SMC1 and BRG2 to SMC2.
+	*/
+	cp->cp_simode = 0x10000000;
 
 	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
 		state->magic = SSTATE_MAGIC;
@@ -2580,7 +2612,12 @@
 
 			/* Set up the baud rate generator.
 			*/
+#ifndef CONFIG_MBX
+			m8xx_cpm_setbrg(state->smc_scc_num,
+							baud_table[baud_idx]);
+#else
 			m8xx_cpm_setbrg(state->smc_scc_num, 9600);
+#endif
 
 			/* If the port is the console, enable Rx and Tx.
 			*/
@@ -2599,12 +2636,26 @@
 static int __init serial_console_setup(struct console *co, char *options)
 {
 	struct		serial_state *ser;
-	uint		mem_addr, dp_addr;
+	uint		mem_addr, dp_addr, bidx;
 	volatile	cbd_t		*bdp;
 	volatile	cpm8xx_t	*cp;
 	volatile	smc_t		*sp;
 	volatile	smc_uart_t	*up;
+
+#ifndef CONFIG_MBX
+	bd_t				*bd;
+
+	bd = (bd_t *)__res;
+
+	for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
+		if (bd->bi_baudrate == baud_table[bidx])
+			break;
+
+	co->cflag = CREAD|CLOCAL|bidx|CS8;
+	baud_idx = bidx;
+#else
 	co->cflag = CREAD|CLOCAL|B9600|CS8;
+#endif
 
 	ser = rs_table + co->index;
 
@@ -2670,7 +2721,11 @@
 
 	/* Set up the baud rate generator.
 	*/
+#ifndef CONFIG_MBX
+	m8xx_cpm_setbrg(ser->smc_scc_num, bd->bi_baudrate);
+#else
 	m8xx_cpm_setbrg(ser->smc_scc_num, 9600);
+#endif
 
 	/* And finally, enable Rx and Tx.
 	*/
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.3.19/linux/arch/ppc/Makefile	Fri Sep 10 23:57:27 1999
+++ linux/arch/ppc/Makefile	Thu Oct  7 10:17:08 1999
@@ -27,7 +27,7 @@
 CPP		= $(CC) -E $(CFLAGS)
 
 ifdef CONFIG_8xx
-CFLAGS := $(CFLAGS) -mcpu=860
+CFLAGS := $(CFLAGS) -mcpu=860 -I../8xx_io
 endif
 
 ifdef CONFIG_PPC64
@@ -45,7 +45,7 @@
 ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES)
 CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
 
-ifdef CONFIG_8xx
+ifdef CONFIG_MATH_EMULATION
 SUBDIRS += arch/ppc/math-emu
 ARCHIVES += arch/ppc/math-emu/math-emu.o
 CORE_FILES += arch/ppc/math-emu/math-emu.o
@@ -77,7 +77,7 @@
 
 BOOT_TARGETS = zImage znetboot.initrd zImage.initrd
 
-ifdef CONFIG_MBX
+ifdef CONFIG_8xx
 $(BOOT_TARGETS): $(CHECKS) vmlinux
 	@$(MAKECOFFBOOT) $@
 	@$(MAKEMBXBOOT) $@
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/amiga/Makefile linux/arch/ppc/amiga/Makefile
--- v2.3.19/linux/arch/ppc/amiga/Makefile	Tue Aug  4 16:06:36 1998
+++ linux/arch/ppc/amiga/Makefile	Thu Oct  7 10:17:08 1999
@@ -12,4 +12,8 @@
             bootinfo.o amisound.o chipram.o ints.o
 OX_OBJS  := amiga_ksyms.o
 
+ifdef CONFIG_AMIGA_PCMCIA
+O_OBJS := $(O_OBJS) pcmcia.o
+endif
+
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c
--- v2.3.19/linux/arch/ppc/amiga/amiints.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/amiga/amiints.c	Thu Oct  7 10:17:08 1999
@@ -1,7 +1,3 @@
-/* Rename a few functions. */
-#define amiga_request_irq request_irq
-#define amiga_free_irq free_irq
-
 /*
  * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code
  *
@@ -23,6 +19,20 @@
  *                           called again.
  *           The whole interrupt handling for CIAs is moved to cia.c
  *           /Roman Zippel
+ *
+ * 07/08/99: rewamp of the interrupt handling - we now have two types of
+ *           interrupts, normal and fast handlers, fast handlers being
+ *           marked with SA_INTERRUPT and runs with all other interrupts
+ *           disabled. Normal interrupts disable their own source but
+ *           run with all other interrupt sources enabled.
+ *           PORTS and EXTER interrupts are always shared even if the
+ *           drivers do not explicitly mark this when calling
+ *           request_irq which they really should do.
+ *           This is similar to the way interrupts are handled on all
+ *           other architectures and makes a ton of sense besides
+ *           having the advantage of making it easier to share
+ *           drivers.
+ *           /Jes
  */
 
 #include <linux/config.h>
@@ -90,7 +100,7 @@
 		} else {
 			ami_irq_list[i] = new_irq_node();
 			ami_irq_list[i]->handler = ami_badint;
-			ami_irq_list[i]->flags   = IRQ_FLG_STD;
+			ami_irq_list[i]->flags   = 0;
 			ami_irq_list[i]->dev_id  = NULL;
 			ami_irq_list[i]->devname = NULL;
 			ami_irq_list[i]->next    = NULL;
@@ -108,7 +118,7 @@
 	custom.intreq = 0x7fff;
 
 #ifdef CONFIG_APUS
-	/* Clear any inter-CPU interrupt requests. Circumvents bug in
+	/* Clear any inter-CPU interupt requests. Circumvents bug in
            Blizzard IPL emulation HW (or so it appears). */
 	APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK);
 
@@ -124,7 +134,7 @@
 	cia_init_IRQ(&ciab_base);
 }
 
-static inline void amiga_insert_irq(irq_node_t **list, irq_node_t *node)
+static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node)
 {
 	unsigned long flags;
 	irq_node_t *cur;
@@ -138,19 +148,18 @@
 
 	cur = *list;
 
-	if (node->flags & IRQ_FLG_FAST) {
-		node->flags &= ~IRQ_FLG_SLOW;
-		while (cur && cur->flags & IRQ_FLG_FAST) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	} else if (node->flags & IRQ_FLG_SLOW) {
-		while (cur) {
+	if (node->flags & SA_INTERRUPT) {
+		if (node->flags & SA_SHIRQ)
+			return -EBUSY;
+		/*
+		 * There should never be more than one
+		 */
+		while (cur && cur->flags & SA_INTERRUPT) {
 			list = &cur->next;
 			cur = cur->next;
 		}
 	} else {
-		while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
+		while (cur) {
 			list = &cur->next;
 			cur = cur->next;
 		}
@@ -160,6 +169,7 @@
 	*list = node;
 
 	restore_flags(flags);
+	return 0;
 }
 
 static inline void amiga_delete_irq(irq_node_t **list, void *dev_id)
@@ -189,13 +199,16 @@
  *                     If the addition was successful, it returns 0.
  */
 
-int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+int amiga_request_irq(unsigned int irq,
+		      void (*handler)(int, void *, struct pt_regs *),
                       unsigned long flags, const char *devname, void *dev_id)
 {
 	irq_node_t *node;
+	int error = 0;
 
 	if (irq >= AMI_IRQS) {
-		printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
+		printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
+			irq, devname);
 		return -ENXIO;
 	}
 
@@ -211,6 +224,11 @@
 		return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA,
 		                       handler, flags, devname, dev_id);
 
+	/*
+	 * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared,
+	 * we could add a check here for the SA_SHIRQ flag but all drivers
+	 * should be aware of sharing anyway.
+	 */
 	if (ami_servers[irq]) {
 		if (!(node = new_irq_node()))
 			return -ENOMEM;
@@ -219,20 +237,8 @@
 		node->dev_id  = dev_id;
 		node->devname = devname;
 		node->next    = NULL;
-		amiga_insert_irq(&ami_irq_list[irq], node);
+		error = amiga_insert_irq(&ami_irq_list[irq], node);
 	} else {
-		if (!(ami_irq_list[irq]->flags & IRQ_FLG_STD)) {
-			if (ami_irq_list[irq]->flags & IRQ_FLG_LOCK) {
-				printk("%s: IRQ %d from %s is not replaceable\n",
-				       __FUNCTION__, irq, ami_irq_list[irq]->devname);
-				return -EBUSY;
-			}
-			if (!(flags & IRQ_FLG_REPLACE)) {
-				printk("%s: %s can't replace IRQ %d from %s\n",
-				       __FUNCTION__, devname, irq, ami_irq_list[irq]->devname);
-				return -EBUSY;
-			}
-		}
 		ami_irq_list[irq]->handler = handler;
 		ami_irq_list[irq]->flags   = flags;
 		ami_irq_list[irq]->dev_id  = dev_id;
@@ -243,7 +249,7 @@
 	if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq])
 		custom.intena = IF_SETCLR | ami_intena_vals[irq];
 
-	return 0;
+	return error;
 }
 
 void amiga_free_irq(unsigned int irq, void *dev_id)
@@ -276,7 +282,7 @@
 			printk("%s: removing probably wrong IRQ %d from %s\n",
 			       __FUNCTION__, irq, ami_irq_list[irq]->devname);
 		ami_irq_list[irq]->handler = ami_badint;
-		ami_irq_list[irq]->flags   = IRQ_FLG_STD;
+		ami_irq_list[irq]->flags   = 0;
 		ami_irq_list[irq]->dev_id  = NULL;
 		ami_irq_list[irq]->devname = NULL;
 		custom.intena = ami_intena_vals[irq];
@@ -366,45 +372,58 @@
 void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
 {
 	irq_node_t *node, *slow_nodes;
-	unsigned short flags;
+	unsigned short flags, intena;
 
 	kstat.irqs[0][SYS_IRQS + irq]++;
 	if (server->count++)
 		server->reentrance = 1;
-	/* serve first fast and normal handlers */
-	for (node = ami_irq_list[irq];
-	     node && (!(node->flags & IRQ_FLG_SLOW));
-	     node = node->next)
-		node->handler(irq, node->dev_id, fp);
-	custom.intreq = ami_intena_vals[irq];
+
+	intena = ami_intena_vals[irq];
+	custom.intreq = intena;
+
+	/* serve first fast handlers - there can only be one of these */
+	node = ami_irq_list[irq];
+
+	/*
+	 * Timer interrupts show up like this
+	 */
 	if (!node) {
 		server->count--;
 		return;
 	}
-#ifdef CONFIG_APUS
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
-	APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
-				  | (~(fp->mq) & IPLEMU_IPLMASK)));
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-#else
+
+	if (node && (node->flags & SA_INTERRUPT)) {
+		save_flags(flags);
+		cli();
+		node->handler(irq, node->dev_id, fp);
+		restore_flags(flags);
+
+		server->count--;
+		return;
+	}
+
+	/*
+	 * Disable the interrupt source in question and reenable all
+	 * other interrupts. No interrupt handler should ever touch
+	 * the intena flags directly!
+	 */
+	custom.intena = intena;
 	save_flags(flags);
-	restore_flags((flags & ~0x0700) | (fp->sr & 0x0700));
-#endif
-	/* if slow handlers exists, serve them now */
+	sti();
+
 	slow_nodes = node;
 	for (;;) {
 		for (; node; node = node->next)
 			node->handler(irq, node->dev_id, fp);
-		/* if reentrance occurred, serve slow handlers again */
-		custom.intena = ami_intena_vals[irq];
+
 		if (!server->reentrance) {
 			server->count--;
-			custom.intena = IF_SETCLR | ami_intena_vals[irq];
+			restore_flags(flags);
+			custom.intena = IF_SETCLR | intena;
 			return;
 		}
+
 		server->reentrance = 0;
-		custom.intena = IF_SETCLR | ami_intena_vals[irq];
 		node = slow_nodes;
 	}
 }
@@ -522,24 +541,13 @@
 	for (i = 0; i < AMI_STD_IRQS; i++) {
 		if (!(node = ami_irq_list[i]))
 			continue;
-		if (node->flags & IRQ_FLG_STD)
-			continue;
 		len += sprintf(buf+len, "ami  %2d: %10u ", i,
 		               kstat.irqs[0][SYS_IRQS + i]);
 		do {
-			if (ami_servers[i]) {
-				if (node->flags & IRQ_FLG_FAST)
-					len += sprintf(buf+len, "F ");
-				else if (node->flags & IRQ_FLG_SLOW)
-					len += sprintf(buf+len, "S ");
-				else
-					len += sprintf(buf+len, "  ");
-			} else {
-				if (node->flags & IRQ_FLG_LOCK)
-					len += sprintf(buf+len, "L ");
-				else
-					len += sprintf(buf+len, "  ");
-			}
+			if (node->flags & SA_INTERRUPT)
+				len += sprintf(buf+len, "F ");
+			else
+				len += sprintf(buf+len, "  ");
 			len += sprintf(buf+len, "%s\n", node->devname);
 			if ((node = node->next))
 				len += sprintf(buf+len, "                    ");
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/amiga/bootinfo.c linux/arch/ppc/amiga/bootinfo.c
--- v2.3.19/linux/arch/ppc/amiga/bootinfo.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/amiga/bootinfo.c	Thu Oct  7 10:17:08 1999
@@ -16,9 +16,11 @@
 
 extern char cmd_line[CL_SIZE];
 
-int num_memory = 0;
-struct mem_info memory[NUM_MEMINFO];
-struct mem_info ramdisk;
+extern int num_memory;
+extern int m68k_realnum_memory;
+extern struct mem_info memory[NUM_MEMINFO];
+extern struct mem_info m68k_memory[NUM_MEMINFO];
+extern struct mem_info ramdisk;
 
 extern int amiga_parse_bootinfo(const struct bi_record *);
 extern int atari_parse_bootinfo(const struct bi_record *);
@@ -42,6 +44,11 @@
 		    memory[num_memory].addr = data[0];
 		    memory[num_memory].size = data[1];
 		    num_memory++;
+
+		    /* FIXME: duplicate for m68k drivers. */
+		    m68k_memory[m68k_realnum_memory].addr = data[0];
+		    m68k_memory[m68k_realnum_memory].size = data[1];
+		    m68k_realnum_memory++;
 		} else
 		    printk("parse_bootinfo: too many memory chunks\n");
 		break;
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/amiga/chipram.c linux/arch/ppc/amiga/chipram.c
--- v2.3.19/linux/arch/ppc/amiga/chipram.c	Tue Aug  4 16:06:36 1998
+++ linux/arch/ppc/amiga/chipram.c	Thu Oct  7 10:17:08 1999
@@ -1 +1,175 @@
-#include "../../m68k/amiga/chipram.c"
+/*
+**  linux/amiga/chipram.c
+**
+**      Modified 03-May-94 by Geert Uytterhoeven
+**                           (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+**          - 64-bit aligned allocations for full AGA compatibility
+*/
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/amigahw.h>
+
+struct chip_desc {
+	unsigned first   :  1;
+	unsigned last    :  1;
+	unsigned alloced :  1;
+	unsigned length  : 24;
+	long pad;					/* We suppose this makes this struct 64 bits long!! */
+};
+
+#define DP(ptr) ((struct chip_desc *)(ptr))
+
+u_long amiga_chip_size;
+static unsigned long chipavail;
+
+unsigned long amiga_chip_avail( void )
+{
+#ifdef DEBUG
+	printk("chip_avail : %ld bytes\n",chipavail);
+#endif
+	return chipavail;
+}
+
+
+__init
+void amiga_chip_init (void)
+{
+  struct chip_desc *dp;
+
+  if (!AMIGAHW_PRESENT(CHIP_RAM))
+    return;
+
+#ifndef CONFIG_APUS_FAST_EXCEPT
+  /*
+   * Remove the first 4 pages where PPC exception handlers will
+   * be located.
+   */
+  amiga_chip_size -= 0x4000;
+#endif
+
+  /* initialize start boundary */
+
+  dp = DP(chipaddr);
+  dp->first = 1;
+
+  dp->alloced = 0;
+  dp->length = amiga_chip_size - 2*sizeof(*dp);
+
+  /* initialize end boundary */
+  dp = DP(chipaddr + amiga_chip_size) - 1;
+  dp->last = 1;
+  
+  dp->alloced = 0;
+  dp->length = amiga_chip_size - 2*sizeof(*dp);
+  chipavail = dp->length;  /*MILAN*/
+
+#ifdef DEBUG
+  printk ("chipram end boundary is %p, length is %d\n", dp,
+	  dp->length);
+#endif
+}
+
+void *amiga_chip_alloc (long size)
+{
+	/* last chunk */
+	struct chip_desc *dp;
+	void *ptr;
+
+	/* round off */
+	size = (size + 7) & ~7;
+
+#ifdef DEBUG
+   printk("chip_alloc: allocate %ld bytes\n", size);
+#endif
+
+	/*
+	 * get pointer to descriptor for last chunk by 
+	 * going backwards from end chunk
+	 */
+	dp = DP(chipaddr + amiga_chip_size) - 1;
+	dp = DP((unsigned long)dp - dp->length) - 1;
+	
+	while ((dp->alloced || dp->length < size)
+	       && !dp->first)
+		dp = DP ((unsigned long)dp - dp[-1].length) - 2;
+
+	if (dp->alloced || dp->length < size) {
+		printk ("no chipmem available for %ld allocation\n", size);
+		return NULL;
+	}
+
+	if (dp->length < (size + 2*sizeof(*dp))) {
+		/* length too small to split; allocate the whole thing */
+		dp->alloced = 1;
+		ptr = (void *)(dp+1);
+		dp = DP((unsigned long)ptr + dp->length);
+		dp->alloced = 1;
+#ifdef DEBUG
+		printk ("chip_alloc: no split\n");
+#endif
+	} else {
+		/* split the extent; use the end part */
+		long newsize = dp->length - (2*sizeof(*dp) + size);
+
+#ifdef DEBUG
+		printk ("chip_alloc: splitting %d to %ld\n", dp->length,
+			newsize);
+#endif
+		dp->length = newsize;
+		dp = DP((unsigned long)(dp+1) + newsize);
+		dp->first = dp->last = 0;
+		dp->alloced = 0;
+		dp->length = newsize;
+		dp++;
+		dp->first = dp->last = 0;
+		dp->alloced = 1;
+		dp->length = size;
+		ptr = (void *)(dp+1);
+		dp = DP((unsigned long)ptr + size);
+		dp->alloced = 1;
+		dp->length = size;
+	}
+
+#ifdef DEBUG
+	printk ("chip_alloc: returning %p\n", ptr);
+#endif
+
+	if ((unsigned long)ptr & 7)
+		panic("chip_alloc: alignment violation\n");
+
+    chipavail -= size + (2*sizeof(*dp)); /*MILAN*/
+
+    return ptr;
+}
+
+void amiga_chip_free (void *ptr)
+{
+	struct chip_desc *sdp = DP(ptr) - 1, *dp2;
+	struct chip_desc *edp = DP((unsigned long)ptr + sdp->length);
+
+    chipavail += sdp->length + (2* sizeof(sdp)); /*MILAN*/
+#ifdef DEBUG
+   printk("chip_free: free %ld bytes at %p\n",sdp->length,ptr);
+#endif
+	/* deallocate the chunk */
+	sdp->alloced = edp->alloced = 0;
+
+	/* check if we should merge with the previous chunk */
+	if (!sdp->first && !sdp[-1].alloced) {
+		dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2;
+		dp2->length += sdp->length + 2*sizeof(*sdp);
+		edp->length = dp2->length;
+		sdp = dp2;
+	}
+
+	/* check if we should merge with the following chunk */
+	if (!edp->last && !edp[1].alloced) {
+		dp2 = DP((unsigned long)edp + edp[1].length) + 2;
+		dp2->length += edp->length + 2*sizeof(*sdp);
+		sdp->length = dp2->length;
+		edp = dp2;
+	}
+}
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c
--- v2.3.19/linux/arch/ppc/amiga/config.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/amiga/config.c	Thu Oct  7 10:17:08 1999
@@ -1,13 +1,12 @@
 #define m68k_debug_device debug_device
-#define m68k_num_memory num_memory
-#define m68k_memory memory
 
 #include <linux/init.h>
 
 /* machine dependent "kbd-reset" setup function */
-void (*kbd_reset_setup) (char *, int) __initdata = 0;
+void (*mach_kbd_reset_setup) (char *, int) __initdata = 0;
 
 #include <asm/io.h>
+#include <asm/system.h>
 
 /*
  *  linux/arch/m68k/amiga/config.c
@@ -41,6 +40,7 @@
 #include <asm/machdep.h>
 #include <linux/zorro.h>
 
+unsigned long powerup_PCI_present;
 unsigned long amiga_model;
 unsigned long amiga_eclock;
 unsigned long amiga_masterclock;
@@ -61,7 +61,6 @@
 /* amiga specific keyboard functions */
 extern int amiga_keyb_init(void);
 extern int amiga_kbdrate (struct kbd_repeat *);
-extern void amiga_kbd_reset_setup(char*, int);
 /* amiga specific irq functions */
 extern void amiga_init_IRQ (void);
 extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *);
@@ -137,8 +136,13 @@
 
     switch (record->tag) {
 	case BI_AMIGA_MODEL:
-	    amiga_model = *data;
-	    break;
+	{
+		unsigned long d = *data;
+
+		powerup_PCI_present = d & 0x100;
+		amiga_model = d & 0xff;
+	}
+	break;
 
 	case BI_AMIGA_ECLOCK:
 	    amiga_eclock = *data;
@@ -352,7 +356,6 @@
   mach_sched_init      = amiga_sched_init;
   mach_keyb_init       = amiga_keyb_init;
   mach_kbdrate         = amiga_kbdrate;
-  kbd_reset_setup      = amiga_kbd_reset_setup;
   mach_init_IRQ        = amiga_init_IRQ;
   mach_default_handler = &amiga_default_handler;
 #ifndef CONFIG_APUS
@@ -451,8 +454,7 @@
 	 * Please don't change this to use ciaa, as it interferes with the
 	 * SCSI code. We'll have to take a look at this later
 	 */
-	request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK,
-		    "timer", NULL);
+	request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, 0, "timer", NULL);
 	/* start timer */
 	ciab.cra |= 0x11;
 }
@@ -741,7 +743,7 @@
 static void amiga_serial_putc(char c)
 {
     custom.serdat = (unsigned char)c | 0x100;
-    iobarrier_rw ();
+    mb();
     while (!(custom.serdatr & 0x2000))
        ;
 }
@@ -921,3 +923,30 @@
 
     return(len);
 }
+
+#ifdef CONFIG_APUS
+int get_hardware_list(char *buffer)
+{
+	extern int get_cpuinfo(char *buffer);
+	int len = 0;
+	char model[80];
+	u_long mem;
+	int i;
+
+	if (mach_get_model)
+		mach_get_model(model);
+	else
+		strcpy(model, "Unknown PowerPC");
+	
+	len += sprintf(buffer+len, "Model:\t\t%s\n", model);
+	len += get_cpuinfo(buffer+len);
+	for (mem = 0, i = 0; i < m68k_realnum_memory; i++)
+		mem += m68k_memory[i].size;
+	len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10);
+
+	if (mach_get_hardware_list)
+		len += mach_get_hardware_list(buffer+len);
+
+	return(len);
+}
+#endif
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/amiga/ints.c linux/arch/ppc/amiga/ints.c
--- v2.3.19/linux/arch/ppc/amiga/ints.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/amiga/ints.c	Thu Oct  7 10:17:08 1999
@@ -5,19 +5,22 @@
  *  Needed to drive the m68k emulating IRQ hardware on the PowerUp boards.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
+#include <linux/sched.h>
 #include <linux/kernel_stat.h>
-#include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 
 #include <asm/setup.h>
+#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
+#include <asm/page.h>
 #include <asm/machdep.h>
 
 /* table for system interrupt handlers */
-irq_handler_t irq_list[SYS_IRQS];
+static irq_handler_t irq_list[SYS_IRQS];
 
 static const char *default_names[SYS_IRQS] = {
 	"spurious int", "int1 handler", "int2 handler", "int3 handler",
@@ -42,14 +45,15 @@
  * the IRQ handling routines.
  */
 
-void __init apus_init_IRQ(void)
+__init
+void m68k_init_IRQ(void)
 {
 	int i;
 
 	for (i = 0; i < SYS_IRQS; i++) {
 		if (mach_default_handler)
 			irq_list[i].handler = (*mach_default_handler)[i];
-		irq_list[i].flags   = IRQ_FLG_STD;
+		irq_list[i].flags   = 0;
 		irq_list[i].dev_id  = NULL;
 		irq_list[i].devname = default_names[i];
 	}
@@ -83,6 +87,7 @@
 		return -ENXIO;
 	}
 
+#if 0
 	if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
 		if (irq_list[irq].flags & IRQ_FLG_LOCK) {
 			printk("%s: IRQ %d from %s is not replaceable\n",
@@ -95,6 +100,8 @@
 			return -EBUSY;
 		}
 	}
+#endif
+
 	irq_list[irq].handler = handler;
 	irq_list[irq].flags   = flags;
 	irq_list[irq].dev_id  = dev_id;
@@ -114,7 +121,7 @@
 		       __FUNCTION__, irq, irq_list[irq].devname);
 
 	irq_list[irq].handler = (*mach_default_handler)[irq];
-	irq_list[irq].flags   = IRQ_FLG_STD;
+	irq_list[irq].flags   = 0;
 	irq_list[irq].dev_id  = NULL;
 	irq_list[irq].devname = default_names[irq];
 }
@@ -134,7 +141,7 @@
 	}
 }
 
-int get_irq_list(char *buf)
+int m68k_get_irq_list(char *buf)
 {
 	int i, len = 0;
 
@@ -143,9 +150,6 @@
 		for (i = 0; i < SYS_IRQS; i++) {
 			len += sprintf(buf+len, "auto %2d: %10u ", i,
 			               i ? kstat.irqs[0][i] : num_spurious);
-			if (irq_list[i].flags & IRQ_FLG_LOCK)
-				len += sprintf(buf+len, "L ");
-			else
 				len += sprintf(buf+len, "  ");
 			len += sprintf(buf+len, "%s\n", irq_list[i].devname);
 		}
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/amiga/pcmcia.c linux/arch/ppc/amiga/pcmcia.c
--- v2.3.19/linux/arch/ppc/amiga/pcmcia.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/amiga/pcmcia.c	Thu Oct  7 10:17:08 1999
@@ -0,0 +1 @@
+#include "../../m68k/amiga/pcmcia.c"
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/amiga/time.c linux/arch/ppc/amiga/time.c
--- v2.3.19/linux/arch/ppc/amiga/time.c	Sun Nov 15 10:51:41 1998
+++ linux/arch/ppc/amiga/time.c	Thu Oct  7 10:17:08 1999
@@ -15,7 +15,7 @@
 	unsigned int day, unsigned int hour,
 	unsigned int min, unsigned int sec);
 
-unsigned long apus_get_rtc_time(void)
+unsigned long m68k_get_rtc_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
 
@@ -30,7 +30,7 @@
 	return mktime(year, mon, day, hour, min, sec);
 }
 
-int apus_set_rtc_time(unsigned long nowtime)
+int m68k_set_rtc_time(unsigned long nowtime)
 {
   if (mach_set_clock_mmss)
     return mach_set_clock_mmss (nowtime);
@@ -89,4 +89,6 @@
                 dist = period / 4;
 	}
 #endif
+	/* should be made smarter */
+	ppc_md.heartbeat_count = 1;
 }
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.3.19/linux/arch/ppc/boot/Makefile	Fri Sep 10 23:57:27 1999
+++ linux/arch/ppc/boot/Makefile	Thu Oct  7 10:17:08 1999
@@ -25,6 +25,10 @@
 IOFF = 0
 ISZ = 0
 
+ifeq ($(CONFIG_ALL_PPC),y)
+CONFIG_PREP=y
+endif
+
 ifeq ($(CONFIG_SMP),y)
 TFTPIMAGE=/tftpboot/zImage.prep.smp$(MSIZE)
 else
@@ -72,16 +76,19 @@
 	rm zvmlinux.initrd.tmp
 
 zImage: zvmlinux mkprep sImage
+ifdef CONFIG_PREP
 	./mkprep -pbp zvmlinux zImage
+endif
 
 sImage: ../../../vmlinux
 ifdef CONFIG_GEMINI
 	$(OBJCOPY) -I elf32-powerpc -O binary ../../../vmlinux sImage
-else
 endif
 
 zImage.initrd: zvmlinux.initrd mkprep
+ifdef CONFIG_PREP
 	./mkprep -pbp zvmlinux.initrd zImage.initrd
+endif
 
 zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
 #
@@ -110,7 +117,9 @@
 	$(HOSTCC) -o mkprep mkprep.c
 
 znetboot : zImage
+ifdef CONFIG_PREP
 	cp zImage $(TFTPIMAGE)
+endif
 ifdef CONFIG_GEMINI
 	cp sImage /tftpboot/
 endif
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- v2.3.19/linux/arch/ppc/common_defconfig	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/common_defconfig	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 #
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
 #
 
 #
@@ -13,6 +13,7 @@
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
 CONFIG_ALL_PPC=y
+# CONFIG_GEMINI is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
@@ -26,8 +27,6 @@
 CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
 CONFIG_PCI=y
-# CONFIG_PCI_QUIRKS is not set
-CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -40,9 +39,14 @@
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
-CONFIG_MAC_KEYBOARD=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+CONFIG_ADB=y
+CONFIG_ADB_CUDA=y
+CONFIG_ADB_MACIO=y
+CONFIG_ADB_PMU=y
+CONFIG_ADB_KEYBOARD=y
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
@@ -50,14 +54,16 @@
 # CONFIG_CMDLINE_BOOL is not set
 
 #
-# Block devices
+# Plug and Play configuration
 #
-CONFIG_BLK_DEV_FD=y
-CONFIG_BLK_DEV_IDE=y
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
 
 #
-# Please see Documentation/ide.txt for help/info on IDE drives
+# Block devices
 #
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
@@ -77,10 +83,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_CPQ_DA is not set
-
-#
-# Additional Block Devices
-#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -96,10 +98,11 @@
 # Networking options
 #
 CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
 CONFIG_NETLINK=y
 # CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
-# CONFIG_FIREWALL is not set
+# CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -112,17 +115,10 @@
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
 CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
-CONFIG_INET_RARP=y
 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=m
 # CONFIG_DECNET is not set
@@ -134,7 +130,6 @@
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
-# CONFIG_CPU_IS_SLOW is not set
 
 #
 # QoS and/or fair queueing
@@ -145,19 +140,11 @@
 # SCSI support
 #
 CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 # CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -175,6 +162,7 @@
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
+# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -187,8 +175,6 @@
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_G_NCR5380_PORT is not set
-# CONFIG_SCSI_G_NCR5380_MEM is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
@@ -232,6 +218,7 @@
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -244,11 +231,12 @@
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
 CONFIG_PCNET32=y
-# CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -264,6 +252,7 @@
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_ZNET is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -275,10 +264,9 @@
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
 CONFIG_PPP=y
-
-#
-# CCP compressors for PPP are only built as modules.
-#
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 
@@ -286,6 +274,7 @@
 # Token ring devices
 #
 # CONFIG_TR is not set
+# CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
 
@@ -298,6 +287,13 @@
 # CONFIG_DLCI is not set
 
 #
+# PCMCIA network devices
+#
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
 # Amateur Radio support
 #
 # CONFIG_HAMRADIO is not set
@@ -316,21 +312,22 @@
 # Console drivers
 #
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-# CONFIG_FB_ATY is not set
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
 CONFIG_FB_MATROX=y
 # CONFIG_FB_MATROX_MILLENIUM is not set
 CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_ATY is not set
+CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -365,7 +362,7 @@
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_LOGIBUSMOUSE is not set
 # CONFIG_MS_BUSMOUSE is not set
-CONFIG_ADBMOUSE=y
+# CONFIG_ADB_MOUSE is not set
 CONFIG_MOUSE=y
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
@@ -385,19 +382,14 @@
 #
 # CONFIG_JOYSTICK 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_FT_NORMAL_DEBUG is not set
-# CONFIG_FT_FULL_DEBUG is not set
-# CONFIG_FT_NO_TRACE is not set
-# CONFIG_FT_NO_TRACE_AT_ALL is not set
-# CONFIG_FT_STD_FDC is not set
-# CONFIG_FT_MACH2 is not set
-# CONFIG_FT_PROBE_FC10 is not set
-# CONFIG_FT_ALT_FDC is not set
+# CONFIG_DRM is not set
 
 #
 # USB drivers - not for the faint of heart
@@ -413,9 +405,13 @@
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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_ISO9660_FS=y
 # 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
@@ -442,12 +438,14 @@
 #
 # Partition Types
 #
-# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MAC_PARTITION=y
-# CONFIG_SMD_DISKLABEL is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_SGI_DISKLABEL is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
 # CONFIG_NLS is not set
 
 #
@@ -458,6 +456,8 @@
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
@@ -472,6 +472,7 @@
 # CONFIG_SOUND_MSS is not set
 # CONFIG_SOUND_SSCAPE is not set
 # CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_VIA82CXXX is not set
 # CONFIG_SOUND_MAD16 is not set
 # CONFIG_SOUND_WAVEFRONT is not set
 CONFIG_SOUND_CS4232=m
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.3.19/linux/arch/ppc/config.in	Fri Sep 10 23:57:27 1999
+++ linux/arch/ppc/config.in	Thu Oct  7 10:17:08 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.103 1999/09/01 19:04:44 cort Exp $
+# $Id: config.in,v 1.106 1999/09/14 19:21:18 cort Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -10,16 +10,33 @@
 choice 'Processor type' \
 	"6xx/7xx		CONFIG_6xx \
 	 630/Power3(64-Bit) 	CONFIG_PPC64 \
-	 860/821		CONFIG_8xx" 6xx/7xx
+	 82xx		 	CONFIG_82xx \
+	 8xx			CONFIG_8xx" 6xx/7xx
 
-choice 'Machine Type' \
+if [ "$CONFIG_8xx" = "y" ]; then
+  choice 'Processor Model' \
+  	"821	CONFIG_MPC821 \
+  	 823	CONFIG_MPC823 \
+  	 850	CONFIG_MPC850 \
+  	 855	CONFIG_MPC855 \
+  	 860	CONFIG_MPC860 \
+  	 860T	CONFIG_MPC860T" 860
+  define_bool CONFIG_SERIAL_CONSOLE y
+  choice 'Machine Type' \
+	"RPX-Lite	CONFIG_RPXLITE \
+	 RPX-Classic	CONFIG_RPXCLASSIC \
+	 BSE-IP		CONFIG_BSEIP \
+  	 MBX		CONFIG_MBX \
+	 WinCept	CONFIG_WINCEPT" RPX-Lite
+else
+  choice 'Machine Type' \
 	"PowerMac	CONFIG_PMAC \
 	 PReP/MTX	CONFIG_PREP \
 	 CHRP		CONFIG_CHRP \
 	 PowerMac/PReP/CHRP	CONFIG_ALL_PPC \
 	 Gemini		CONFIG_GEMINI \
-  	 APUS           CONFIG_APUS \
-	 MBX		CONFIG_MBX" PowerMac
+  	 APUS           CONFIG_APUS" PowerMac
+fi
 
 bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_ALL_PPC" != "y" ];then
@@ -35,10 +52,6 @@
 fi
 endmenu
 
-if [ "$CONFIG_MBX" = "y" ];then
-  define_bool CONFIG_SERIAL_CONSOLE y
-fi
-
 mainmenu_option next_comment
 comment 'General setup'
 
@@ -52,7 +65,11 @@
 if [ "$CONFIG_APUS" = "y" ]; then
   define_bool CONFIG_PCI n
 else
-  define_bool CONFIG_PCI y
+  if [ "$CONFIG_8xx" = "y" ]; then
+    bool 'QSpan PCI' CONFIG_PCI
+  else
+    define_bool CONFIG_PCI y
+  fi
 fi
 
 bool 'Networking support' CONFIG_NET
@@ -67,23 +84,32 @@
 
 source drivers/parport/Config.in
 
-bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
-bool 'Support for frame buffer devices' CONFIG_FB
-if [ "$CONFIG_FB" = "y" ]; then
-  bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
-fi
-
-bool 'Power management support for PowerBook 3400/2400' CONFIG_PMAC_PBOOK
-bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
-bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
-tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
-if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
-   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
-fi
-bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
-bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
-bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
-bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP
+if [ "$CONFIG_8xx" != "y" ]; then
+  bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
+  bool 'Support for frame buffer devices' CONFIG_FB
+  if [ "$CONFIG_FB" = "y" ]; then
+    bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
+  fi
+
+  bool 'Power management support for PowerBooks' CONFIG_PMAC_PBOOK
+  bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
+  tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
+  if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
+     bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+  fi
+  bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB
+  if [ "$CONFIG_ADB" = "y" ]; then
+     bool '   Include CUDA ADB driver' CONFIG_ADB_CUDA
+     bool '   Include MacIO ADB driver' CONFIG_ADB_MACIO
+     bool '   Include PMU (Powerbook) ADB driver' CONFIG_ADB_PMU
+     bool 'Support for ADB keyboard' CONFIG_ADB_KEYBOARD 
+  fi
+  bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+  bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
+  bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
+  bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP
+fi
+
 if [ "$CONFIG_PREP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
   bool 'PReP bootloader kernel arguments' CONFIG_CMDLINE_BOOL y
   if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then
@@ -182,6 +208,10 @@
 fi
 
 endmenu
+
+if [ "$CONFIG_8xx" = "y" ]; then
+source arch/ppc/8xx_io/Config.in
+fi
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.3.19/linux/arch/ppc/defconfig	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/defconfig	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 #
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
 #
 
 #
@@ -13,6 +13,7 @@
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
 CONFIG_ALL_PPC=y
+# CONFIG_GEMINI is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
@@ -26,8 +27,6 @@
 CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
 CONFIG_PCI=y
-# CONFIG_PCI_QUIRKS is not set
-CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -40,9 +39,14 @@
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
-CONFIG_MAC_KEYBOARD=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+CONFIG_ADB=y
+CONFIG_ADB_CUDA=y
+CONFIG_ADB_MACIO=y
+CONFIG_ADB_PMU=y
+CONFIG_ADB_KEYBOARD=y
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
@@ -50,14 +54,16 @@
 # CONFIG_CMDLINE_BOOL is not set
 
 #
-# Block devices
+# Plug and Play configuration
 #
-CONFIG_BLK_DEV_FD=y
-CONFIG_BLK_DEV_IDE=y
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
 
 #
-# Please see Documentation/ide.txt for help/info on IDE drives
+# Block devices
 #
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
@@ -77,10 +83,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_CPQ_DA is not set
-
-#
-# Additional Block Devices
-#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -96,10 +98,11 @@
 # Networking options
 #
 CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
 CONFIG_NETLINK=y
 # CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
-# CONFIG_FIREWALL is not set
+# CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -112,17 +115,10 @@
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
 CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
-CONFIG_INET_RARP=y
 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=m
 # CONFIG_DECNET is not set
@@ -134,7 +130,6 @@
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
-# CONFIG_CPU_IS_SLOW is not set
 
 #
 # QoS and/or fair queueing
@@ -145,19 +140,11 @@
 # SCSI support
 #
 CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 # CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -175,6 +162,7 @@
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
+# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -187,8 +175,6 @@
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_G_NCR5380_PORT is not set
-# CONFIG_SCSI_G_NCR5380_MEM is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
@@ -232,6 +218,7 @@
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -244,11 +231,12 @@
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
 CONFIG_PCNET32=y
-# CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -264,6 +252,7 @@
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_ZNET is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -275,10 +264,9 @@
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
 CONFIG_PPP=y
-
-#
-# CCP compressors for PPP are only built as modules.
-#
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 
@@ -286,6 +274,7 @@
 # Token ring devices
 #
 # CONFIG_TR is not set
+# CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
 
@@ -298,6 +287,13 @@
 # CONFIG_DLCI is not set
 
 #
+# PCMCIA network devices
+#
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
 # Amateur Radio support
 #
 # CONFIG_HAMRADIO is not set
@@ -316,21 +312,22 @@
 # Console drivers
 #
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-# CONFIG_FB_ATY is not set
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
 CONFIG_FB_MATROX=y
 # CONFIG_FB_MATROX_MILLENIUM is not set
 CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_ATY is not set
+CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -365,7 +362,7 @@
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_LOGIBUSMOUSE is not set
 # CONFIG_MS_BUSMOUSE is not set
-CONFIG_ADBMOUSE=y
+# CONFIG_ADB_MOUSE is not set
 CONFIG_MOUSE=y
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
@@ -385,19 +382,14 @@
 #
 # CONFIG_JOYSTICK 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_FT_NORMAL_DEBUG is not set
-# CONFIG_FT_FULL_DEBUG is not set
-# CONFIG_FT_NO_TRACE is not set
-# CONFIG_FT_NO_TRACE_AT_ALL is not set
-# CONFIG_FT_STD_FDC is not set
-# CONFIG_FT_MACH2 is not set
-# CONFIG_FT_PROBE_FC10 is not set
-# CONFIG_FT_ALT_FDC is not set
+# CONFIG_DRM is not set
 
 #
 # USB drivers - not for the faint of heart
@@ -413,9 +405,13 @@
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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_ISO9660_FS=y
 # 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
@@ -442,12 +438,14 @@
 #
 # Partition Types
 #
-# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MAC_PARTITION=y
-# CONFIG_SMD_DISKLABEL is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_SGI_DISKLABEL is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
 # CONFIG_NLS is not set
 
 #
@@ -458,6 +456,8 @@
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
@@ -472,6 +472,7 @@
 # CONFIG_SOUND_MSS is not set
 # CONFIG_SOUND_SSCAPE is not set
 # CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_VIA82CXXX is not set
 # CONFIG_SOUND_MAD16 is not set
 # CONFIG_SOUND_WAVEFRONT is not set
 CONFIG_SOUND_CS4232=m
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/gemini_defconfig linux/arch/ppc/gemini_defconfig
--- v2.3.19/linux/arch/ppc/gemini_defconfig	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/gemini_defconfig	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -8,14 +8,25 @@
 CONFIG_PPC=y
 CONFIG_6xx=y
 # CONFIG_PPC64 is not set
+# CONFIG_82xx is not set
 # CONFIG_8xx is not set
+# CONFIG_MPC821 is not set
+# CONFIG_MPC823 is not set
+# CONFIG_MPC850 is not set
+# CONFIG_MPC855 is not set
+# CONFIG_MPC860 is not set
+# CONFIG_MPC860T is not set
+# CONFIG_RPXLITE is not set
+# CONFIG_RPXCLASSIC is not set
+# CONFIG_BSEIP is not set
+# CONFIG_MBX is not set
+# CONFIG_WINCEPT is not set
 # CONFIG_PMAC is not set
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
 # CONFIG_ALL_PPC is not set
 CONFIG_GEMINI=y
 # CONFIG_APUS is not set
-# CONFIG_MBX is not set
 # CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 CONFIG_6xx=y
@@ -39,9 +50,9 @@
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_FB is not set
 # CONFIG_PMAC_PBOOK is not set
-CONFIG_MAC_KEYBOARD=y
 # CONFIG_MAC_FLOPPY is not set
 # CONFIG_MAC_SERIAL is not set
+# CONFIG_ADB is not set
 # CONFIG_PROC_DEVICETREE is not set
 # CONFIG_TOTALMP is not set
 # CONFIG_BOOTX_TEXT is not set
@@ -51,15 +62,22 @@
 # 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
 # CONFIG_BLK_CPQ_DA 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
@@ -91,10 +109,18 @@
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
 CONFIG_SYN_COOKIES=y
+
+#
+# (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
@@ -116,11 +142,19 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 # CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -147,6 +181,8 @@
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
@@ -194,7 +230,21 @@
 #
 # Ethernet (10 or 100Mbit)
 #
-# CONFIG_NET_ETHERNET is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+CONFIG_NCR885E=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
@@ -241,7 +291,6 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_PC_KEYB=y
 CONFIG_SERIAL=y
 CONFIG_SERIAL_CONSOLE=y
 # CONFIG_SERIAL_EXTENDED is not set
@@ -256,14 +305,13 @@
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_LOGIBUSMOUSE is not set
 # CONFIG_MS_BUSMOUSE is not set
-CONFIG_ADBMOUSE=y
 CONFIG_MOUSE=y
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
-CONFIG_NVRAM=y
+# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 
 #
@@ -283,6 +331,15 @@
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
+# CONFIG_DRM is not set
 
 #
 # USB drivers - not for the faint of heart
@@ -298,12 +355,10 @@
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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_ISO9660_FS=y
 # 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
@@ -347,6 +402,6 @@
 #
 # Kernel hacking
 #
-CONFIG_MAGIC_SYSRQ=y
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.3.19/linux/arch/ppc/kernel/Makefile	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/Makefile	Thu Oct  7 10:17:08 1999
@@ -12,48 +12,83 @@
 
 O_TARGET := kernel.o
 OX_OBJS := ppc_ksyms.o setup.o
+KHEAD := head.o
 
+ifdef CONFIG_PPC_ALL
+CONFIG_PMAC=y
+CONFIG_PREP=y
+CONFIG_CHRP=y
+endif
 
 O_OBJS := entry.o traps.o irq.o idle.o time.o process.o signal.o syscalls.o \
 	  misc.o bitops.o ptrace.o align.o ppc_htab.o semaphore.o
+
 ifndef CONFIG_8xx
 O_OBJS += hashtable.o
 endif
+
 ifdef CONFIG_PCI
 O_OBJS += pci.o
 endif
+
 ifdef CONFIG_KGDB
 O_OBJS += ppc-stub.o
 endif
+
 ifdef CONFIG_TOTALMP
 O_OBJS += totalmp.o
 endif
 
-ifeq ($(CONFIG_MBX),y)
-O_OBJS += mbx_setup.o mbx_pci.o i8259.o ppc8xx_pic.o
+ifdef CONFIG_PMAC_PBOOK
+O_OBJS += sleep.o
+endif
+
+ifdef CONFIG_SMP
+O_OBJS += smp.o
+endif
+
+ifeq ($(CONFIG_8xx),y)
+KHEAD := head_8xx.o
+O_OBJS += m8xx_setup.o ppc8xx_pic.o
+ifndef CONFIG_MATH_EMULATION
+O_OBJS += softemu8xx.o
+endif
+ifdef CONFIG_PCI
+O_OBJS += qspan_pci.c
+endif
+ifdef CONFIG_MBX
+O_OBJS += i8259.o
+endif
 else
 ifeq ($(CONFIG_APUS),y)
 O_OBJS += apus_setup.o prom.o open_pic.o
 else
-ifneq ($(CONFIG_MBX),y)
-O_OBJS += prep_time.o pmac_time.o chrp_time.o \
-	  pmac_setup.o pmac_support.o \
-	  prep_pci.o pmac_pci.o chrp_pci.o \
-	  residual.o prom.o open_pic.o feature.o \
-	  prep_nvram.o i8259.o pmac_pic.o indirect_pci.o \
+ifneq ($(CONFIG_8xx),y)
+O_OBJS += chrp_setup.o chrp_pci.o chrp_time.o \
+	  pmac_time.o pmac_support.o pmac_pci.o pmac_setup.o \
+	  prom.o open_pic.o feature.o \
+	  i8259.o pmac_pic.o indirect_pci.o \
 	  gemini_pci.o gemini_prom.o gemini_setup.o
-OX_OBJS += chrp_setup.o prep_setup.o
+
+ifeq ($(CONFIG_PREP), y)
+O_OBJS += prep_pci.o prep_setup.o prep_nvram.o prep_time.o residual.o
 endif
+
+ifeq ($(CONFIG_PMAC), y)
 endif
+
+ifeq ($(CONFIG_PMAC), y)
 endif
 
-ifdef CONFIG_SMP
-O_OBJS += smp.o
+endif
+endif
 endif
 
-all: head.o kernel.o
+all: $(KHEAD) kernel.o
 
 head.o: head.S ppc_defs.h
+
+head_8xx.o: head_8xx.S ppc_defs.h
 
 ppc_defs.h: mk_defs.c ppc_defs.head \
 		$(TOPDIR)/include/asm/mmu.h \
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- v2.3.19/linux/arch/ppc/kernel/apus_setup.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/kernel/apus_setup.c	Thu Oct  7 10:17:08 1999
@@ -1,11 +1,16 @@
 /*
  *  linux/arch/ppc/kernel/apus_setup.c
  *
- *  Copyright (C) 1998  Jesper Skov
+ *  Copyright (C) 1998, 1999  Jesper Skov
  *
  *  Basically what is needed to replace functionality found in
  *  arch/m68k allowing Amiga drivers to work under APUS.
  *  Bits of code and/or ideas from arch/m68k and arch/ppc files.
+ *
+ * TODO:
+ *  This file needs a *really* good cleanup. Restructure and optimize.
+ *  Make sure it can be compiled for non-APUS configs. Begin to move
+ *  Amiga specific stuff into linux/machine/amiga.
  */
 
 #include <linux/config.h>
@@ -14,79 +19,96 @@
 #include <linux/sched.h>
 #include <linux/kd.h>
 #include <linux/init.h>
+#include <linux/serial.h>
 #include <linux/hdreg.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_APUS
+#include <asm/logging.h>
+#endif
 
 /* Get the IDE stuff from the 68k file */
+#include <linux/ide.h>
 #define ide_init_hwif_ports m68k_ide_init_hwif_ports
 #define ide_default_irq m68k_ide_default_irq
+#define ide_request_irq m68k_ide_request_irq
 #define ide_default_io_base m68k_ide_default_io_base
 #define ide_check_region m68k_ide_check_region
 #define ide_request_region m68k_ide_request_region
 #define ide_release_region m68k_ide_release_region
 #define ide_fix_driveid m68k_ide_fix_driveid
+#define ide_init_default_hwifs m68k_ide_init_default_hwifs
+#define select_t m68k_select_t
+#define ide_free_irq m68k_ide_free_irq
+//#include <asm/hdreg.h>
 #include <asm-m68k/ide.h>
+#undef ide_free_irq
+#undef select_t
+#undef ide_request_irq
+#undef ide_init_default_hwifs
 #undef ide_init_hwif_ports
-#define ide_default_irq
-#define ide_default_io_base
-#define ide_check_region
-#define ide_request_region
-#define ide_release_region
-#define ide_fix_driveid
-
+#undef ide_default_irq
+#undef ide_default_io_base
+#undef ide_check_region
+#undef ide_request_region
+#undef ide_release_region
+#undef ide_fix_driveid
+/*-------------------------------------------*/
 
+#include <asm/bootinfo.h>
 #include <asm/setup.h>
 #include <asm/amigahw.h>
 #include <asm/amigappc.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
+#include <asm/dma.h>
 #include <asm/machdep.h>
-#include <asm/ide.h>
+#include <asm/init.h>
 
-#include "time.h"
 #include "local_irq.h"
 
-unsigned long apus_get_rtc_time(void);
-int apus_set_rtc_time(unsigned long nowtime);
-
-/* APUS defs */
-extern int parse_bootinfo(const struct bi_record *);
-extern char _end[];
-#ifdef CONFIG_APUS
-struct mem_info ramdisk;
-unsigned long isa_io_base;
-unsigned long isa_mem_base;
-unsigned long pci_dram_offset;
-#endif
-/* END APUS defs */
-
-unsigned long m68k_machtype;
-char debug_device[6] = "";
+unsigned long m68k_machtype __apusdata;
+char debug_device[6] __apusdata = "";
 
 void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata;
 /* machine dependent keyboard functions */
 int (*mach_keyb_init) (void) __initdata;
-int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
-void (*mach_kbd_leds) (unsigned int) = NULL;
+int (*mach_kbdrate) (struct kbd_repeat *) __apusdata = NULL;
+void (*mach_kbd_leds) (unsigned int) __apusdata = NULL;
 /* machine dependent irq functions */
 void (*mach_init_IRQ) (void) __initdata;
-void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
-void (*mach_get_model) (char *model) = NULL;
-int (*mach_get_hardware_list) (char *buffer) = NULL;
-int (*mach_get_irq_list) (char *) = NULL;
-void (*mach_process_int) (int, struct pt_regs *) = NULL;
+void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) __apusdata = NULL;
+void (*mach_get_model) (char *model) __apusdata = NULL;
+int (*mach_get_hardware_list) (char *buffer) __apusdata = NULL;
+int (*mach_get_irq_list) (char *) __apusdata = NULL;
+void (*mach_process_int) (int, struct pt_regs *) __apusdata = NULL;
 /* machine dependent timer functions */
-unsigned long (*mach_gettimeoffset) (void);
-void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
-int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
-int (*mach_set_clock_mmss) (unsigned long) = NULL;
-void (*mach_reset)( void );
-long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
+unsigned long (*mach_gettimeoffset) (void) __apusdata;
+void (*mach_gettod) (int*, int*, int*, int*, int*, int*) __apusdata;
+int (*mach_hwclk) (int, struct hwclk_time*) __apusdata = NULL;
+int (*mach_set_clock_mmss) (unsigned long) __apusdata = NULL;
+void (*mach_reset)( void ) __apusdata;
+long mach_max_dma_address __apusdata = 0x00ffffff; /* default set to the lower 16MB */
+#if defined(CONFIG_AMIGA_FLOPPY)
 void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
-void (*mach_floppy_eject) (void) = NULL;
+void (*mach_floppy_eject) (void) __apusdata = NULL;
 #endif
 #ifdef CONFIG_HEARTBEAT
-void (*mach_heartbeat) (int) = NULL;
+void (*mach_heartbeat) (int) __apusdata = NULL;
+extern void apus_heartbeat (void);
+static int heartbeat_enabled = 1;
+
+void enable_heartbeat(void)
+{
+	heartbeat_enabled = 1;
+}
+
+void disable_heartbeat(void)
+{
+	heartbeat_enabled = 0;
+	mach_heartbeat(0);
+}
 #endif
 
 extern unsigned long amiga_model;
@@ -94,22 +116,154 @@
 extern unsigned count_period_num; /* 1 decrementer count equals */
 extern unsigned count_period_den; /* count_period_num / count_period_den us */
 
-extern struct mem_info memory[NUM_MEMINFO];/* memory description */
+int num_memory __apusdata = 0;
+struct mem_info memory[NUM_MEMINFO] __apusdata;/* memory description */
+/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */
+int m68k_realnum_memory __apusdata = 0;
+struct mem_info m68k_memory[NUM_MEMINFO] __apusdata;/* memory description */
+
+struct mem_info ramdisk __apusdata;
 
 extern void amiga_floppy_setup(char *, int *);
 extern void config_amiga(void);
 
-static int __60nsram = 0;
+static int __60nsram __apusdata = 0;
+
+/* for cpuinfo */
+static int __bus_speed __apusdata = 0;
+static int __speed_test_failed __apusdata = 0;
+
+/********************************************** COMPILE PROTECTION */
+/* Provide some stubs that links to Amiga specific functions. 
+ * This allows CONFIG_APUS to be removed from generic PPC files while
+ * preventing link errors for other PPC targets.
+ */
+__apus
+unsigned long apus_get_rtc_time(void)
+{
+#ifdef CONFIG_APUS
+	extern unsigned long m68k_get_rtc_time(void);
+	
+	return m68k_get_rtc_time ();
+#else
+	return 0;
+#endif
+}
+
+__apus
+int apus_set_rtc_time(unsigned long nowtime)
+{
+#ifdef CONFIG_APUS
+	extern int m68k_set_rtc_time(unsigned long nowtime);
+
+	return m68k_set_rtc_time (nowtime);
+#else
+	return 0;
+#endif
+}
+
+__apus
+int  apus_request_irq(unsigned int irq, 
+		      void (*handler)(int, void *, struct pt_regs *),
+		      unsigned long flags, const char *devname, 
+		      void *dev_id)
+{
+#ifdef CONFIG_APUS
+	extern int  amiga_request_irq(unsigned int irq, 
+				      void (*handler)(int, void *, 
+						      struct pt_regs *),
+				      unsigned long flags, 
+				      const char *devname, 
+				      void *dev_id);
+
+	return amiga_request_irq (irq, handler, flags, devname, dev_id);
+#else
+	return 0;
+#endif
+}
+
+__apus
+void apus_free_irq(unsigned int irq, void *dev_id)
+{
+#ifdef CONFIG_APUS
+	extern void amiga_free_irq(unsigned int irq, void *dev_id);
+
+	amiga_free_irq (irq, dev_id);
+#endif
+}
+
+__apus
+void apus_process_int(unsigned long vec, void *fp)
+{
+#ifdef CONFIG_APUS
+	extern void process_int(unsigned long vec, struct pt_regs *fp);
+
+	process_int (vec, (struct pt_regs*)fp);
+#endif
+}
+
+__apus
+int apus_get_irq_list(char *buf)
+{
+#ifdef CONFIG_APUS
+	extern int m68k_get_irq_list (char*);
+	
+	return m68k_get_irq_list (buf);
+#else
+	return 0;
+#endif
+}
+
+
+/* Here some functions we don't support, but which the other ports reference */
+int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+	return 0; 
+}
+int pckbd_getkeycode(unsigned int scancode) 
+{ 
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+	return 0; 
+}
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+		    char raw_mode) 
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+	return 0; 
+}
+char pckbd_unexpected_up(unsigned char keycode)
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+	return 0;
+}
+void pckbd_leds(unsigned char leds)
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+}
+void pckbd_init_hw(void)
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+}
+unsigned char pckbd_sysrq_xlate[128];
+
+struct pci_bus * __init pci_scan_peer_bridge(int bus)
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+	return NULL;
+}
 
 /*********************************************************** SETUP */
 /* From arch/m68k/kernel/setup.c. */
 void __init apus_setup_arch(unsigned long * memory_start_p,
 				unsigned long * memory_end_p)
 {
+#ifdef CONFIG_APUS
 	extern char cmd_line[];
 	int i;
 	char *p, *q;
 
+	/* Let m68k-shared code know it should do the Amiga thing. */
 	m68k_machtype = MACH_AMIGA;
 
 	/* Parse the command line for arch-specific options.
@@ -143,10 +297,46 @@
 	}
 
 	config_amiga();
+
+	{
+#define LOG_SIZE 4096
+		void* base;
+
+		/* Throw away some memory - the P5 firmare stomps on top
+		 * of CHIP memory during bootup.
+		 */
+		amiga_chip_alloc(0x1000);
+
+		base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t));
+		LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE);
+	}
+#endif
 }
 
+__apus
+int
+apus_get_cpuinfo(char *buffer)
+{
+#ifdef CONFIG_APUS
+	extern int __map_without_bats;
+	extern unsigned long powerup_PCI_present;
+	int len;
+
+	len = sprintf(buffer, "machine\t\t: Amiga\n");
+	len += sprintf(buffer+len, "bus speed\t: %d%s", __bus_speed,
+		       (__speed_test_failed) ? " [failed]\n" : "\n");
+	len += sprintf(buffer+len, "using BATs\t: %s\n",
+		       (__map_without_bats) ? "No" : "Yes");
+	len += sprintf(buffer+len, "ram speed\t: %dns\n", 
+		       (__60nsram) ? 60 : 70);
+	len += sprintf(buffer+len, "PCI bridge\t: %s\n",
+		       (powerup_PCI_present) ? "Yes" : "No");
+	return len;
+#endif
+}
 
-void get_current_tb(unsigned long long *time)
+__apus
+static void get_current_tb(unsigned long long *time)
 {
 	__asm __volatile ("1:mftbu 4      \n\t"
 			  "  mftb  5      \n\t"
@@ -161,14 +351,17 @@
 }
 
 
+__apus
 void apus_calibrate_decr(void)
 {
+#ifdef CONFIG_APUS
 	int freq, divisor;
 
 	/* This algorithm for determining the bus speed was
            contributed by Ralph Schmidt. */
 	unsigned long long start, stop;
 	int bus_speed;
+	int speed_test_failed = 0;
 
 	{
 		unsigned long loop = amiga_eclock / 10;
@@ -200,16 +393,23 @@
 			"Defaulting to 50MHz", bus_speed);
 		bus_speed = 50;
 		freq = 12500000;
+		speed_test_failed = 1;
 	}
 
 	/* Ease diagnostics... */
 	{
 		extern int __map_without_bats;
+		extern unsigned long powerup_PCI_present;
 
-		printk ("APUS: BATs=%d, BUS=%dMHz, RAM=%dns\n",
+		printk ("APUS: BATs=%d, BUS=%dMHz",
 			(__map_without_bats) ? 0 : 1,
-			bus_speed,
-			(__60nsram) ? 60 : 70);
+			bus_speed);
+		if (speed_test_failed)
+			printk ("[FAILED - please report]");
+
+		printk (", RAM=%dns, PCI bridge=%d\n",
+			(__60nsram) ? 60 : 70,
+			(powerup_PCI_present) ? 1 : 0);
 
 		/* print a bit more if asked politely... */
 		if (!(ciaa.pra & 0x40)){
@@ -232,25 +432,67 @@
         decrementer_count = freq / HZ / divisor;
         count_period_num = divisor;
         count_period_den = freq / 1000000;
+
+	__bus_speed = bus_speed;
+	__speed_test_failed = speed_test_failed;
+#endif
 }
 
+__apus
 void arch_gettod(int *year, int *mon, int *day, int *hour,
 		 int *min, int *sec)
 {
+#ifdef CONFIG_APUS
 	if (mach_gettod)
 		mach_gettod(year, mon, day, hour, min, sec);
 	else
 		*year = *mon = *day = *hour = *min = *sec = 0;
+#endif
+}
+
+/* for "kbd-reset" cmdline param */
+__init
+void kbd_reset_setup(char *str, int *ints)
+{
+}
+
+#if defined(CONFIG_WHIPPET_SERIAL)||defined(CONFIG_MULTIFACE_III_TTY)||defined(CONFIG_GVPIOEXT)||defined(CONFIG_AMIGA_BUILTIN_SERIAL)
+
+long m68k_rs_init(void);
+int m68k_register_serial(struct serial_struct *);
+void m68k_unregister_serial(int);
+long m68k_serial_console_init(long, long );
+
+int rs_init(void)
+{
+	return m68k_rs_init();
+}
+int register_serial(struct serial_struct *p)
+{
+	return m68k_register_serial(p);
+}
+void unregister_serial(int i)
+{
+	m68k_unregister_serial(i);
 }
+#ifdef CONFIG_SERIAL_CONSOLE
+long serial_console_init(long kmem_start, long kmem_end)
+{
+	return m68k_serial_console_init(kmem_start, kmem_end);
+}
+#endif
+#endif
 
 /*********************************************************** FLOPPY */
-#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
-void __init floppy_setup(char *str, int *ints)
+#if defined(CONFIG_AMIGA_FLOPPY)
+__init 
+void floppy_setup(char *str, int *ints)
 {
 	if (mach_floppy_setup)
 		mach_floppy_setup (str, ints);
 }
 
+__apus
 void floppy_eject(void)
 {
 	if (mach_floppy_eject)
@@ -259,44 +501,13 @@
 #endif
 
 /*********************************************************** MEMORY */
-extern void
-map_page(struct task_struct *tsk, unsigned long va,
-	 unsigned long pa, int flags);
-
-#define KMAP_MAX 8
-static unsigned long kmap_chunks[KMAP_MAX*3];
-static int kmap_chunk_count = 0;
-
-/* Based on arch/ppc/mm/init.c:ioremap() which maps the address range
-   to the same virtual address as the physical address - which may
-   cause problems since Z3 IO space is not the same as PCI/ISA.
-   This should be rewritten to something more like the m68k version. */
-unsigned long kernel_map (unsigned long phys_addr, unsigned long size,
-			  int cacheflag, unsigned long *memavailp)
-{
-	unsigned long v_ret, end;
-	/* Remap to 0x90000000. Related comment in ppc/mm/init.c. */
-	static unsigned long virt = 0x90000000;
-	v_ret = virt;
-
-	if (kmap_chunk_count == KMAP_MAX*3)
-		panic ("kernel_map: Can only map %d chunks.\n",
-		       KMAP_MAX);
-
-	kmap_chunks[kmap_chunk_count++] = phys_addr;
-	kmap_chunks[kmap_chunk_count++] = size;
-	kmap_chunks[kmap_chunk_count++] = v_ret;
-
-	for (end = phys_addr + size ; phys_addr < end; 
-	     phys_addr += PAGE_SIZE, virt += PAGE_SIZE) {
-		map_page(&init_task, virt, phys_addr,
-			 pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
-	}
-	return v_ret;
-}
+#define KMAP_MAX 32
+unsigned long kmap_chunks[KMAP_MAX*3] __apusdata;
+int kmap_chunk_count __apusdata = 0;
 
 /* From pgtable.h */
-extern __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va)
+__apus
+static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va)
 {
 	pgd_t *dir = 0;
 	pmd_t *pmd = 0;
@@ -318,10 +529,11 @@
 
 
 /* Again simulating an m68k/mm/kmap.c function. */
+__apus
 void kernel_set_cachemode( unsigned long address, unsigned long size,
 			   unsigned int cmode )
 {
-	int mask, flags;
+	unsigned long mask, flags;
 
 	switch (cmode)
 	{
@@ -360,6 +572,7 @@
 	}
 }
 
+__apus
 unsigned long mm_ptov (unsigned long paddr)
 {
 	unsigned long ret;
@@ -388,6 +601,7 @@
 	return ret;
 }
 
+__apus
 int mm_end_of_chunk (unsigned long addr, int len)
 {
 	if (memory[0].addr + memory[0].size == addr + len)
@@ -399,6 +613,7 @@
 
 #define L1_CACHE_BYTES 32
 #define MAX_CACHE_SIZE 8192
+__apus
 void cache_push(__u32 addr, int length)
 {
 	addr = mm_ptov(addr);
@@ -417,6 +632,8 @@
 	       "sync \n\t"
 	       : : "r" (addr));
 }
+
+__apus
 void cache_clear(__u32 addr, int length)
 {
 	if (MAX_CACHE_SIZE < length)
@@ -450,6 +667,7 @@
 	       : : "r" (addr));
 }
 
+/****************************************************** from setup.c */
 void
 apus_restart(char *cmd)
 {
@@ -478,37 +696,13 @@
    apus_restart(NULL);
 }
 
-void
-apus_do_IRQ(struct pt_regs *regs,
-	    int            cpu,
-            int            isfake)
-{
-        int old_level, new_level;
-
-	/* I don't think we need SMP code here - Corey */
-
-        old_level = ~(regs->mq) & IPLEMU_IPLMASK;
-        new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
-        if (new_level != 0)
-        {
-                APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
-                APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
-                                          | (~(new_level) & IPLEMU_IPLMASK)));
-                APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-
-                process_int (VEC_SPUR+new_level, regs);
-                APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
-                APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
-                APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
-                                          | (~(old_level) & IPLEMU_IPLMASK)));
-        }
-        APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-}
-
+/****************************************************** from setup.c/IDE */
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 /*
  * IDE stuff.
  */
+void ide_insw(ide_ioreg_t port, void *buf, int ns);
+void ide_outsw(ide_ioreg_t port, void *buf, int ns);
 void
 apus_ide_insw(ide_ioreg_t port, void *buf, int ns)
 {
@@ -524,13 +718,13 @@
 int
 apus_ide_default_irq(ide_ioreg_t base)
 {
-        m68k_ide_default_irq(base);
+        return m68k_ide_default_irq(base);
 }
 
 ide_ioreg_t
 apus_ide_default_io_base(int index)
 {
-        m68k_ide_default_io_base(index);
+        return 0;
 }
 
 int
@@ -560,25 +754,156 @@
         m68k_ide_fix_driveid(id);
 }
 
-void __init
-apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+__init
+void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, 
+			       ide_ioreg_t ctrl_port, int *irq)
 {
         m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
 }
 #endif
+/****************************************************** from irq.c */
+#define VEC_SPUR    (24)
 
-void __init
-apus_local_init_IRQ(void)
+void
+apus_do_IRQ(struct pt_regs *regs,
+	    int            cpu,
+            int            isfake)
 {
-	ppc_md.mask_irq = amiga_disable_irq;
-	ppc_md.unmask_irq = amiga_enable_irq;
-	apus_init_IRQ();
+	int old_level, new_level;
+
+	new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
+		
+	if (0 != new_level && 7 != new_level) {
+		old_level = ~(regs->mq) & IPLEMU_IPLMASK;
+
+		apus_process_int (VEC_SPUR+new_level, regs);
+		
+		APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
+		APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+		APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
+					  | (~(old_level) & IPLEMU_IPLMASK)));
+		APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+	}
 }
 
-void __init
-apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	  unsigned long r6, unsigned long r7)
+__apus
+static void apus_save_flags(unsigned long* flags)
 {
+	unsigned short __f;
+	APUS_READ(APUS_IPL_EMU, __f);
+	return ((~__f) & IPLEMU_IPLMASK) << 8;
+}
+
+__apus
+static void apus_restore_flags(unsigned long flags)
+{
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET
+                   | (~(flags >> 8) & IPLEMU_IPLMASK));
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+}
+
+__apus
+static void apus_sti(void)
+{
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+}
+
+__apus
+static void apus_cli(void)
+{
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+}
+
+/****************************************************** keyboard */
+__apus
+static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	return -EOPNOTSUPP;
+}
+
+__apus
+static int apus_kbd_getkeycode(unsigned int scancode)
+{
+	return scancode > 127 ? -EINVAL : scancode;
+}
+
+__apus
+static int apus_kbd_translate(unsigned char keycode, unsigned char *keycodep,
+			      char raw_mode)
+{
+	*keycodep = keycode;
+	return 1;
+}
+
+__apus
+static char apus_kbd_unexpected_up(unsigned char keycode)
+{
+	return 0200;
+}
+
+__apus  
+static void apus_kbd_leds(unsigned char leds)
+{
+}
+
+__apus  
+static void apus_kbd_init_hw(void)
+{
+#ifdef CONFIG_APUS
+	extern int amiga_keyb_init(void);
+
+printk("**** " __FUNCTION__ "\n");
+	amiga_keyb_init();
+#endif
+}
+
+
+/****************************************************** init */
+extern void amiga_disable_irq(unsigned int irq);
+extern void amiga_enable_irq(unsigned int irq);
+extern void m68k_init_IRQ (void);
+
+struct hw_interrupt_type amiga_irq_ctl = {
+	" Amiga    ",
+        NULL,
+        NULL,
+        NULL,
+        amiga_enable_irq,
+        amiga_disable_irq,
+        NULL,
+        0
+};
+
+__init
+void apus_init_IRQ(void)
+{
+	int i;
+
+	for (i = 0; i < NR_IRQS; i++)
+		irq_desc[i].ctl = &amiga_irq_ctl;
+	m68k_init_IRQ ();
+
+	int_control.int_sti = apus_sti;
+	int_control.int_cli = apus_cli;
+	int_control.int_save_flags = apus_save_flags;
+	int_control.int_restore_flags = apus_restore_flags;
+}
+
+__init
+void apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	       unsigned long r6, unsigned long r7)
+{
+	extern int parse_bootinfo(const struct bi_record *);
+	extern char _end[];
+	
 	/* Parse bootinfo. The bootinfo is located right after
            the kernel bss */
 	parse_bootinfo((const struct bi_record *)&_end);
@@ -591,9 +916,6 @@
 		initrd_end = (unsigned long) 
 			__va(ramdisk.size + ramdisk.addr);
 	}
-	/* Make sure code below is not executed. */
-	r4 = 0;
-	r6 = 0;
 #endif /* CONFIG_BLK_DEV_INITRD */
 
 	ISA_DMA_THRESHOLD = 0x00ffffff;
@@ -604,7 +926,10 @@
 	ppc_md.irq_cannonicalize = NULL;
 	ppc_md.init_IRQ       = apus_init_IRQ;
 	ppc_md.do_IRQ         = apus_do_IRQ;
-	ppc_md.get_irq_source = NULL;
+#ifdef CONFIG_HEARTBEAT
+	ppc_md.heartbeat      = apus_heartbeat;
+	ppc_md.heartbeat_count = 1;
+#endif
 	ppc_md.init           = NULL;
 
 	ppc_md.restart        = apus_restart;
@@ -616,24 +941,29 @@
 	ppc_md.get_rtc_time   = apus_get_rtc_time;
 	ppc_md.calibrate_decr = apus_calibrate_decr;
 
+	ppc_md.nvram_read_val = NULL;
+	ppc_md.nvram_write_val = NULL;
+
 	/* These should not be used for the APUS yet, since it uses
 	   the M68K keyboard now. */
-	ppc_md.kbd_setkeycode    = NULL;
-	ppc_md.kbd_getkeycode    = NULL;
-	ppc_md.kbd_translate     = NULL;
-	ppc_md.kbd_unexpected_up = NULL;
-	ppc_md.kbd_leds          = NULL;
-	ppc_md.kbd_init_hw       = NULL;
+	ppc_md.kbd_setkeycode    = apus_kbd_setkeycode;
+	ppc_md.kbd_getkeycode    = apus_kbd_getkeycode;
+	ppc_md.kbd_translate     = apus_kbd_translate;
+	ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up;
+	ppc_md.kbd_leds          = apus_kbd_leds;
+	ppc_md.kbd_init_hw       = apus_kbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
 	ppc_md.kbd_sysrq_xlate	 = NULL;
+#endif
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
         ppc_ide_md.insw = apus_ide_insw;
         ppc_ide_md.outsw = apus_ide_outsw;
         ppc_ide_md.default_irq = apus_ide_default_irq;
         ppc_ide_md.default_io_base = apus_ide_default_io_base;
-        ppc_ide_md.check_region = apus_ide_check_region;
-        ppc_ide_md.request_region = apus_ide_request_region;
-        ppc_ide_md.release_region = apus_ide_release_region;
+        ppc_ide_md.ide_check_region = apus_ide_check_region;
+        ppc_ide_md.ide_request_region = apus_ide_request_region;
+        ppc_ide_md.ide_release_region = apus_ide_release_region;
         ppc_ide_md.fix_driveid = apus_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports;
 
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- v2.3.19/linux/arch/ppc/kernel/chrp_pci.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/kernel/chrp_pci.c	Thu Oct  7 10:17:08 1999
@@ -354,7 +354,8 @@
                 else
                 {
 			if ( !strncmp("IBM,7043-150", get_property(find_path_device("/"), "name", NULL),12) ||
-			     !strncmp("IBM,7046-155", get_property(find_path_device("/"), "name", NULL),12) )
+			     !strncmp("IBM,7046-155", get_property(find_path_device("/"), "name", NULL),12) ||
+			     !strncmp("IBM,7046-B50", get_property(find_path_device("/"), "name", NULL),12) )
 			{
 				pci_dram_offset = 0;
 				isa_mem_base = 0x80000000;
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.3.19/linux/arch/ppc/kernel/chrp_setup.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/kernel/chrp_setup.c	Thu Oct  7 10:17:08 1999
@@ -33,6 +33,8 @@
 #include <linux/pci.h>
 #include <linux/openpic.h>
 #include <linux/version.h>
+#include <linux/adb.h>
+#include <linux/module.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -46,7 +48,6 @@
 #include <asm/dma.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
-#include <asm/adb.h>
 #include <asm/hydra.h>
 #include <asm/keyboard.h>
 
@@ -55,14 +56,6 @@
 #include "i8259.h"
 #include "open_pic.h"
 
-/* Fixme - need to move these into their own .c and .h file */
-extern void i8259_mask_and_ack_irq(unsigned int irq_nr);
-extern void i8259_set_irq_mask(unsigned int irq_nr);
-extern void i8259_mask_irq(unsigned int irq_nr);
-extern void i8259_unmask_irq(unsigned int irq_nr);
-extern void i8259_init(void);
-
-/* Fixme - remove this when it is fixed. - Corey */
 extern volatile unsigned char *chrp_int_ack_special;
 
 unsigned long chrp_get_rtc_time(void);
@@ -91,7 +84,6 @@
 extern void mackbd_init_hw(void);
 extern unsigned char mackbd_sysrq_xlate[128];
 
-/* for the mac fs */
 kdev_t boot_dev;
 
 extern PTE *Hash, *Hash_end;
@@ -185,12 +177,11 @@
 }
 
 /*
-     *  Fixes for the National Semiconductor PC78308VUL SuperI/O
-     *
-     *  Some versions of Open Firmware incorrectly initialize the IRQ settings
-     *  for keyboard and mouse
-     */
-
+ *  Fixes for the National Semiconductor PC78308VUL SuperI/O
+ *
+ *  Some versions of Open Firmware incorrectly initialize the IRQ settings
+ *  for keyboard and mouse
+ */
 static inline void __init sio_write(u8 val, u8 index)
 {
 	outb(index, 0x15c);
@@ -236,7 +227,7 @@
 
 
 void __init
-	   chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)
+chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
 	extern char cmd_line[];
 	struct device_node *device;
@@ -358,6 +349,46 @@
 	}
 }
 
+int chrp_get_irq( struct pt_regs *regs )
+{
+        int irq;
+
+        irq = openpic_irq( smp_processor_id() );
+        if (irq == IRQ_8259_CASCADE)
+        {
+                /*
+                 * This magic address generates a PCI IACK cycle.
+                 */
+		if ( chrp_int_ack_special )
+			irq = *chrp_int_ack_special;
+		else
+			irq = i8259_irq( smp_processor_id() );
+                /*
+                 * Acknowledge as soon as possible to allow i8259
+                 * interrupt nesting                         */
+                openpic_eoi( smp_processor_id() );
+        }
+        if (irq == OPENPIC_VEC_SPURIOUS)
+                /*
+                 * Spurious interrupts should never be
+                 * acknowledged
+                 */
+		irq = -1;
+	return irq;
+}
+
+void chrp_post_irq(int irq)
+{
+	/*
+	 * If it's an i8259 irq then we've already done the
+	 * openpic irq.  So we just check to make sure the controller
+	 * is an openpic and if it is then eoi -- Cort
+	 */
+	if ( irq_desc[irq].ctl == &open_pic )
+		openpic_eoi( smp_processor_id() );
+}
+
+#if 0
 void
 chrp_do_IRQ(struct pt_regs *regs,
 	    int            cpu,
@@ -432,9 +463,9 @@
         if (!openpic_eoi_done)
                 openpic_eoi(0);
 }
+#endif
 
-void __init
-	   chrp_init_IRQ(void)
+void __init chrp_init_IRQ(void)
 {
 	struct device_node *np;
 	int i;
@@ -465,11 +496,8 @@
 }
 
 void __init
-	   chrp_init2(void)
+chrp_init2(void)
 {
-	adb_init();
-
-	/* Should this be here? - Corey */
 	pmac_nvram_init();
 }
 
@@ -482,8 +510,9 @@
 ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
 ide_ioreg_t chrp_idedma_regbase;
 
-void chrp_ide_probe(void) {
-
+void
+chrp_ide_probe(void)
+{
         struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL);
 
         chrp_ide_ports_known = 1;
@@ -570,11 +599,12 @@
 		hw->irq = chrp_ide_irq;
 }
 
+#if defined(CONFIG_BLK_DEV_IDE_MODULE)
 EXPORT_SYMBOL(chrp_ide_irq);
 EXPORT_SYMBOL(chrp_ide_ports_known);
 EXPORT_SYMBOL(chrp_ide_regbase);
 EXPORT_SYMBOL(chrp_ide_probe);
-
+#endif
 #endif
 
 void __init
@@ -601,7 +631,8 @@
 	ppc_md.get_cpuinfo    = chrp_get_cpuinfo;
 	ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
 	ppc_md.init_IRQ       = chrp_init_IRQ;
-	ppc_md.do_IRQ         = chrp_do_IRQ;
+	ppc_md.get_irq        = chrp_get_irq;
+	ppc_md.post_irq	      = chrp_post_irq;
 		
 	ppc_md.init           = chrp_init2;
 
@@ -616,7 +647,7 @@
 
 #ifdef CONFIG_VT
 #ifdef CONFIG_MAC_KEYBOAD
-	if ( adb_hardware == ADB_NONE )
+	if (adb_driver == NULL)
 	{
 		ppc_md.kbd_setkeycode    = pckbd_setkeycode;
 		ppc_md.kbd_getkeycode    = pckbd_getkeycode;
@@ -678,7 +709,8 @@
 	if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0);
 }
 
-void chrp_progress(char *s, unsigned short hex)
+void
+chrp_progress(char *s, unsigned short hex)
 {
 	extern unsigned int rtas_data;
 	int max_width, width;
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S
--- v2.3.19/linux/arch/ppc/kernel/entry.S	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/entry.S	Thu Oct  7 10:17:08 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/entry.S
  *
- *  $Id: entry.S,v 1.3 1999/09/05 11:56:26 paulus Exp $
+ *  $Id: entry.S,v 1.4 1999/09/14 05:18:14 dmalek Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -26,6 +26,7 @@
 #include "ppc_asm.h"
 #include <asm/processor.h>
 #include <asm/page.h>
+#include <asm/mmu.h>
 #include <linux/errno.h>
 #include <linux/sys.h>
 #include <linux/config.h>
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c
--- v2.3.19/linux/arch/ppc/kernel/feature.c	Wed Mar 10 21:30:31 1999
+++ linux/arch/ppc/kernel/feature.c	Thu Oct  7 10:17:08 1999
@@ -41,7 +41,9 @@
 	OH_BAY_FLOPPY_ENABLE,	/* FEATURE_Mediabay_floppy_enable */
 	0,			/* FEATURE_BMac_reset */
 	0,			/* FEATURE_BMac_IO_enable */
-	0			/* FEATURE_Modem_Reset -> guess...*/
+	0,			/* FEATURE_Modem_Reset -> guess... */
+	OH_IDE_POWER,		/* FEATURE_IDE_DiskPower -> guess... */
+	OH_IDE_RESET		/* FEATURE_IDE_Reset (0 based) -> guess... */
 };
 
 /* assume these are the same as the ohare until proven otherwise */
@@ -63,7 +65,9 @@
 	OH_BAY_FLOPPY_ENABLE,	/* FEATURE_Mediabay_floppy_enable */
 	0x80000000,		/* FEATURE_BMac_reset */
 	0x60000000,		/* FEATURE_BMac_IO_enable */
-	0x02000000		/* FEATURE_Modem_Reset -> guess...*/
+	0x02000000,		/* FEATURE_Modem_Reset -> guess...*/
+	OH_IDE_POWER,		/* FEATURE_IDE_DiskPower -> guess... */
+	OH_IDE_RESET		/* FEATURE_IDE_Reset (0 based) -> guess... */
 };
 
 /* definition of a feature controller object */
@@ -191,9 +195,10 @@
 
 	save_flags(flags);
 	cli();
-	st_le32( controllers[controller].reg,
-		 ld_le32(controllers[controller].reg) |
+	out_le32( controllers[controller].reg,
+		 in_le32(controllers[controller].reg) |
 		 controllers[controller].bits[f]);
+	(void)in_le32(controllers[controller].reg);
 	restore_flags(flags);
 	udelay(10);
 	
@@ -220,9 +225,10 @@
 
 	save_flags(flags);
 	cli();
-	st_le32( controllers[controller].reg,
-		 ld_le32(controllers[controller].reg) &
+	out_le32( controllers[controller].reg,
+		 in_le32(controllers[controller].reg) &
 		 ~(controllers[controller].bits[f]));
+	(void)in_le32(controllers[controller].reg);
 	restore_flags(flags);
 	udelay(10);
 	
@@ -241,7 +247,7 @@
 	if (controller < 0)
 		return controller;
 	
-	return (ld_le32(controllers[controller].reg) &
+	return (in_le32(controllers[controller].reg) &
 		controllers[controller].bits[f]) != 0;
 }
 
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/gemini_pci.c linux/arch/ppc/kernel/gemini_pci.c
--- v2.3.19/linux/arch/ppc/kernel/gemini_pci.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/gemini_pci.c	Thu Oct  7 10:17:08 1999
@@ -244,7 +244,6 @@
 
 void __init gemini_pcibios_fixup(void)
 {
-	struct pci_bus *bus;
 	unsigned long orig_mem_base, orig_io_base;
 	
 	orig_mem_base = pci_mem_base;
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c
--- v2.3.19/linux/arch/ppc/kernel/gemini_setup.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/gemini_setup.c	Thu Oct  7 10:17:08 1999
@@ -53,6 +53,8 @@
 	0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
 };
 
+int chrp_get_irq(struct pt_regs *);
+void chrp_post_irq(int);		 
 
 static inline unsigned long _get_HID1(void)
 {
@@ -479,7 +481,7 @@
 void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5,
 			unsigned long r6, unsigned long r7)
 {
-	void chrp_do_IRQ(struct pt_regs *, int, int);
+	int chrp_get_irq( struct pt_regs * );
 	void layout_bus( struct pci_bus * );
  
 	gemini_setup_pci_ptrs();
@@ -501,7 +503,8 @@
 	ppc_md.get_cpuinfo = gemini_get_cpuinfo;
 	ppc_md.irq_cannonicalize = NULL;
 	ppc_md.init_IRQ = gemini_init_IRQ;
-	ppc_md.do_IRQ = chrp_do_IRQ;
+	ppc_md.get_irq = chrp_get_irq;
+	ppc_md.post_irq = chrp_post_irq;
 	ppc_md.init = NULL;
 
 	ppc_md.restart = gemini_restart;
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.3.19/linux/arch/ppc/kernel/head.S	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/head.S	Thu Oct  7 10:17:08 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.143 1999/09/05 11:56:28 paulus Exp $
+ *  $Id: head.S,v 1.147 1999/09/15 23:58:53 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -333,8 +333,12 @@
 	.long	ret_from_except
 
 /* System reset */
-#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */
+#ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */
+#ifdef CONFIG_GEMINI
+	STD_EXCEPTION(0x100, Reset, __secondary_start_gemini)
+#else /* CONFIG_GEMINI */
 	STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)
+#endif /* CONFIG_GEMINI */
 #else
 	STD_EXCEPTION(0x100, Reset, UnknownException)
 #endif
@@ -421,6 +425,8 @@
 	li	r20,MSR_KERNEL
 	li	r4,0
 	bl	transfer_to_handler
+	.globl do_IRQ_intercept
+do_IRQ_intercept:
 	.long	do_IRQ;
 	.long	ret_from_except
 	
@@ -461,7 +467,17 @@
 	.long	KernelFP
 	.long	ret_from_except
 
-	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+	. = 0x900
+Decrementer:
+	EXCEPTION_PROLOG
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	bl	transfer_to_handler
+	.globl timer_interrupt_intercept
+timer_interrupt_intercept:
+	.long	timer_interrupt
+	.long	ret_from_except
+
 	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
 	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
 
@@ -1011,6 +1027,20 @@
 	mr	r24,r3			/* cpu # */
 	blr
 
+	.globl	__secondary_start_gemini
+__secondary_start_gemini:
+1011:	b	1011b
+	
+        mfspr   r4,HID0
+        ori     r4,r4,HID0_ICFI
+        li      r3,0
+        ori     r3,r3,HID0_ICE
+        andc    r4,r4,r3
+        mtspr   HID0,r4
+        sync
+        bl      prom_init
+        b       __secondary_start
+	
 	.globl	__secondary_start_psurge
 __secondary_start_psurge:
 	li	r24,1			/* cpu # */
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S
--- v2.3.19/linux/arch/ppc/kernel/head_8xx.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/head_8xx.S	Thu Oct  7 10:17:08 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/except_8xx.S
  *
- *  $Id: head_8xx.S,v 1.2 1999/08/23 02:53:19 paulus Exp $
+ *  $Id: head_8xx.S,v 1.4 1999/09/18 18:43:19 dmalek Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -28,6 +28,8 @@
 #include <asm/page.h>
 #include <linux/config.h>
 #include <asm/mmu.h>
+#include <asm/cache.h>
+#include <asm/pgtable.h>
 	
 	.text
 	.globl	_stext
@@ -109,25 +111,19 @@
 	mtspr	MI_AP, r8
 	mtspr	MD_AP, r8
 
-/* We will get these from a configuration file as soon as I verify
- * the extraneous bits don't cause problems in the TLB.
- */
-#if defined(CONFIG_MBX) || defined(CONFIG_RPXLITE)
-#define BOOT_IMMR      0xfa000000
-#endif
-#ifdef CONFIG_BSEIP
-#define BOOT_IMMR      0xff000000
-#endif
-	/* Map another 8 MByte at 0xfa000000 to get the processor
+	/* Map another 8 MByte at the IMMR to get the processor
 	 * internal registers (among other things).
 	 */
-	lis     r8, BOOT_IMMR@h         /* Create vaddr for TLB */
+	mfspr	r9, 638			/* Get current IMMR */
+	andis.	r9, r9, 0xff80		/* Get 8Mbyte boundary */
+
+	mr	r8, r9			/* Create vaddr for TLB */
 	ori	r8, r8, MD_EVALID	/* Mark it valid */
 	mtspr	MD_EPN, r8
 	li	r8, MD_PS8MEG		/* Set 8M byte page */
 	ori	r8, r8, MD_SVALID	/* Make it valid */
 	mtspr	MD_TWC, r8
-	lis     r8, BOOT_IMMR@h         /* Create paddr for TLB */
+	mr	r8, r9			/* Create paddr for TLB */
 	ori	r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */
 	mtspr	MD_RPN, r8
 
@@ -301,6 +297,8 @@
 	li	r20,MSR_KERNEL
 	li	r4,0
 	bl	transfer_to_handler
+	.globl do_IRQ_intercept
+do_IRQ_intercept:
 	.long	do_IRQ;
 	.long	ret_from_except
 	
@@ -335,7 +333,17 @@
 */
 	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
 
-	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+	. = 0x900
+Decrementer:
+	EXCEPTION_PROLOG
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	bl	transfer_to_handler
+	.globl timer_interrupt_intercept
+timer_interrupt_intercept:
+	.long	timer_interrupt
+	.long	ret_from_except
+
 	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
 	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
 
@@ -553,7 +561,6 @@
 	mtcr	r21
 	lwz	r21, 4(r0)
 	b	DataAccess
-#endif /* CONFIG_8xx */
 
 	STD_EXCEPTION(0x1500, Trap_15, UnknownException)
 	STD_EXCEPTION(0x1600, Trap_16, UnknownException)
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/i8259.c linux/arch/ppc/kernel/i8259.c
--- v2.3.19/linux/arch/ppc/kernel/i8259.c	Tue May 11 08:24:32 1999
+++ linux/arch/ppc/kernel/i8259.c	Thu Oct  7 10:17:08 1999
@@ -96,7 +96,6 @@
         " i8259    ",
         NULL,
         NULL,
-        NULL,
         i8259_unmask_irq,
         i8259_mask_irq,
         i8259_mask_and_ack_irq,
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.3.19/linux/arch/ppc/kernel/idle.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/idle.c	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: idle.c,v 1.66 1999/09/05 11:56:30 paulus Exp $
+ * $Id: idle.c,v 1.67 1999/09/10 05:05:47 paulus Exp $
  *
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
@@ -73,7 +73,7 @@
  * SMP entry into the idle task - calls the same thing as the
  * non-smp versions. -- Cort
  */
-int cpu_idle()
+int cpu_idle(void)
 {
 	idled();
 	return 0; 
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/indirect_pci.c linux/arch/ppc/kernel/indirect_pci.c
--- v2.3.19/linux/arch/ppc/kernel/indirect_pci.c	Tue May 11 08:24:32 1999
+++ linux/arch/ppc/kernel/indirect_pci.c	Thu Oct  7 10:17:08 1999
@@ -19,7 +19,7 @@
 int indirect_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
 			     unsigned char offset, unsigned char *val)
 {
-	unsigned flags;
+	unsigned long flags;
 
 	save_flags(flags); cli();
 	
@@ -35,7 +35,7 @@
 int indirect_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
 			     unsigned char offset, unsigned short *val)
 {
-	unsigned flags;
+	unsigned long flags;
 	
 	if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
 
@@ -53,7 +53,7 @@
 int indirect_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
 			     unsigned char offset, unsigned int *val)
 {
-	unsigned flags;
+	unsigned long flags;
 	
 	if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
 
@@ -71,7 +71,7 @@
 int indirect_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
 			     unsigned char offset, unsigned char val)
 {
-	unsigned flags;
+	unsigned long flags;
 
 	save_flags(flags); cli();
 	
@@ -87,7 +87,7 @@
 int indirect_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
 			     unsigned char offset, unsigned short val)
 {
-	unsigned flags;
+	unsigned long flags;
 
 	if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
 
@@ -105,7 +105,7 @@
 int indirect_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
 			     unsigned char offset, unsigned int val)
 {
-	unsigned flags;
+	unsigned long flags;
 
 	if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
 
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.19/linux/arch/ppc/kernel/irq.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/irq.c	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: irq.c,v 1.109 1999/09/05 11:56:31 paulus Exp $
+ * $Id: irq.c,v 1.113 1999/09/17 17:22:56 cort Exp $
  *
  *  arch/ppc/kernel/irq.c
  *
@@ -79,8 +79,8 @@
 
 #define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
 
+struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
 int ppc_spurious_interrupts = 0;
-
 unsigned int ppc_local_bh_count[NR_CPUS];
 unsigned int ppc_local_irq_count[NR_CPUS];
 struct irqaction *ppc_irq_action[NR_IRQS];
@@ -124,9 +124,16 @@
 	kfree(ptr);
 }
 
-struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
-
+#ifndef CONFIG_8xx
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+#else
+/* Name change so we can catch standard drivers that potentially mess up
+ * the internal interrupt controller on 8xx and 82xx.  Just bear with me,
+ * I don't like this either and I am searching a better solution.  For
+ * now, this is what I need. -- Dan
+ */
+int request_8xxirq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+#endif
 	unsigned long irqflags, const char * devname, void *dev_id)
 {
 	struct irqaction *old, **p, *action;
@@ -186,7 +193,11 @@
 
 void free_irq(unsigned int irq, void *dev_id)
 {
+#ifndef CONFIG_8xx
 	request_irq(irq, NULL, 0, NULL, dev_id);
+#else
+	request_8xxirq(irq, NULL, 0, NULL, dev_id);
+#endif
 }
 
 /* XXX should implement irq disable depth like on intel */
@@ -277,12 +288,28 @@
 asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
 {
 	int cpu = smp_processor_id();
+	int irq;
+
+        hardirq_enter( cpu );
 
-        hardirq_enter(cpu);
-        ppc_md.do_IRQ(regs, cpu, isfake);
-        hardirq_exit(cpu);
+	/* every arch is required to have a get_irq -- Cort */
+	irq = ppc_md.get_irq( regs );
+	if ( irq < 0 )
+	{
+                printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+                       irq, regs->nip);
+                ppc_spurious_interrupts++;
+		return;
+	}
+	ppc_irq_dispatch_handler( regs, irq );
+	if ( ppc_md.post_irq )
+		ppc_md.post_irq( irq );
+	
+        hardirq_exit( cpu );
 }
 
+
+
 unsigned long probe_irq_on (void)
 {
 	return 0;
@@ -469,7 +496,7 @@
  */
 void __global_cli(void)
 {
-	unsigned int flags;
+	unsigned long flags;
 	
 	__save_flags(flags);
 	if (flags & (1 << 15)) {
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/local_irq.h linux/arch/ppc/kernel/local_irq.h
--- v2.3.19/linux/arch/ppc/kernel/local_irq.h	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/local_irq.h	Thu Oct  7 10:17:08 1999
@@ -4,28 +4,9 @@
 
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
+#include <asm/irq_control.h>
 
 void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
-
-/* Structure describing interrupts */
-struct hw_interrupt_type {
-	const char * typename;
-	void (*startup)(unsigned int irq);
-	void (*shutdown)(unsigned int irq);
-	void (*handle)(unsigned int irq, struct pt_regs * regs);
-	void (*enable)(unsigned int irq);
-	void (*disable)(unsigned int irq);
-	void (*mask_and_ack)(unsigned int irq);
-	int irq_offset;
-};
-
-struct irqdesc {
-	struct irqaction *action;
-	struct hw_interrupt_type *ctl;
-};
-
-extern struct irqdesc irq_desc[NR_IRQS];
-
 
 #define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
 
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c
--- v2.3.19/linux/arch/ppc/kernel/m8xx_setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/m8xx_setup.c	Thu Oct  7 10:17:08 1999
@@ -0,0 +1,521 @@
+/*
+ * $Id: m8xx_setup.c,v 1.4 1999/09/18 18:40:36 dmalek Exp $
+ *
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
+ *  Further modified for generic 8xx by Dan.
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include <asm/machdep.h>
+
+#include "time.h"
+#include "ppc8xx_pic.h"
+
+static int m8xx_set_rtc_time(unsigned long time);
+unsigned long m8xx_get_rtc_time(void);
+void m8xx_calibrate_decr(void);
+
+#if 0
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+#endif
+
+extern unsigned long loops_per_sec;
+
+unsigned char __res[sizeof(bd_t)];
+unsigned long empty_zero_page[1024];
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start;	/* starting block # of image */
+#endif
+
+extern char saved_command_line[256];
+
+extern unsigned long find_available_memory(void);
+extern void m8xx_cpm_reset(uint);
+
+void __init adbdev_init(void)
+{
+}
+
+void __init
+m8xx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+	int	cpm_page;
+	extern char cmd_line[];
+	
+	cpm_page = *memory_start_p;
+	*memory_start_p += PAGE_SIZE;
+	
+	printk("Boot arguments: %s\n", cmd_line);
+
+	/* Reset the Communication Processor Module.
+	*/
+	m8xx_cpm_reset(cpm_page);
+
+#ifdef notdef
+	ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+#endif
+	
+#ifdef CONFIG_BLK_DEV_INITRD
+#if 0
+	ROOT_DEV = to_kdev_t(0x0200); /* floppy */  
+	rd_prompt = 1;
+	rd_doload = 1;
+	rd_image_start = 0;
+#endif
+	/* initrd_start and size are setup by boot/head.S and kernel/head.S */
+	if ( initrd_start )
+	{
+		if (initrd_end > *memory_end_p)
+		{
+			printk("initrd extends beyond end of memory "
+			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+			       initrd_end,*memory_end_p);
+			initrd_start = 0;
+		}
+	}
+#endif
+}
+
+void
+abort(void)
+{
+#ifdef CONFIG_XMON
+	extern void xmon(void *);
+	xmon(0);
+#endif
+	machine_restart(NULL);
+}
+
+/* The decrementer counts at the system (internal) clock frequency divided by
+ * sixteen, or external oscillator divided by four.  We force the processor
+ * to use system clock divided by sixteen.
+ */
+void __init m8xx_calibrate_decr(void)
+{
+	bd_t	*binfo = (bd_t *)__res;
+	int freq, fp, divisor;
+
+	/* Unlock the SCCR.
+	*/
+	((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = ~KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = KAPWR_KEY;
+
+	/* Force all 8xx processors to use divide by 16 processor clock.
+	*/
+	((volatile immap_t *)IMAP_ADDR)->im_clkrst.car_sccr |= 0x02000000;
+
+	/* Processor frequency is MHz.
+	 * The value 'fp' is the number of decrementer ticks per second.
+	 */
+	fp = (binfo->bi_intfreq * 1000000) / 16;
+	freq = fp*60;	/* try to make freq/1e6 an integer */
+        divisor = 60;
+        printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+        decrementer_count = freq / HZ / divisor;
+        count_period_num = divisor;
+        count_period_den = freq / 1000000;
+}
+
+/* A place holder for time base interrupts, if they are ever enabled.
+*/
+void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+	printk("timebase_interrupt()\n");
+}
+
+/* The RTC on the MPC8xx is an internal register.
+ * We want to protect this during power down, so we need to unlock,
+ * modify, and re-lock.
+ */
+static int
+m8xx_set_rtc_time(unsigned long time)
+{
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
+	return(0);
+}
+
+unsigned long __init
+m8xx_get_rtc_time(void)
+{
+	/* First, unlock all of the registers we are going to modify.
+	 * To protect them from corruption during power down, registers
+	 * that are maintained by keep alive power are "locked".  To
+	 * modify these registers we have to write the key value to
+	 * the key location associated with the register.
+	 * Some boards power up with these unlocked, while others
+	 * are locked.  Writing anything (including the unlock code?)
+	 * to the unlocked registers will lock them again.  So, here
+	 * we guarantee the registers are locked, then we unlock them
+	 * for our use.
+	 */
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = ~KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = ~KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk = ~KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk = KAPWR_KEY;
+
+	/* Disable the RTC one second and alarm interrupts.
+	*/
+	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
+						~(RTCSC_SIE | RTCSC_ALE);
+
+	/* Enabling the decrementer also enables the timebase interrupts
+	 * (or from the other point of view, to get decrementer interrupts
+	 * we have to enable the timebase).  The decrementer interrupt
+	 * is wired into the vector table, nothing to do here for that.
+	 */
+	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
+				((mk_int_int_mask(DEC_INTERRUPT) << 8) |
+					 (TBSCR_TBF | TBSCR_TBE));
+	if (request_8xxirq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
+		panic("Could not allocate timer IRQ!");
+
+	/* Get time from the RTC.
+	*/
+	return((unsigned long)(((immap_t *)IMAP_ADDR)->im_sit.sit_rtc));
+}
+
+void
+m8xx_restart(char *cmd)
+{
+	extern void m8xx_gorom(void);
+
+	m8xx_gorom();
+}
+
+void
+m8xx_power_off(void)
+{
+   m8xx_restart(NULL);
+}
+
+void
+m8xx_halt(void)
+{
+   m8xx_restart(NULL);
+}
+
+
+int m8xx_setup_residual(char *buffer)
+{
+        int     len = 0;
+	bd_t	*bp;
+
+	bp = (bd_t *)__res;
+			
+	len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
+		       "bus clock\t: %dMHz\n",
+		       bp->bi_intfreq /*/ 1000000*/,
+		       bp->bi_busfreq /*/ 1000000*/);
+
+	return len;
+}
+
+/* Initialize the internal interrupt controller.  The number of
+ * interrupts supported can vary with the processor type, and the
+ * 82xx family can have up to 64.
+ * External interrupts can be either edge or level triggered, and
+ * need to be initialized by the appropriate driver.
+ */
+void __init
+m8xx_init_IRQ(void)
+{
+	int i;
+	void cpm_interrupt_init(void);
+
+        ppc8xx_pic.irq_offset = 0;
+        for ( i = 0 ; i < NR_SIU_INTS ; i++ )
+                irq_desc[i].ctl = &ppc8xx_pic;
+	
+	/* We could probably incorporate the CPM into the multilevel
+	 * interrupt structure.
+	 */
+	cpm_interrupt_init();
+        unmask_irq(CPM_INTERRUPT);
+
+#if defined(CONFIG_PCI)
+        for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ )
+                irq_desc[i].ctl = &i8259_pic;
+        i8259_pic.irq_offset = NR_SIU_INTS;
+        i8259_init();
+        request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
+        enable_irq(ISA_BRIDGE_INT);
+#endif
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+
+/* Define this to make a PCMCIA ATA Flash card work.
+*/
+#define ATA_FLASH 1
+
+/*
+ * IDE stuff.
+ */
+void
+m8xx_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+#ifdef ATA_FLASH
+	ide_insw(port, buf, ns);
+#else
+	ide_insw(port+_IO_BASE, buf, ns);
+#endif
+}
+
+void
+m8xx_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+#ifdef ATA_FLASH
+	ide_outsw(port, buf, ns);
+#else
+	ide_outsw(port+_IO_BASE, buf, ns);
+#endif
+}
+
+int
+m8xx_ide_default_irq(ide_ioreg_t base)
+{
+#ifdef ATA_FLASH
+	return PCMCIA_INTERRUPT;
+#else
+        return 14;
+#endif
+}
+
+ide_ioreg_t
+m8xx_ide_default_io_base(int index)
+{
+        return index;
+}
+
+int
+m8xx_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return 0;
+}
+
+void
+m8xx_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+}
+
+void
+m8xx_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+}
+
+int
+m8xx_ide_request_irq(unsigned int irq,
+		       void (*handler)(int, void *, struct pt_regs *),
+		       unsigned long flags, 
+		       const char *device,
+		       void *dev_id)
+{
+#ifdef ATA_FLASH
+	return request_8xxirq(irq, handler, flags, device, dev_id);
+#else
+	return request_irq(irq, handler, flags, device, dev_id);
+#endif
+}
+
+void
+m8xx_ide_fix_driveid(struct hd_driveid *id)
+{
+        ppc_generic_ide_fix_driveid(id);
+}
+
+/* We can use an external IDE controller or wire the IDE interface to
+ * the internal PCMCIA controller.
+ */
+void __init m8xx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+	ide_ioreg_t port = base;
+	int i;
+#ifdef ATA_FLASH
+	volatile pcmconf8xx_t	*pcmp;
+#endif
+
+#ifdef ATA_FLASH
+	*p = 0;
+	*irq = 0;
+
+	if (base != 0)		/* Only map the first ATA flash drive */
+		return;
+
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+	if (pcmp->pcmc_pipr & 0x18000000)
+		return;		/* No card in slot */
+
+	base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
+
+	/* For the M-Systems ATA card, the first 8 registers map 1:1.
+	 * The following register, control/Altstatus, is located at 0x0e.
+	 * Following that, the irq offset, is not used, so we place it in
+	 * an unused location, 0x0a.
+	 */
+	*p++ = base + 8;
+	for (i = 1; i < 8; ++i)
+		*p++ = base + i;
+	*p++ = base + 0x0e;		/* control/altstatus */
+	*p = base + 0x0a;		/* IRQ, not used */
+	if (irq)
+		*irq = PCMCIA_INTERRUPT;
+
+	/* Configure the interface for this interrupt.
+	*/
+	pcmp->pcmc_pgcra = (mk_int_int_mask(PCMCIA_INTERRUPT) << 24) |
+		(mk_int_int_mask(PCMCIA_INTERRUPT) << 16);
+
+	/* Enable status change interrupt from slot A.
+	*/
+	pcmp->pcmc_per = 0xff100000;
+	pcmp->pcmc_pscr = ~0;
+#else
+	
+	/* Just a regular IDE drive on some I/O port.
+	*/
+	i = 8;
+	while (i--)
+		*p++ = port++;
+	*p++ = base + 0x206;
+	if (irq != NULL)
+		*irq = 0;
+#endif
+}
+#endif
+
+void __init
+m8xx_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	 unsigned long r6, unsigned long r7)
+{
+
+	if ( r3 )
+		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+	
+#ifdef CONFIG_PCI
+	m8xx_setup_pci_ptrs();
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+	/* take care of cmd line */
+	if ( r6 )
+	{
+		
+		*(char *)(r7+KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6+KERNELBASE));
+	}
+
+	ppc_md.setup_arch     = m8xx_setup_arch;
+	ppc_md.setup_residual = m8xx_setup_residual;
+	ppc_md.get_cpuinfo    = NULL;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = m8xx_init_IRQ;
+	ppc_md.get_irq	      = m8xx_get_irq;
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = m8xx_restart;
+	ppc_md.power_off      = m8xx_power_off;
+	ppc_md.halt           = m8xx_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.set_rtc_time   = m8xx_set_rtc_time;
+	ppc_md.get_rtc_time   = m8xx_get_rtc_time;
+	ppc_md.calibrate_decr = m8xx_calibrate_decr;
+
+#if 0
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_pretranslate  = pckbd_pretranslate;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif
+#else
+	ppc_md.kbd_setkeycode    = NULL;
+	ppc_md.kbd_getkeycode    = NULL;
+	ppc_md.kbd_translate     = NULL;
+	ppc_md.kbd_unexpected_up = NULL;
+	ppc_md.kbd_leds          = NULL;
+	ppc_md.kbd_init_hw       = NULL;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = NULL;
+#endif
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = m8xx_ide_insw;
+        ppc_ide_md.outsw = m8xx_ide_outsw;
+        ppc_ide_md.default_irq = m8xx_ide_default_irq;
+        ppc_ide_md.default_io_base = m8xx_ide_default_io_base;
+        ppc_ide_md.check_region = m8xx_ide_check_region;
+        ppc_ide_md.request_region = m8xx_ide_request_region;
+        ppc_ide_md.release_region = m8xx_ide_release_region;
+        ppc_ide_md.fix_driveid = m8xx_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports;
+        ppc_ide_md.ide_request_irq = m8xx_ide_request_irq;
+
+        ppc_ide_md.io_base = _IO_BASE;
+#endif		
+}
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.3.19/linux/arch/ppc/kernel/misc.S	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/misc.S	Thu Oct  7 10:17:08 1999
@@ -45,17 +45,34 @@
 	mtlr	r0
 	blr
 
-_GLOBAL(__cli)
+/* void __no_use_save_flags(unsigned long *flags) */
+_GLOBAL(__no_use_save_flags)
+	mfmsr	r4
+	stw	r4,0(r3)
+	blr
+
+/* void __no_use_restore_flags(unsigned long flags) */	
+_GLOBAL(__no_use_restore_flags)
+	andi.	r4,r3,MSR_EE
+	bne	10f
+	lis	r4,ppc_n_lost_interrupts@ha
+	lwz	r4,ppc_n_lost_interrupts@l(r4)
+	cmpi	0,r4,0		/* lost interrupts to process first? */
+	bne-	do_lost_interrupts
+10:	sync
+	mtmsr	r3
+	isync
+	blr
+	
+_GLOBAL(__no_use_cli)
 	mfmsr	r0		/* Get current interrupt state */
 	rlwinm	r3,r0,16+1,32-1,31	/* Extract old value of 'EE' */
-	li	r4,0		/* Need [unsigned] value of MSR_EE */
-	ori	r4,r4,MSR_EE	/* Set to turn off bit */
-	andc	r0,r0,r4	/* Clears bit in (r4) */
+	rlwinm	r0,r0,0,17,15	/* clear MSR_EE in r0 */
 	sync			/* Some chip revs have problems here... */
 	mtmsr	r0		/* Update machine state */
 	blr			/* Done */
 
-_GLOBAL(__sti)
+_GLOBAL(__no_use_sti)
 	lis	r4,ppc_n_lost_interrupts@ha
 	lwz	r4,ppc_n_lost_interrupts@l(r4)
 	mfmsr	r3		/* Get current state */
@@ -472,6 +489,7 @@
  *
  *  ashrdi3:     XXXYYY/ZZZAAA -> SSSXXX/YYYZZZ
  *  ashldi3:     XXXYYY/ZZZAAA -> YYYZZZ/AAA000
+ *  lshrdi3:     XXXYYY/ZZZAAA -> 000XXX/YYYZZZ
  */
 _GLOBAL(__ashrdi3)
 	li	r6,32
@@ -481,7 +499,7 @@
 	or	r4,r4,r7	/* YYYZZZ */
 	sraw	r3,r3,r5	/* SSSXXX */
 	blr
-	
+
 _GLOBAL(__ashldi3)
 	li	r6,32
 	sub	r6,r6,r5
@@ -491,6 +509,15 @@
 	or	r3,r3,r7	/* YYYZZZ */
 	blr
 
+_GLOBAL(__lshrdi3)
+	li	r6,32
+	sub	r6,r6,r5
+	slw	r7,r3,r6        /* isolate YYY */
+	srw	r4,r4,r5        /* isolate ZZZ */
+	or	r4,r4,r7        /* YYYZZZ */
+	srw	r3,r3,r5        /* 000XXX */
+	blr
+
 _GLOBAL(abs)
 	cmpi	0,r3,0
 	bge	10f
@@ -553,36 +580,42 @@
 	Author:	Terry Greeniaus (tgree@phys.ualberta.ca)
 	Please e-mail updates to this file to me, thanks!
 */
+/* Usage:
+	
+	When setting the L2CR register, you must do a few special
+	things.  If you are enabling the cache, you must perform a
+	global invalidate.  If you are disabling the cache, you must
+	flush the cache contents first.  This routine takes care of
+	doing these things.  When first enabling the cache, make sure
+	you pass in the L2CR you want, as well as passing in the
+	global invalidate bit set.  A global invalidate will only be
+	performed if the L2I bit is set in applyThis.  When enabling
+	the cache, you should also set the L2E bit in applyThis.  If
+	you want to modify the L2CR contents after the cache has been
+	enabled, the recommended procedure is to first call
+	__setL2CR(0) to disable the cache and then call it again with
+	the new values for L2CR.  Examples:
+
+	_setL2CR(0)		- disables the cache
+	_setL2CR(0xB3A04000)	- enables my G3 upgrade card:
+				- L2E set to turn on the cache
+				- L2SIZ set to 1MB
+				- L2CLK set to 1:1
+				- L2RAM set to pipelined synchronous late-write
+				- L2I set to perform a global invalidation
+				- L2OH set to 0.5 nS
+				- L2DF set because this upgrade card
+				  requires it
+
+	A similar call should work for your card.  You need to know
+	the correct setting for your card and then place them in the
+	fields I have outlined above.  Other fields support optional
+	features, such as L2DO which caches only data, or L2TS which
+	causes cache pushes from the L1 cache to go to the L2 cache
+	instead of to main memory.
+*/
 
 _GLOBAL(_set_L2CR)
-	/* Usage:
-	
-		When setting the L2CR register, you must do a few special things.  If you are enabling the
-		cache, you must perform a global invalidate.  If you are disabling the cache, you must
-		flush the cache contents first.  This routine takes care of doing these things.  When first
-		enabling the cache, make sure you pass in the L2CR you want, as well as passing in the
-		global invalidate bit set.  A global invalidate will only be performed if the L2I bit is set
-		in applyThis.  When enabling the cache, you should also set the L2E bit in applyThis.  If you
-		want to modify the L2CR contents after the cache has been enabled, the recommended
-		procedure is to first call __setL2CR(0) to disable the cache and then call it again with
-		the new values for L2CR.  Examples:
-	
-			_setL2CR(0)			-	disables the cache
-			_setL2CR(0xB3A04000)		-	enables my G3 upgrade card:
-							-	L2E set to turn on the cache
-							-	L2SIZ set to 1MB
-							-	L2CLK set to 1:1
-							-	L2RAM set to pipelined syncronous late-write
-							-	L2I set to perform a global invalidation
-							-	L2OH set to 0.5 nS
-							-	L2DF set because this upgrade card requires it
-	
-		A similar call should work for your card.  You need to know the correct setting for your
-		card and then place them in the fields I have outlined above.  Other fields support optional
-		features, such as L2DO which caches only data, or L2TS which causes cache pushes from
-		the L1 cache to go to the L2 cache instead of to main memory.
-	*/
-	
 	/* Make sure this is a 750 chip */
 	mfspr	r4,PVR
 	rlwinm	r4,r4,16,16,31
@@ -594,76 +627,74 @@
 thisIs750:
 	/* Get the current enable bit of the L2CR into r4 */
 	mfspr	r4,L2CR
-	rlwinm	r4,r4,0,0,0
+	mfmsr	r7
 	
 	/* See if we want to perform a global inval this time. */
-	rlwinm	r6,r3,0,10,10		/* r6 contains the new invalidate bit */
-	rlwinm.	r5,r3,0,0,0		/* r5 contains the new enable bit */
-	rlwinm	r3,r3,0,11,9		/* Turn off the invalidate bit */
-	rlwinm	r3,r3,0,1,31		/* Turn off the enable bit */
-	or	r3,r3,r4		/* Keep the enable bit the same as it was for now. */
-	bne	dontDisableCache	/* Only disable the cache if L2CRApply has the enable bit off */
+	rlwinm	r6,r3,0,10,10	/* r6 contains the new invalidate bit */
+	rlwinm.	r5,r3,0,0,0	/* r5 contains the new enable bit */
+	rlwinm	r3,r3,0,11,9	/* Turn off the invalidate bit */
+	rlwimi	r3,r4,0,0,0	/* Keep the enable bit the same as it was. */
+	bne	dontDisableCache /* Only disable the cache if L2CRApply
+				    has the enable bit off */
 
 disableCache:
-	/* Disable the cache.  First, we turn off data relocation. */
-	mfmsr	r7
-	rlwinm	r4,r7,0,28,26		/* Turn off DR bit */
-	rlwinm	r4,r4,0,17,15		/* Turn off EE bit - an external exception while we are flushing
-					   the cache is fatal (comment this line and see!) */
+	/* Disable the cache.  First, we turn off interrupts.
+	   An interrupt while we are flushing the cache could bring
+	   in data which may not get properly flushed. */
+	rlwinm	r4,r7,0,17,15	/* Turn off EE bit */
 	sync
 	mtmsr	r4
 	sync
 	
-	/*
-		Now, read the first 2MB of memory to put new data in the cache.
-		(Actually we only need the size of the L2 cache plus
-		the size of the L1 cache, but 2MB will cover everything just to be safe).
-	*/
+/*
+	Now, read the first 2MB of memory to put new data in the cache.
+	(Actually we only need the size of the L2 cache plus the size
+	of the L1 cache, but 2MB will cover everything just to be safe).
+*/
 	lis	r4,0x0001
 	mtctr	r4
-	li	r4,0
-loadLoop:
-	lwzx	r0,r0,r4
+	lis	r4,KERNELBASE@h
+1:	lwzx	r0,r0,r4
 	addi	r4,r4,0x0020		/* Go to start of next cache line */
-	bdnz	loadLoop
+	bdnz	1b
 	
 	/* Now, flush the first 2MB of memory */
 	lis	r4,0x0001
 	mtctr	r4
-	li	r4,0
+	lis	r4,KERNELBASE@h
 	sync
-flushLoop:
-	dcbf	r0,r4
+2:	dcbf	r0,r4
 	addi	r4,r4,0x0020	/* Go to start of next cache line */
-	bdnz	flushLoop
+	bdnz	2b
 	
 	/* Turn off the L2CR enable bit. */
 	rlwinm	r3,r3,0,1,31
 	
-	/* Reenable data relocation. */
-	sync
-	mtmsr	r7
-	sync
-	
 dontDisableCache:
 	/* Set up the L2CR configuration bits */
 	sync
 	mtspr	L2CR,r3
 	sync
+
+	/* Reenable interrupts if necessary. */
+	mtmsr	r7
+	sync
+	
 	cmplwi	r6,0
 	beq	noInval
 	
 	/* Perform a global invalidation */
 	oris	r3,r3,0x0020
 	sync
-	mtspr	1017,r3
+	mtspr	L2CR,r3
 	sync
-invalCompleteLoop:			/* Wait for the invalidation to complete */
-	mfspr	r3,1017
+
+	/* Wait for the invalidation to complete */
+3:	mfspr	r3,L2CR
 	rlwinm.	r4,r3,0,31,31
-	bne	invalCompleteLoop
+	bne	3b
 	
-	rlwinm	r3,r3,0,11,9;		/* Turn off the L2I bit */
+	rlwinm	r3,r3,0,11,9		/* Turn off the L2I bit */
 	sync
 	mtspr	L2CR,r3
 	sync
@@ -672,8 +703,7 @@
 	/* See if we need to enable the cache */
 	cmplwi	r5,0
 	beqlr
-	
-enableCache:
+
 	/* Enable the cache */
 	oris	r3,r3,0x8000
 	mtspr	L2CR,r3
@@ -967,7 +997,7 @@
 	.long sys_getresuid	/* 165 */
 	.long sys_query_module
 	.long sys_poll
-#ifdef CONFIG_NFSD	
+#ifdef CONFIG_NFSD
 	.long sys_nfsservctl
 #else
 	.long sys_ni_syscall
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c
--- v2.3.19/linux/arch/ppc/kernel/open_pic.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/open_pic.c	Thu Oct  7 10:17:08 1999
@@ -33,7 +33,6 @@
 	" OpenPIC  ",
 	NULL,
 	NULL,
-	NULL,
 	openpic_enable_irq,
 	openpic_disable_irq,
 	0,
@@ -352,6 +351,13 @@
 	openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask);
 }
 
+void openpic_enable_IPI(u_int ipi)
+{
+	check_arg_ipi(ipi);
+	openpic_clearfield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
+			   OPENPIC_MASK);
+}
+
 /*
  *  Initialize a timer interrupt (and disable it)
  *
@@ -384,13 +390,13 @@
 void openpic_enable_irq(u_int irq)
 {
 	check_arg_irq(irq);
-	openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+	openpic_clearfield(&OpenPIC->Source[irq-irq_desc[irq].ctl->irq_offset].Vector_Priority, OPENPIC_MASK);
 }
 
 void openpic_disable_irq(u_int irq)
 {
 	check_arg_irq(irq);
-	openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+	openpic_setfield(&OpenPIC->Source[irq-irq_desc[irq].ctl->irq_offset].Vector_Priority, OPENPIC_MASK);
 }
 
 /*
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.3.19/linux/arch/ppc/kernel/pci.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/pci.c	Thu Oct  7 12:23:21 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: pci.c,v 1.60 1999/09/08 03:04:07 cort Exp $
+ * $Id: pci.c,v 1.64 1999/09/17 18:01:53 cort Exp $
  * Common pmac/prep/chrp pci routines. -- Cort
  */
 
@@ -92,7 +92,7 @@
 				struct resource *pr;
 				if (!r->start)
 					continue;
-				pr = pci_find_parent_resource(dev, r);
+				pr = pci_find_parent_resource(dev, r, 0);
 				if (!pr || request_resource(pr, r) < 0)
 				{
 					printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name);
@@ -117,7 +117,7 @@
 	return str;
 }
 
-#ifndef CONFIG_MBX
+#ifndef CONFIG_8xx
 /* Recursively searches any node that is of type PCI-PCI bridge. Without
  * this, the old code would miss children of P2P bridges and hence not
  * fix IRQ's for cards located behind P2P bridges.
@@ -141,8 +141,3 @@
 	}
 }
 #endif
-
-int pcibios_assign_resource(struct pci_dev *pdev, int resource)
-{
-	return 0;
-}
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- v2.3.19/linux/arch/ppc/kernel/pmac_pic.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/pmac_pic.c	Thu Oct  7 10:17:08 1999
@@ -102,7 +102,6 @@
         " PMAC-PIC ",
         NULL,
         NULL,
-        NULL,
         pmac_unmask_irq,
         pmac_mask_irq,
         pmac_mask_and_ack_irq,
@@ -113,7 +112,6 @@
 	" GATWICK  ",
 	NULL,
 	NULL,
-	NULL,
 	pmac_unmask_irq,
 	pmac_mask_irq,
 	pmac_mask_and_ack_irq,
@@ -143,6 +141,7 @@
 		ppc_irq_dispatch_handler( regs, irq );
 }
 
+#if 0
 void
 pmac_do_IRQ(struct pt_regs *regs,
 	    int            cpu,
@@ -155,19 +154,13 @@
         /* IPI's are a hack on the powersurge -- Cort */
         if ( cpu != 0 )
         {
-                if (!isfake)
-                {
 #ifdef CONFIG_XMON
-                        static int xmon_2nd;
-                        if (xmon_2nd)
-                                xmon(regs);
+		static int xmon_2nd;
+		if (xmon_2nd)
+			xmon(regs);
 #endif
-                        smp_message_recv();
-                        goto out;
-                }
-                /* could be here due to a do_fake_interrupt call but we don't
-                   mess with the controller from the second cpu -- Cort */
-                goto out;
+		smp_message_recv();
+		return -1;
         }
 
         {
@@ -214,11 +207,65 @@
 out:
 #endif /* CONFIG_SMP */
 }
+#endif
+
+int
+pmac_get_irq(struct pt_regs *regs)
+{
+	int irq;
+	unsigned long bits = 0;
+
+#ifdef __SMP__
+        /* IPI's are a hack on the powersurge -- Cort */
+        if ( smp_processor_id() != 0 )
+        {
+#ifdef CONFIG_XMON
+		static int xmon_2nd;
+		if (xmon_2nd)
+			xmon(regs);
+#endif
+		smp_message_recv();
+		return -1;
+        }
+
+        {
+                unsigned int loops = MAXCOUNT;
+                while (test_bit(0, &global_irq_lock)) {
+                        if (smp_processor_id() == global_irq_holder) {
+                                printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                                break;
+                        }
+                        if (loops-- == 0) {
+                                printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                        }
+                }
+        }
+#endif /* __SMP__ */
+
+        for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
+                int i = irq >> 5;
+                bits = ld_le32(&pmac_irq_hw[i]->flag)
+                        | ppc_lost_interrupts[i];
+                if (bits == 0)
+                        continue;
+                irq -= cntlzw(bits);
+                break;
+        }
+
+	return irq;
+}
 
 /* This routine will fix some missing interrupt values in the device tree
  * on the gatwick mac-io controller used by some PowerBooks
  */
-static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+static void __init
+pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
 {
 	struct device_node *node;
 	int count;
@@ -362,3 +409,41 @@
 	request_irq(20, xmon_irq, 0, "NMI - XMON", 0);
 #endif	/* CONFIG_XMON */
 }
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * These procedures are used in implementing sleep on the powerbooks.
+ * sleep_save_intrs() saves the states of all interrupt enables
+ * and disables all interupts except for the nominated one.
+ * sleep_restore_intrs() restores the states of all interrupt enables.
+ */
+unsigned int sleep_save_mask[2];
+
+void
+sleep_save_intrs(int viaint)
+{
+	sleep_save_mask[0] = ppc_cached_irq_mask[0];
+	sleep_save_mask[1] = ppc_cached_irq_mask[1];
+	ppc_cached_irq_mask[0] = 0;
+	ppc_cached_irq_mask[1] = 0;
+	set_bit(viaint, ppc_cached_irq_mask);
+	out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
+	if (max_real_irqs > 32)
+		out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
+	mb();
+}
+
+void
+sleep_restore_intrs(void)
+{
+	int i;
+
+	out_le32(&pmac_irq_hw[0]->enable, 0);
+	if (max_real_irqs > 32)
+		out_le32(&pmac_irq_hw[1]->enable, 0);
+	mb();
+	for (i = 0; i < max_real_irqs; ++i)
+		if (test_bit(i, sleep_save_mask))
+			pmac_unmask_irq(i);
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/pmac_pic.h linux/arch/ppc/kernel/pmac_pic.h
--- v2.3.19/linux/arch/ppc/kernel/pmac_pic.h	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/pmac_pic.h	Thu Oct  7 10:17:08 1999
@@ -6,10 +6,7 @@
 extern struct hw_interrupt_type pmac_pic;
 
 void pmac_pic_init(void);
-void pmac_do_IRQ(struct pt_regs *regs,
-                 int            cpu,
-                 int            isfake);
-
+int pmac_get_irq(struct pt_regs *regs);
+void pmac_post_irq(int);
 
 #endif /* _PPC_KERNEL_PMAC_PIC_H */
-
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.3.19/linux/arch/ppc/kernel/pmac_setup.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/pmac_setup.c	Thu Oct  7 10:17:08 1999
@@ -43,6 +43,9 @@
 #include <linux/console.h>
 #include <linux/ide.h>
 #include <linux/pci.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
 
 #include <asm/init.h>
 #include <asm/prom.h>
@@ -51,9 +54,6 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/pci-bridge.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
-#include <asm/pmu.h>
 #include <asm/ohare.h>
 #include <asm/mediabay.h>
 #include <asm/feature.h>
@@ -166,16 +166,24 @@
 	/* find ram info */
 	np = find_devices("memory");
 	if (np != 0) {
+		int n;
 		struct reg_property *reg = (struct reg_property *)
-			get_property(np, "reg", NULL);
+			get_property(np, "reg", &n);
+		
 		if (reg != 0) {
-			len += sprintf(buffer+len, "memory\t\t: %dMB\n",
-				       reg->size >> 20);
+			unsigned long total = 0;
+
+			for (n /= sizeof(struct reg_property); n > 0; --n)
+				total += (reg++)->size;
+			len += sprintf(buffer+len, "memory\t\t: %luMB\n",
+				       total >> 20);
 		}
 	}
 
 	/* Checks "l2cr-value" property in the registry */
 	np = find_devices("cpus");		
+	if (np == 0)
+		np = find_type_devices("cpu");		
 	if (np != 0) {
 		unsigned int *l2cr = (unsigned int *)
 			get_property(np, "l2cr-value", NULL);
@@ -267,6 +275,8 @@
 	/* Checks "l2cr-value" property in the registry */
 	if ( (_get_PVR() >> 16) == 8) {
 		struct device_node *np = find_devices("cpus");		
+		if (np == 0)
+			np = find_type_devices("cpu");		
 		if (np != 0) {
 			unsigned int *l2cr = (unsigned int *)
 				get_property(np, "l2cr-value", NULL);
@@ -290,8 +300,12 @@
 	zs_kgdb_hook(0);
 #endif
 
+#ifdef CONFIG_ADB_CUDA
 	find_via_cuda();
+#endif	
+#ifdef CONFIG_ADB_PMU
 	find_via_pmu();
+#endif	
 
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
@@ -360,9 +374,10 @@
 void __init
 pmac_init2(void)
 {
-	adb_init();
 	pmac_nvram_init();
+#ifdef CONFIG_PMAC_PBOOK	
 	media_bay_init();
+#endif	
 }
 
 #ifdef CONFIG_SCSI
@@ -470,19 +485,24 @@
 void
 pmac_restart(char *cmd)
 {
+#ifdef CONFIG_ADB_CUDA
 	struct adb_request req;
+#endif /* CONFIG_ADB_CUDA */
 
-	switch (adb_hardware) {
-	case ADB_VIACUDA:
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
 		cuda_request(&req, NULL, 2, CUDA_PACKET,
 			     CUDA_RESET_SYSTEM);
 		for (;;)
 			cuda_poll();
 		break;
-
-	case ADB_VIAPMU:
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU		
+	case SYS_CTRLER_PMU:
 		pmu_restart();
 		break;
+#endif /* CONFIG_ADB_PMU */		
 	default:
 	}
 }
@@ -490,19 +510,24 @@
 void
 pmac_power_off(void)
 {
+#ifdef CONFIG_ADB_CUDA
 	struct adb_request req;
+#endif /* CONFIG_ADB_CUDA */
 
-	switch (adb_hardware) {
-	case ADB_VIACUDA:
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
 		cuda_request(&req, NULL, 2, CUDA_PACKET,
 			     CUDA_POWERDOWN);
 		for (;;)
 			cuda_poll();
 		break;
-
-	case ADB_VIAPMU:
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU:
 		pmu_shutdown();
 		break;
+#endif /* CONFIG_ADB_PMU */
 	default:
 	}
 }
@@ -609,7 +634,7 @@
 	ppc_md.get_cpuinfo    = pmac_get_cpuinfo;
 	ppc_md.irq_cannonicalize = NULL;
 	ppc_md.init_IRQ       = pmac_pic_init;
-	ppc_md.do_IRQ         = pmac_do_IRQ;
+	ppc_md.get_irq        = pmac_get_irq;
 	ppc_md.init           = pmac_init2;
 
 	ppc_md.restart        = pmac_restart;
@@ -621,7 +646,7 @@
 	ppc_md.get_rtc_time   = pmac_get_rtc_time;
 	ppc_md.calibrate_decr = pmac_calibrate_decr;
 
-#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD)
+#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD)
 	ppc_md.kbd_setkeycode    = mackbd_setkeycode;
 	ppc_md.kbd_getkeycode    = mackbd_getkeycode;
 	ppc_md.kbd_translate     = mackbd_translate;
@@ -648,4 +673,3 @@
         ppc_ide_md.io_base = _IO_BASE;	/* actually too early for this :-( */
 #endif		
 }
-
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c
--- v2.3.19/linux/arch/ppc/kernel/pmac_support.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/pmac_support.c	Thu Oct  7 10:17:08 1999
@@ -12,8 +12,8 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/prom.h>
-#include <asm/adb.h>
-#include <asm/pmu.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
 
 /*
  * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
@@ -47,7 +47,7 @@
 	} else if (nvram_naddrs == 2) {
 		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
 		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
-	} else if (nvram_naddrs == 0 && adb_hardware == ADB_VIAPMU) {
+	} else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
 		nvram_naddrs = -1;
 	} else {
 		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
@@ -55,6 +55,7 @@
 	}
 }
 
+#ifdef CONFIG_NVRAM
 unsigned char nvram_read_byte(int addr)
 {
 	struct adb_request req;
@@ -100,3 +101,4 @@
 	}
 	eieio();
 }
+#endif /* CONFIG_NVRAM */
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c
--- v2.3.19/linux/arch/ppc/kernel/pmac_time.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/pmac_time.c	Thu Oct  7 10:17:08 1999
@@ -15,11 +15,11 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
 
 #include <asm/init.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
-#include <asm/pmu.h>
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -55,11 +55,14 @@
 
 unsigned long pmac_get_rtc_time(void)
 {
+#ifdef CONFIG_ADB
 	struct adb_request req;
+#endif
 
 	/* Get the time from the RTC */
-	switch (adb_hardware) {
-	case ADB_VIACUDA:
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
 		if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
 			return 0;
 		while (!req.complete)
@@ -69,7 +72,9 @@
 			       req.reply_len);
 		return (req.reply[3] << 24) + (req.reply[4] << 16)
 			+ (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
-	case ADB_VIAPMU:
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU:
 		if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
 			return 0;
 		while (!req.complete)
@@ -79,6 +84,7 @@
 			       req.reply_len);
 		return (req.reply[1] << 24) + (req.reply[2] << 16)
 			+ (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET;
+#endif /* CONFIG_ADB_PMU */
 	default:
 		return 0;
 	}
@@ -141,13 +147,12 @@
 /*
  * Reset the time after a sleep.
  */
-static int time_sleep_notify(struct notifier_block *this, unsigned long event,
-			     void *x)
+static int time_sleep_notify(struct pmu_sleep_notifier *self, int when)
 {
 	static unsigned long time_diff;
 
-	switch (event) {
-	case PBOOK_SLEEP:
+	switch (when) {
+	case PBOOK_SLEEP_NOW:
 		time_diff = xtime.tv_sec - pmac_get_rtc_time();
 		break;
 	case PBOOK_WAKE:
@@ -157,11 +162,11 @@
 		last_rtc_update = xtime.tv_sec;
 		break;
 	}
-	return NOTIFY_DONE;
+	return PBOOK_SLEEP_OK;
 }
 
-static struct notifier_block time_sleep_notifier = {
-	time_sleep_notify, NULL, 100
+static struct pmu_sleep_notifier time_sleep_notifier = {
+	time_sleep_notify, SLEEP_LEVEL_MISC,
 };
 #endif /* CONFIG_PMAC_PBOOK */
 
@@ -176,7 +181,7 @@
 	int freq, *fp, divisor;
 
 #ifdef CONFIG_PMAC_PBOOK
-	notifier_chain_register(&sleep_notifier_list, &time_sleep_notifier);
+	pmu_register_sleep_notifier(&time_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 
 	if (via_calibrate_decr())
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/ppc8xx_pic.c linux/arch/ppc/kernel/ppc8xx_pic.c
--- v2.3.19/linux/arch/ppc/kernel/ppc8xx_pic.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/ppc8xx_pic.c	Thu Oct  7 10:17:08 1999
@@ -5,45 +5,170 @@
 #include <linux/signal.h>
 #include <asm/irq.h>
 #include <asm/8xx_immap.h>
-#include <asm/mbx.h>
+#include <asm/mpc8xx.h>
 #include "ppc8xx_pic.h"
 
+/* The 8xx or 82xx internal interrupt controller.  It is usually
+ * the only interrupt controller.  Some boards, like the MBX and
+ * Sandpoint have the 8259 as a secondary controller.  Depending
+ * upon the processor type, the internal controller can have as
+ * few as 16 interrups or as many as 64.  We could use  the
+ * "clear_bit()" and "set_bit()" functions like other platforms,
+ * but they are overkill for us.
+ */
 
-static void mbx_mask_irq(unsigned int irq_nr)
+static void m8xx_mask_irq(unsigned int irq_nr)
 {
-	if ( irq_nr == ISA_BRIDGE_INT ) return;
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	ppc_cached_irq_mask[0] &= ~(1 << (31-irq_nr));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	ppc_cached_irq_mask[0];
+	int	bit, word;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
+#ifdef CONFIG_82xx
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] =
+						ppc_cached_irq_mask[word];
+#else
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
+						ppc_cached_irq_mask[word];
+#endif
 }
 
-static void mbx_unmask_irq(unsigned int irq_nr)
+static void m8xx_unmask_irq(unsigned int irq_nr)
 {
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	ppc_cached_irq_mask[0] |= (1 << (31-irq_nr));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	ppc_cached_irq_mask[0];
+	int	bit, word;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] |= (1 << (31-bit));
+#ifdef CONFIG_82xx
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] =
+						ppc_cached_irq_mask[word];
+#else
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
+						ppc_cached_irq_mask[word];
+#endif
 }
 
-static void mbx_mask_and_ack(unsigned int irq_nr)
+static void m8xx_mask_and_ack(unsigned int irq_nr)
 {
-	/* this shouldn't be masked, we mask the 8259 if we need to -- Cort */
-	if ( irq_nr != ISA_BRIDGE_INT )
-		mbx_mask_irq(irq_nr);
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	/* clear the pending bits */
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr);
+	int	bit, word;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
+#ifdef CONFIG_82xx
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] =
+						ppc_cached_irq_mask[word];
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend[word] = 1 << (31-bit);
+#else
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
+						ppc_cached_irq_mask[word];
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit);
+#endif
 }
 
 struct hw_interrupt_type ppc8xx_pic = {
 	" 8xx SIU  ",
 	NULL,
 	NULL,
-	NULL,
-	mbx_unmask_irq,
-	mbx_mask_irq,
-	mbx_mask_and_ack,
+	m8xx_unmask_irq,
+	m8xx_mask_irq,
+	m8xx_mask_and_ack,
 	0
 };
+
+#if 0
+void
+m8xx_do_IRQ(struct pt_regs *regs,
+	   int            cpu,
+           int            isfake)
+{
+	int irq;
+        unsigned long bits = 0;
+
+        /* For MPC8xx, read the SIVEC register and shift the bits down
+         * to get the irq number.         */
+        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
+        irq = bits >> 26;
+#if 0
+        irq += ppc8xx_pic.irq_offset;
+#endif
+        bits = 1UL << irq;
+
+	if (irq < 0) {
+		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+		       irq, regs->nip);
+		ppc_spurious_interrupts++;
+	}
+	else {
+                ppc_irq_dispatch_handler( regs, irq );
+	}
+
+}
+#endif
+
+
+int
+m8xx_get_irq(struct pt_regs *regs)
+{
+	int irq;
+        unsigned long bits = 0;
+
+        /* For MPC8xx, read the SIVEC register and shift the bits down
+         * to get the irq number.         */
+        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
+        irq = bits >> 26;
+#if 0
+        irq += ppc8xx_pic.irq_offset;
+#endif
+	return irq;
+}
+
+/* The MBX is the only 8xx board that uses the 8259.
+*/
+#ifdef CONFIG_MBX
+void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int bits, irq;
+
+	/* A bug in the QSpan chip causes it to give us 0xff always
+	 * when doing a character read.  So read 32 bits and shift.
+	 * This doesn't seem to return useful values anyway, but
+	 * read it to make sure things are acked.
+	 * -- Cort
+	 */
+	irq = (inl(0x508) >> 24)&0xff;
+	if ( irq != 0xff ) printk("iack %d\n", irq);
+	
+	outb(0x0C, 0x20);
+	irq = inb(0x20) & 7;
+	if (irq == 2)
+	{
+		outb(0x0C, 0xA0);
+		irq = inb(0xA0);
+		irq = (irq&7) + 8;
+	}
+	bits = 1UL << irq;
+	irq += i8259_pic.irq_offset;
+	ppc_irq_dispatch_handler( regs, irq );
+}
+#endif
+
+/* Only the MBX uses the external 8259.  This allows us to catch standard
+ * drivers that may mess up the internal interrupt controllers, and also
+ * allow them to run without modification on the MBX.
+ */
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+	unsigned long irqflags, const char * devname, void *dev_id)
+{
+
+#ifdef CONFIG_MBX
+	irq += i8259_pic.irq_offset;
+	return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
+#else
+	panic("request_irq");
+#endif
+}
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/ppc8xx_pic.h linux/arch/ppc/kernel/ppc8xx_pic.h
--- v2.3.19/linux/arch/ppc/kernel/ppc8xx_pic.h	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/ppc8xx_pic.h	Thu Oct  7 10:17:08 1999
@@ -6,4 +6,16 @@
 
 extern struct hw_interrupt_type ppc8xx_pic;
 
+void m8xx_pic_init(void);
+void m8xx_do_IRQ(struct pt_regs *regs,
+                 int            cpu,
+                 int            isfake);
+int m8xx_get_irq(struct pt_regs *regs);
+
+#ifdef CONFIG_MBX
+#include "i8259.h"
+#include <asm/io.h>
+void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs);
+#endif
+
 #endif /* _PPC_KERNEL_PPC8xx_H */
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c
--- v2.3.19/linux/arch/ppc/kernel/ppc_htab.c	Mon Jun 28 13:40:39 1999
+++ linux/arch/ppc/kernel/ppc_htab.c	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: ppc_htab.c,v 1.28 1999/06/27 10:53:32 davem Exp $
+ * $Id: ppc_htab.c,v 1.29 1999/09/10 05:05:50 paulus Exp $
  *
  * PowerPC hash table management proc entry.  Will show information
  * about the current hash table and will allow changes to it.
@@ -256,6 +256,8 @@
 		return 0;
 	if (n > strlen(buffer) - *ppos)
 		n = strlen(buffer) - *ppos;
+	if (n > count)
+		n = count;
 	copy_to_user(buf, buffer + *ppos, n);
 	*ppos += n;
 	return n;
@@ -533,7 +535,21 @@
 	int vleft, first=1, len, left, val;
 	#define TMPBUFLEN 256
 	char buf[TMPBUFLEN], *p;
-	
+	static const char *sizestrings[4] = {
+		"unknown size", "256KB", "512KB", "1MB"
+	};
+	static const char *clockstrings[8] = {
+		"clock disabled", "+1 clock", "+1.5 clock", "reserved(3)",
+		"+2 clock", "+2.5 clock", "+3 clock", "reserved(7)"
+	};
+	static const char *typestrings[4] = {
+		"flow-through burst SRAM", "reserved SRAM",
+		"pipelined burst SRAM", "pipelined late-write SRAM"
+	};
+	static const char *holdstrings[4] = {
+		"0.5", "1.0", "(reserved2)", "(reserved3)"
+	};
+
 	if ( (_get_PVR() >> 16) != 8) return -EFAULT;
 	
 	if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
@@ -586,55 +602,13 @@
 			p += sprintf(p, " %s",
 				     (val&0x80000000)?"enabled":"disabled");
 			p += sprintf(p,",%sparity",(val&0x40000000)?"":"no ");
-			
-			switch( (val >> 28) & 0x3 )
-			{
-			case 1: p += sprintf(p,",256Kb");
-				break;
-			case 2: p += sprintf(p,",512Kb");
-				break;
-			case 3: p += sprintf(p,",1M");
-				break;
-			default: p += sprintf(p,",unknown size");
-				break;
-			}
-
-			
-			switch( (val >> 25) & 0x7 )
-			{
-			case 0: p += sprintf(p,",clock disabled");
-				break;
-			case 1: p += sprintf(p,",+1 clock");
-				break;
-			case 2: p += sprintf(p,",+1.5 clock");
-				break;
-			case 7:
-			case 3: p += sprintf(p,",reserved clock");
-				break;
-			case 4: p += sprintf(p,",+2 clock");
-				break;
-			case 5: p += sprintf(p,",+2.5 clock");
-				break;
-			case 6: p += sprintf(p,",+3 clock");
-				break;
-			}
-			
-			switch( (val >> 23) & 0x2 )
-			{
-			case 0: p += sprintf(p,",flow-through burst SRAM");
-				break;
-			case 1: p += sprintf(p,",reserved SRAM");
-				break;
-			case 2: p += sprintf(p,",pipelined burst SRAM");
-				break;
-			case 3: p += sprintf(p,",pipelined late-write SRAM");
-				break;
-			}
-			
-			p += sprintf(p,"%s",(val>>22)?"":",data only");
-			p += sprintf(p,"%s",(val>>20)?",ZZ enabled":"");
-			p += sprintf(p,",%s",(val>>19)?"write-through":"copy-back");
-			p += sprintf(p,",%sns hold",(val>>16)?"1.0":"0.5");
+			p += sprintf(p, ",%s", sizestrings[(val >> 28) & 3]);
+			p += sprintf(p, ",%s", clockstrings[(val >> 25) & 7]);
+			p += sprintf(p, ",%s", typestrings[(val >> 23) & 0x2]);
+			p += sprintf(p,"%s",(val>>22)&1?"":",data only");
+			p += sprintf(p,"%s",(val>>20)&1?",ZZ enabled":"");
+			p += sprintf(p,",%s",(val>>19)&1?"write-through":"copy-back");
+			p += sprintf(p,",%sns hold", holdstrings[(val>>16)&3]);
 			
 			p += sprintf(p,"\n");
 			
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.3.19/linux/arch/ppc/kernel/ppc_ksyms.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Thu Oct  7 10:17:08 1999
@@ -21,9 +21,9 @@
 #include <asm/bitops.h>
 #include <asm/checksum.h>
 #include <asm/pgtable.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
-#include <asm/pmu.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/pci-bridge.h>
@@ -31,6 +31,9 @@
 #include <asm/feature.h>
 #include <asm/dma.h>
 #include <asm/machdep.h>
+#ifdef __SMP__
+#include <asm/smplock.h>
+#endif /* __SMP__ */
 
 /* Tell string.h we don't want memcpy etc. as cpp defines */
 #define EXPORT_SYMTAB_STROPS
@@ -47,6 +50,8 @@
 extern void do_lost_interrupts(unsigned long);
 extern int do_signal(sigset_t *, struct pt_regs *);
 
+asmlinkage long long __ashrdi3(long long, int);
+asmlinkage long long __lshrdi3(long long, int);
 asmlinkage int abs(int);
 
 EXPORT_SYMBOL(clear_page);
@@ -67,15 +72,24 @@
 EXPORT_SYMBOL(disable_irq_nosync);
 EXPORT_SYMBOL(ppc_local_irq_count);
 EXPORT_SYMBOL(ppc_local_bh_count);
+#ifdef __SMP__
+EXPORT_SYMBOL(kernel_flag);
+#endif /* __SMP__ */
 
+#ifndef CONFIG_8xx
 EXPORT_SYMBOL(isa_io_base);
 EXPORT_SYMBOL(isa_mem_base);
 EXPORT_SYMBOL(pci_dram_offset);
+#endif
 EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
 EXPORT_SYMBOL(DMA_MODE_READ);
 EXPORT_SYMBOL(DMA_MODE_WRITE);
+#ifndef CONFIG_8xx
+#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC)
 EXPORT_SYMBOL(_prep_type);
 EXPORT_SYMBOL(ucSystemType);
+#endif
+#endif
 
 EXPORT_SYMBOL(atomic_add);
 EXPORT_SYMBOL(atomic_sub);
@@ -175,20 +189,30 @@
 EXPORT_SYMBOL(_write_unlock);
 #endif
 
+#ifndef CONFIG_MACH_SPECIFIC
 EXPORT_SYMBOL(_machine);
+#endif
 EXPORT_SYMBOL(ppc_md);
 
+#ifdef CONFIG_ADB
+/*
+ * This could be more fine-grained, but for now assume if we have
+ * ADB we have it all -- Cort
+ */
 EXPORT_SYMBOL(adb_request);
 EXPORT_SYMBOL(adb_register);
 EXPORT_SYMBOL(cuda_request);
 EXPORT_SYMBOL(cuda_poll);
 EXPORT_SYMBOL(pmu_request);
 EXPORT_SYMBOL(pmu_poll);
+#endif /* CONFIG_ADB */
 #ifdef CONFIG_PMAC_PBOOK
-EXPORT_SYMBOL(sleep_notifier_list);
+EXPORT_SYMBOL(pmu_register_sleep_notifier);
+EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
 EXPORT_SYMBOL(pmu_enable_irled);
 #endif CONFIG_PMAC_PBOOK
 EXPORT_SYMBOL(abort);
+#ifndef CONFIG_8xx
 EXPORT_SYMBOL(find_devices);
 EXPORT_SYMBOL(find_type_devices);
 EXPORT_SYMBOL(find_compatible_devices);
@@ -200,15 +224,18 @@
 EXPORT_SYMBOL(feature_set);
 EXPORT_SYMBOL(feature_clear);
 EXPORT_SYMBOL(feature_test);
+#endif
 #ifdef CONFIG_SCSI
 EXPORT_SYMBOL(note_scsi_host);
 #endif
 EXPORT_SYMBOL(kd_mksound);
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_NVRAM
 EXPORT_SYMBOL(nvram_read_byte);
 EXPORT_SYMBOL(nvram_write_byte);
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_NVRAM */
 
+EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__lshrdi3);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memmove);
@@ -216,8 +243,17 @@
 EXPORT_SYMBOL_NOVERS(memcmp);
 
 EXPORT_SYMBOL(abs);
+#ifndef CONFIG_8xx
 EXPORT_SYMBOL(device_is_compatible);
+#endif
 
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(screen_info);
 #endif
+
+EXPORT_SYMBOL(int_control);
+EXPORT_SYMBOL(timer_interrupt_intercept);
+EXPORT_SYMBOL(timer_interrupt);
+extern unsigned long do_IRQ_intercept;
+EXPORT_SYMBOL(do_IRQ_intercept);
+EXPORT_SYMBOL(irq_desc);
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/prep_nvram.c linux/arch/ppc/kernel/prep_nvram.c
--- v2.3.19/linux/arch/ppc/kernel/prep_nvram.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/prep_nvram.c	Thu Oct  7 10:17:08 1999
@@ -29,14 +29,14 @@
 
 unsigned char *rs_pcNvRAM;
 
-unsigned char prep_nvram_read_val(int addr)
+unsigned char __prep prep_nvram_read_val(int addr)
 {
 	outb(addr, PREP_NVRAM_AS0);
 	outb(addr>>8, PREP_NVRAM_AS1);
 	return inb(PREP_NVRAM_DATA);
 }
   
-void prep_nvram_write_val(int           addr,
+void __prep prep_nvram_write_val(int           addr,
 			  unsigned char val)
 {
 	outb(addr, PREP_NVRAM_AS0);
@@ -47,12 +47,12 @@
 /*
  * Most Radstone boards have NvRAM memory mapped at offset 8M in ISA space
  */
-unsigned char rs_nvram_read_val(int addr)
+unsigned char __prep rs_nvram_read_val(int addr)
 {
 	return rs_pcNvRAM[addr];
 }
   
-void rs_nvram_write_val(int addr,
+void __prep rs_nvram_write_val(int addr,
 			unsigned char val)
 {
 	rs_pcNvRAM[addr]=val;
@@ -113,7 +113,7 @@
 }
 
 __prep
-char *prep_nvram_get_var(const char *name)
+char __prep *prep_nvram_get_var(const char *name)
 {
 	char *cp;
 	int  namelen;
@@ -133,7 +133,7 @@
 }
 
 __prep
-char *prep_nvram_first_var(void)
+char __prep *prep_nvram_first_var(void)
 {
         if (nvram->Header.GELength == 0) {
 		return NULL;
@@ -144,7 +144,7 @@
 }
 
 __prep
-char *prep_nvram_next_var(char *name)
+char __prep *prep_nvram_next_var(char *name)
 {
 	char *cp;
 
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- v2.3.19/linux/arch/ppc/kernel/prep_pci.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/prep_pci.c	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: prep_pci.c,v 1.39 1999/08/31 15:42:39 cort Exp $
+ * $Id: prep_pci.c,v 1.40 1999/09/17 17:23:05 cort Exp $
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -39,7 +39,8 @@
 /* Used for Motorola to store system config register */
 static unsigned long	*ProcInfo;
 
-extern void chrp_do_IRQ(struct pt_regs *,int , int);
+extern int chrp_get_irq(struct pt_regs *);
+extern void chrp_post_irq(int);
 
 /* Tables for known hardware */   
 
@@ -734,7 +735,8 @@
 	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
 	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
 
-	ppc_md.do_IRQ = chrp_do_IRQ;
+	ppc_md.get_irq = chrp_get_irq;
+	ppc_md.post_irq = chrp_post_irq;
 	
 	/* If raven is present on Motorola store the system config register
 	 * for later use.
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.3.19/linux/arch/ppc/kernel/prep_setup.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/prep_setup.c	Thu Oct  7 10:17:08 1999
@@ -86,7 +86,6 @@
 extern unsigned char pckbd_sysrq_xlate[128];
 
 extern void prep_setup_pci_ptrs(void);
-extern void chrp_do_IRQ(struct pt_regs *regs, int cpu, int isfake);
 extern char saved_command_line[256];
 
 int _prep_type;
@@ -114,8 +113,7 @@
 unsigned long vgacon_remap_base;
 #endif
 
-__prep
-int
+int __prep
 prep_get_cpuinfo(char *buffer)
 {
 	extern char *Motherboard_map_name;
@@ -312,7 +310,7 @@
 	 * it's the only way to support both addrs from one binary.
 	 * -- Cort
 	 */
-	if ( is_prep )
+	if ( _machine == _MACH_prep )
 	{
 		extern struct card_info snd_installed_cards[];
 		struct card_info  *snd_ptr;
@@ -486,7 +484,7 @@
 	count_period_den = freq / 1000000;
 }
 
-void
+void __prep
 prep_restart(char *cmd)
 {
         unsigned long i = 10000;
@@ -509,7 +507,7 @@
 /*
  * This function will restart a board regardless of port 92 functionality
  */
-void
+void __prep
 prep_direct_restart(char *cmd)
 {
 	u32 jumpaddr=0xfff00100;
@@ -532,7 +530,7 @@
 	 */
 }
 
-void
+void __prep
 prep_halt(void)
 {
         unsigned long flags;
@@ -552,13 +550,14 @@
 	 */
 }
 
-void
+void __prep
 prep_power_off(void)
 {
 	prep_halt();
 }
 
-int prep_setup_residual(char *buffer)
+int __prep
+prep_setup_residual(char *buffer)
 {
         int len = 0;
 
@@ -576,7 +575,7 @@
 	return len;
 }
 
-u_int
+u_int __prep
 prep_irq_cannonicalize(u_int irq)
 {
 	if (irq == 2)
@@ -589,7 +588,8 @@
 	}
 }
 
-void                           
+#if 0
+void __prep
 prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
 {
         int irq;
@@ -602,6 +602,13 @@
 		return;
 	}
         ppc_irq_dispatch_handler( regs, irq );
+}
+#endif
+
+int __prep
+prep_get_irq(struct pt_regs *regs)
+{
+	return i8259_irq(smp_processor_id());
 }		
 
 void __init
@@ -628,19 +635,19 @@
 /*
  * IDE stuff.
  */
-void
+void __prep
 prep_ide_insw(ide_ioreg_t port, void *buf, int ns)
 {
 	_insw((unsigned short *)((port)+_IO_BASE), buf, ns);
 }
 
-void
+void __prep
 prep_ide_outsw(ide_ioreg_t port, void *buf, int ns)
 {
 	_outsw((unsigned short *)((port)+_IO_BASE), buf, ns);
 }
 
-int
+int __prep
 prep_ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -653,7 +660,7 @@
 	}
 }
 
-ide_ioreg_t
+ide_ioreg_t __prep
 prep_ide_default_io_base(int index)
 {
 	switch (index) {
@@ -666,13 +673,13 @@
 	}
 }
 
-int
+int __prep
 prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
 {
         return check_region(from, extent);
 }
 
-void
+void __prep
 prep_ide_request_region(ide_ioreg_t from,
 			unsigned int extent,
 			const char *name)
@@ -680,14 +687,14 @@
         request_region(from, extent, name);
 }
 
-void
+void __prep
 prep_ide_release_region(ide_ioreg_t from,
 			unsigned int extent)
 {
         release_region(from, extent);
 }
 
-void
+void __prep
 prep_ide_fix_driveid(struct hd_driveid *id)
 {
 }
@@ -776,7 +783,7 @@
 	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
 	ppc_md.init_IRQ       = prep_init_IRQ;
 	/* this gets changed later on if we have an OpenPIC -- Cort */
-	ppc_md.do_IRQ         = prep_do_IRQ;
+	ppc_md.get_irq        = prep_get_irq;
 	ppc_md.init           = NULL;
 
 	ppc_md.restart        = prep_restart;
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.3.19/linux/arch/ppc/kernel/process.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/process.c	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: process.c,v 1.95 1999/08/31 06:54:07 davem Exp $
+ * $Id: process.c,v 1.97 1999/09/14 19:07:42 cort Exp $
  *
  *  linux/arch/ppc/kernel/process.c
  *
@@ -162,7 +162,7 @@
 	  struct task_struct **last)
 {
 	struct thread_struct *new_thread, *old_thread;
-	int s;
+	unsigned long s;
 	
 	__save_flags(s);
 	__cli();
@@ -513,7 +513,7 @@
 	 * vidmem just needs to be setup for it.
 	 * -- Cort
 	 */
-	if ( ! is_prep )
+	if ( _machine != _MACH_prep )
 		return;
 	x = orig_x;
 	y = orig_y;
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.3.19/linux/arch/ppc/kernel/prom.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/prom.c	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: prom.c,v 1.73 1999/09/05 11:56:32 paulus Exp $
+ * $Id: prom.c,v 1.77 1999/09/14 01:13:19 cort Exp $
  *
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -109,9 +109,9 @@
 
 #ifdef CONFIG_BOOTX_TEXT
 
-static void drawchar(char c);
+void drawchar(char c);
+void drawstring(const char *c);
 static void drawhex(unsigned long v);
-static void drawstring(const char *c);
 static void scrollscreen(void);
 
 static void draw_byte(unsigned char c, long locX, long locY);
@@ -138,7 +138,6 @@
 				  unsigned long, struct device_node ***);
 static unsigned long finish_node(struct device_node *, unsigned long,
 				 interpret_func *);
-static void relocate_nodes(void);
 static unsigned long check_display(unsigned long);
 static int prom_next_node(phandle *);
 static void *early_get_property(unsigned long, unsigned long, char *);
@@ -287,7 +286,7 @@
 	gemini_prom_init();
 	return;
 #endif /* CONFIG_GEMINI */
-	
+
 	/* check if we're apus, return if we are */
 	if ( r3 == 0x61707573 )
 		return;
@@ -304,6 +303,8 @@
 #endif		
 
 		RELOC(boot_infos) = PTRUNRELOC(bi);
+		if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
+			bi->logicalDisplayBase = 0;
 
 		clearscreen();
 
@@ -357,9 +358,13 @@
 			}
 		}
 		
-		space = bi->deviceTreeOffset + bi->deviceTreeSize;
-		if (bi->ramDisk)
-			space = bi->ramDisk + bi->ramDiskSize;
+		/* Move klimit to enclose device tree, args, ramdisk, etc... */
+		if (bi->version < 5) {
+			space = bi->deviceTreeOffset + bi->deviceTreeSize;
+			if (bi->ramDisk)
+				space = bi->ramDisk + bi->ramDiskSize;
+		} else
+			space = bi->totalParamsSize;
 		RELOC(klimit) = PTRUNRELOC((char *) bi + space);
 
 		/* New BootX will have flushed all TLBs and enters kernel with
@@ -748,8 +753,6 @@
 {
 	unsigned long mem = (unsigned long) klimit;
 
-	if (boot_infos)
-		relocate_nodes();
 	mem = finish_node(allnodes, mem, NULL);
 	printk(KERN_INFO "device tree used %lu bytes\n",
 	       mem - (unsigned long) allnodes);
@@ -843,7 +846,7 @@
  * This procedure updates the pointers.
  */
 __init
-static void relocate_nodes(void)
+void relocate_nodes(void)
 {
 	unsigned long base;
 	struct device_node *np;
@@ -1183,6 +1186,23 @@
 	return 0;
 }
 
+
+/*
+ * Indicates whether the root node has a given value in its
+ * compatible property.
+ */
+__openfirmware
+int
+machine_is_compatible(const char *compat)
+{
+	struct device_node *root;
+	
+	root = find_path_device("/");
+	if (root == 0)
+		return 0;
+	return device_is_compatible(root, compat);
+}
+
 /*
  * Construct and return a list of the device_nodes with a given type
  * and compatible property.
@@ -1316,7 +1336,8 @@
 	  unsigned long *outputs, ...)
 {
 	va_list list;
-	int i, s;
+	int i;
+	unsigned long s;
 	struct device_node *rtas;
 	int *tokp;
 	union {
@@ -1361,19 +1382,41 @@
 	prom_exit();
 }
 
+#ifdef CONFIG_XMON
+__init
+void
+map_bootx_text(void)
+{
+	if (boot_infos == 0)
+		return;
+	boot_infos->logicalDisplayBase =
+		ioremap((unsigned long) boot_infos->dispDeviceBase,
+			boot_infos->dispDeviceRowBytes * boot_infos->dispDeviceRect[3]);
+}
+#endif /* CONFIG_XMON */
+
 /* Calc the base address of a given point (x,y) */
-#define CALC_BASE(x,y)	((BOOT_INFO_IS_V2_COMPATIBLE(bi) ? bi->logicalDisplayBase :	\
-			bi->dispDeviceBase) + (bi->dispDeviceRect[0] + (x)) *		\
-			(bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes *		\
-			((y) + bi->dispDeviceRect[1]))
+__pmac
+static unsigned char *
+calc_base(boot_infos_t *bi, int x, int y)
+{
+	unsigned char *base;
 
-__init
+	base = bi->logicalDisplayBase;
+	if (base == 0)
+		base = bi->dispDeviceBase;
+	base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3);
+	base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes;
+	return base;
+}
+
+__pmac
 static void
 clearscreen(void)
 {
 	unsigned long offset	= reloc_offset();
 	boot_infos_t* bi	= PTRRELOC(RELOC(boot_infos));
-	unsigned long *base	= (unsigned long *)CALC_BASE(0,0);
+	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
 	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
 					(bi->dispDeviceDepth >> 3)) >> 2;
 	int i,j;
@@ -1392,13 +1435,13 @@
 	__asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr));
 }
 
-__init
+__pmac
 static void
 flushscreen(void)
 {
 	unsigned long offset	= reloc_offset();
 	boot_infos_t* bi	= PTRRELOC(RELOC(boot_infos));
-	unsigned long *base	= (unsigned long *)CALC_BASE(0,0);
+	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
 	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
 					(bi->dispDeviceDepth >> 3)) >> 2;
 	int i,j;
@@ -1416,14 +1459,14 @@
 
 #ifdef CONFIG_BOOTX_TEXT
 
-__init
+__pmac
 static void
 scrollscreen(void)
 {
 	unsigned long offset		= reloc_offset();
 	boot_infos_t* bi		= PTRRELOC(RELOC(boot_infos));
-	unsigned long *src		= (unsigned long *)CALC_BASE(0,16);
-	unsigned long *dst		= (unsigned long *)CALC_BASE(0,0);
+	unsigned long *src		= (unsigned long *)calc_base(bi,0,16);
+	unsigned long *dst		= (unsigned long *)calc_base(bi,0,0);
 	unsigned long width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
 						(bi->dispDeviceDepth >> 3)) >> 2;
 	int i,j;
@@ -1446,21 +1489,33 @@
 	}
 }
 
-__init
-static void
+__pmac
+void
 drawchar(char c)
 {
 	unsigned long offset = reloc_offset();
 
-	switch(c) {
-		case '\r': RELOC(g_loc_X) = 0;			break;
-		case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++;	break;
-		default:
-			draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y));
-			if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) {
-				RELOC(g_loc_X) = 0;
-				RELOC(g_loc_Y)++;
-			}
+	switch (c) {
+	case '\b':
+		if (RELOC(g_loc_X) > 0)
+			--RELOC(g_loc_X);
+		break;
+	case '\t':
+		RELOC(g_loc_X) = (RELOC(g_loc_X) & -8) + 8;
+		break;
+	case '\r':
+		RELOC(g_loc_X) = 0;
+		break;
+	case '\n':
+		RELOC(g_loc_X) = 0;
+		RELOC(g_loc_Y)++;
+		break;
+	default:
+		draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y));
+	}
+	if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) {
+		RELOC(g_loc_X) = 0;
+		RELOC(g_loc_Y)++;
 	}
 	while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) {
 		scrollscreen();
@@ -1468,15 +1523,15 @@
 	}
 }
 
-__init
-static void
+__pmac
+void
 drawstring(const char *c)
 {
-	while(*c)
-		drawchar(*(c++));
+	while (*c)
+		drawchar(*c++);
 }
 
-__init
+__pmac
 static void
 drawhex(unsigned long v)
 {
@@ -1494,13 +1549,13 @@
 }
 
 
-__init
+__pmac
 static void
 draw_byte(unsigned char c, long locX, long locY)
 {
 	unsigned long offset	= reloc_offset();
 	boot_infos_t* bi	= PTRRELOC(RELOC(boot_infos));
-	unsigned char *base	= CALC_BASE(locX << 3, locY << 4);
+	unsigned char *base	= calc_base(bi, locX << 3, locY << 4);
 	unsigned char *font	= &RELOC(vga_font)[((unsigned long)c) * 16];
 	
 	switch(bi->dispDeviceDepth) {
@@ -1518,7 +1573,7 @@
 	}
 }
 
-__init
+__pmac
 static unsigned long expand_bits_8[16] = {
 	0x00000000,
 	0x000000ff,
@@ -1538,7 +1593,7 @@
 	0xffffffff
 };
 
-__init
+__pmac
 static unsigned long expand_bits_16[4] = {
 	0x00000000,
 	0x0000ffff,
@@ -1547,7 +1602,7 @@
 };
 
 
-__init
+__pmac
 static void
 draw_byte_32(unsigned char *font, unsigned long *base)
 {
@@ -1573,7 +1628,7 @@
 	}
 }
 
-__init
+__pmac
 static void
 draw_byte_16(unsigned char *font, unsigned long *base)
 {
@@ -1595,7 +1650,7 @@
 	}
 }
 
-__init
+__pmac
 static void
 draw_byte_8(unsigned char *font, unsigned long *base)
 {
@@ -1615,7 +1670,7 @@
 	}
 }
 
-__init
+__pmac
 static unsigned char vga_font[cmapsz] = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/qspan_pci.c linux/arch/ppc/kernel/qspan_pci.c
--- v2.3.19/linux/arch/ppc/kernel/qspan_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/qspan_pci.c	Thu Oct  7 10:17:08 1999
@@ -0,0 +1,379 @@
+/*
+ * QSpan pci routines.
+ * Most 8xx boards use the QSpan PCI bridge.  The config address register
+ * is located 0x500 from the base of the bridge control/status registers.
+ * The data register is located at 0x504.
+ * This is a two step operation.  First, the address register is written,
+ * then the data register is read/written as required.
+ * I don't know what to do about interrupts (yet).
+ *
+ * The RPX Classic implementation shares a chip select for normal
+ * PCI access and QSpan control register addresses.  The selection is
+ * further selected by a bit setting in a board control register.
+ * Although it should happen, we disable interrupts during this operation
+ * to make sure some driver doesn't accidently access the PCI while
+ * we have switched the chip select.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/mpc8xx.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
+
+
+/*
+ * This blows......
+ * When reading the configuration space, if something does not respond
+ * the bus times out and we get a machine check interrupt.  So, the
+ * good ol' exception tables come to mind to trap it and return some
+ * value.
+ *
+ * On an error we just return a -1, since that is what the caller wants
+ * returned if nothing is present.  I copied this from __get_user_asm,
+ * with the only difference of returning -1 instead of EFAULT.
+ * There is an associated hack in the machine check trap code.
+ *
+ * The QSPAN is also a big endian device, that is it makes the PCI
+ * look big endian to us.  This presents a problem for the Linux PCI
+ * functions, which assume little endian.  For example, we see the
+ * first 32-bit word like this:
+ *	------------------------
+ *	| Device ID | Vendor ID |
+ *	------------------------
+ * If we read/write as a double word, that's OK.  But in our world,
+ * when read as a word, device ID is at location 0, not location 2 as
+ * the little endian PCI would believe.  We have to switch bits in
+ * the PCI addresses given to us to get the data to/from the correct
+ * byte lanes.
+ *
+ * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5.
+ * It always forces the MS bit to zero.  Therefore, dev_fn values
+ * greater than 128 are returned as "no device found" errors.
+ *
+ * The QSPAN can only perform long word (32-bit) configuration cycles.
+ * The "offset" must have the two LS bits set to zero.  Read operations
+ * require we read the entire word and then sort out what should be
+ * returned.  Write operations other than long word require that we
+ * read the long word, update the proper word or byte, then write the
+ * entire long word back.
+ *
+ * PCI Bridge hack.  We assume (correctly) that bus 0 is the primary
+ * PCI bus from the QSPAN.  If we are called with a bus number other
+ * than zero, we create a Type 1 configuration access that a downstream
+ * PCI bridge will interpret.
+ */
+
+#define __get_qspan_pci_config(x, addr, op)		\
+	__asm__ __volatile__(				\
+		"1:	"op" %0,0(%1)\n"		\
+		"	eieio\n"			\
+		"2:\n"					\
+		".section .fixup,\"ax\"\n"		\
+		"3:	li %0,-1\n"			\
+		"	b 2b\n"				\
+		".section __ex_table,\"a\"\n"		\
+		"	.align 2\n"			\
+		"	.long 1b,3b\n"			\
+		".text"					\
+		: "=r"(x) : "r"(addr))
+
+#define QS_CONFIG_ADDR	((volatile uint *)(PCI_CSR_ADDR + 0x500))
+#define QS_CONFIG_DATA	((volatile uint *)(PCI_CSR_ADDR + 0x504))
+
+#define mk_config_addr(bus, dev, offset) \
+	(((bus)<<16) | ((dev)<<8) | (offset & 0xfc))
+
+#define mk_config_type1(bus, dev, offset) \
+	mk_config_addr(bus, dev, offset) | 1;
+
+int qspan_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+				  unsigned char offset, unsigned char *val)
+{
+	uint	temp;
+	u_char	*cp;
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127)) {
+		*val = 0xff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	__get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz");
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	offset ^= 0x03;
+	cp = ((u_char *)&temp) + (offset & 0x03);
+	*val = *cp;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+				  unsigned char offset, unsigned short *val)
+{
+	uint	temp;
+	ushort	*sp;
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127)) {
+		*val = 0xffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	__get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz");
+	offset ^= 0x02;
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	sp = ((ushort *)&temp) + ((offset >> 1) & 1);
+	*val = *sp;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned int *val)
+{
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127)) {
+		*val = 0xffffffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	__get_qspan_pci_config(*val, QS_CONFIG_DATA, "lwz");
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned char val)
+{
+	uint	temp;
+	u_char	*cp;
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
+
+	offset ^= 0x03;
+	cp = ((u_char *)&temp) + (offset & 0x03);
+	*cp = val;
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	*QS_CONFIG_DATA = temp;
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned short val)
+{
+	uint	temp;
+	ushort	*sp;
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
+
+	offset ^= 0x02;
+	sp = ((ushort *)&temp) + ((offset >> 1) & 1);
+	*sp = val;
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	*QS_CONFIG_DATA = temp;
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+				    unsigned char offset, unsigned int val)
+{
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	*(unsigned int *)QS_CONFIG_DATA = val;
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+			     unsigned short index, unsigned char *bus_ptr,
+			     unsigned char *dev_fn_ptr)
+{
+    int num, devfn;
+    unsigned int x, vendev;
+
+    if (vendor == 0xffff)
+	return PCIBIOS_BAD_VENDOR_ID;
+    vendev = (dev_id << 16) + vendor;
+    num = 0;
+    for (devfn = 0;  devfn < 32;  devfn++) {
+	qspan_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
+	if (x == vendev) {
+	    if (index == num) {
+		*bus_ptr = 0;
+		*dev_fn_ptr = devfn<<3;
+		return PCIBIOS_SUCCESSFUL;
+	    }
+	    ++num;
+	}
+    }
+    return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int qspan_pcibios_find_class(unsigned int class_code, unsigned short index,
+			    unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+    int devnr, x, num;
+
+    num = 0;
+    for (devnr = 0;  devnr < 32;  devnr++) {
+	qspan_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
+	if ((x>>8) == class_code) {
+	    if (index == num) {
+		*bus_ptr = 0;
+		*dev_fn_ptr = devnr<<3;
+		return PCIBIOS_SUCCESSFUL;
+	    }
+	    ++num;
+	}
+    }
+    return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+void __init
+m8xx_pcibios_fixup(void))
+{
+   /* Lots to do here, all board and configuration specific. */
+}
+
+void __init
+m8xx_setup_pci_ptrs(void))
+{
+	set_config_access_method(qspan);
+
+	ppc_md.pcibios_fixup = m8xx_pcibios_fixup;
+}
+
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/residual.c linux/arch/ppc/kernel/residual.c
--- v2.3.19/linux/arch/ppc/kernel/residual.c	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/kernel/residual.c	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: residual.c,v 1.15 1999/05/14 07:24:27 davem Exp $
+ * $Id: residual.c,v 1.16 1999/09/17 17:23:09 cort Exp $
  *
  * Code to deal with the PReP residual data.
  *
@@ -49,6 +49,9 @@
 #include <linux/ide.h>
 #include <asm/ide.h>
 
+
+unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,};
+RESIDUAL *res = (RESIDUAL *)&__res;
 
 const char * PnP_BASE_TYPES[] __initdata = {
   "Reserved",
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.19/linux/arch/ppc/kernel/setup.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/setup.c	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.148 1999/09/05 11:56:34 paulus Exp $
+ * $Id: setup.c,v 1.159 1999/09/18 18:40:38 dmalek Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -13,9 +13,6 @@
 #include <linux/blk.h>
 
 #include <asm/init.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
-#include <asm/pmu.h>
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <linux/ide.h>
@@ -27,8 +24,8 @@
 #include <asm/setup.h>
 #include <asm/amigappc.h>
 #include <asm/smp.h>
-#ifdef CONFIG_MBX
-#include <asm/mbx.h>
+#ifdef CONFIG_8xx
+#include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
 #endif
 #include <asm/bootx.h>
@@ -52,7 +49,7 @@
                       unsigned long r6,
                       unsigned long r7);
 
-extern void mbx_init(unsigned long r3,
+extern void m8xx_init(unsigned long r3,
 		     unsigned long r4,
 		     unsigned long r5,
 		     unsigned long r6,
@@ -74,18 +71,17 @@
 extern char cmd_line[512];
 char saved_command_line[256];
 unsigned char aux_device_present;
-
+struct int_control_struct int_control;
 struct ide_machdep_calls ppc_ide_md;
 
 unsigned long ISA_DMA_THRESHOLD;
 unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
 
-/* Temporary hacks until machdep.h is fully done. */
+#ifndef CONFIG_MACH_SPECIFIC
 int _machine = 0;
-/* do we have OF? */
 int have_of = 0;
-int is_prep = 0;
-int is_chrp = 0;
+#endif /* CONFIG_MACH_SPECIFIC */
+
 #ifdef CONFIG_MAGIC_SYSRQ
 unsigned long SYSRQ_KEY;
 #endif /* CONFIG_MAGIC_SYSRQ */
@@ -98,21 +94,19 @@
 
 
 /* copy of the residual data */
-#ifndef CONFIG_MBX
-unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,};
+#ifndef CONFIG_8xx
+extern unsigned char __res[sizeof(RESIDUAL)];
 #else
-unsigned char __res[sizeof(bd_t)] = {0,};
+extern unsigned char __res[sizeof(bd_t)];
 #endif
 
-RESIDUAL *res = (RESIDUAL *)&__res;
-
 /*
  * Perhaps we can put the pmac screen_info[] here
  * on pmac as well so we don't need the ifdef's.
  * Until we get multiple-console support in here
  * that is.  -- Cort
  */ 
-#ifndef CONFIG_MBX
+#ifndef CONFIG_8xx
 struct screen_info screen_info = {
 	0, 25,			/* orig-x, orig-y */
 	0,			/* unused */
@@ -136,7 +130,7 @@
 {
 }
 
-#else /* CONFIG_MBX */
+#else /* CONFIG_8xx */
 
 /* We need this to satisfy some external references until we can
  * strip the kernel down.
@@ -152,7 +146,7 @@
 	0,			/* orig-video-isVGA */
 	16			/* orig-video-points */
 };
-#endif /* CONFIG_MBX */
+#endif /* CONFIG_8xx */
 
 void machine_restart(char *cmd)
 {
@@ -267,6 +261,7 @@
 		 * Assume here that all clock rates are the same in a
 		 * smp system.  -- Cort
 		 */
+#ifndef CONFIG_8xx
 		if ( have_of )
 		{
 			struct device_node *cpu_node;
@@ -290,6 +285,7 @@
 			len += sprintf(len+buffer, "clock\t\t: %dMHz\n",
 				       *fp / 1000000);
 		}
+#endif
 
 		if (ppc_md.setup_residual != NULL)
 		{
@@ -345,9 +341,8 @@
 identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
 		 unsigned long r6, unsigned long r7)
 {
-#ifdef __SMP__
-	if ( first_cpu_booted ) return 0;
-#endif /* __SMP__ */
+
+#ifndef CONFIG_8xx
 	if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100);
 	
 #ifndef CONFIG_MACH_SPECIFIC
@@ -358,68 +353,46 @@
 		r3 = 0;
 	}
 	/* prep boot loader tells us if we're prep or not */
-	else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) {
+	else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
+	{
 		_machine = _MACH_prep;
-		is_prep = 1;
-	} else {
+	} else
+	{
 		char *model;
+		struct device_node *root;
 
 		have_of = 1;
-		
+
 		/* prom_init has already been called from __start */
-		finish_device_tree();
+		if (boot_infos)
+			relocate_nodes();
+
 		/* ask the OF info if we're a chrp or pmac */
-		model = get_property(find_path_device("/"), "device_type", NULL);
-		if ( model && !strncmp("chrp",model,4) )
-		{
-			_machine = _MACH_chrp;
-			is_chrp = 1;
-		}
-		else
-		{
-			model = get_property(find_path_device("/"),
-					     "model", NULL);
-			if ( model && !strncmp(model, "IBM", 3))
-			{
+		/* we need to set _machine before calling finish_device_tree */
+		root = find_path_device("/");
+		if (root != 0) {
+			/* assume pmac unless proven to be chrp -- Cort */
+			_machine = _MACH_Pmac;
+			model = get_property(root, "device_type", NULL);
+			if (model && !strncmp("chrp", model, 4))
 				_machine = _MACH_chrp;
-				is_chrp = 1;
-			}
-			else
-			{
-				_machine = _MACH_Pmac;
+			else {
+				model = get_property(root, "model", NULL);
+				if (model && !strncmp(model, "IBM", 3))
+					_machine = _MACH_chrp;
 			}
 		}
 
+		finish_device_tree();
 	}
-#else /* CONFIG_MACH_SPECIFIC */
-
-#ifdef CONFIG_PREP
-	_machine = _MACH_prep;
-	is_prep  = 1;
-#elif defined(CONFIG_CHRP)
-	_machine = _MACH_chrp;
-	is_chrp  = 1;
-	have_of  = 1;
-#elif defined(CONFIG_PMAC)
-	_machine = _MACH_Pmac;
-	have_of  = 1;
-#elif defined(CONFIG_MBX)
-	_machine = _MACH_mbx;
-#elif defined(CONFIG_FADS)
-	_machine = _MACH_fads;
-#elif defined(CONFIG_APUS)
-	_machine = _MACH_apus;
-#elif defined(CONFIG_GEMINI)
-	_machine = _MACH_gemini;
-#else
-#error "Machine not defined correctly"
-#endif /* CONFIG_APUS */
 #endif /* CONFIG_MACH_SPECIFIC */
 
 	if ( have_of )
 	{
 #ifdef CONFIG_MACH_SPECIFIC
 		/* prom_init has already been called from __start */
+		if (boot_infos)
+			relocate_nodes();
 		finish_device_tree();
 #endif /* CONFIG_MACH_SPECIFIC	*/
 		/*
@@ -473,6 +446,11 @@
 		cmd_line[sizeof(cmd_line) - 1] = 0;
 	}
 
+	int_control.int_sti = __no_use_sti;
+	int_control.int_cli = __no_use_cli;
+	int_control.int_save_flags = __no_use_save_flags;
+	int_control.int_restore_flags = __no_use_restore_flags;
+	
 	switch (_machine)
 	{
 	case _MACH_Pmac:
@@ -489,14 +467,11 @@
                 apus_init(r3, r4, r5, r6, r7);
 		break;
 #endif
-#ifdef CONFIG_MBX
-        case _MACH_mbx:
-                mbx_init(r3, r4, r5, r6, r7);
-                break;
-#endif
+#ifdef CONFIG_GEMINI
 	case _MACH_gemini:
 		gemini_init(r3, r4, r5, r6, r7);
 		break;
+#endif		
 	default:
 		printk("Unknown machine type in identify_machine!\n");
 	}
@@ -505,6 +480,17 @@
 		extern int __map_without_bats;
 		__map_without_bats = 1;
 	}
+#else /* CONFIG_8xx */
+	int_control.int_sti = __no_use_sti;
+	int_control.int_cli = __no_use_cli;
+	int_control.int_save_flags = __no_use_save_flags;
+	int_control.int_restore_flags = __no_use_restore_flags;
+
+        m8xx_init(r3, r4, r5, r6, r7);
+#endif
+
+	/* this is for modules since _machine can be a define -- Cort */
+	ppc_md.ppc_machine = _machine;
 
 	if ( ppc_md.progress ) ppc_md.progress("id mach(): done", 0x200);
 	return 0;
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/sleep.S linux/arch/ppc/kernel/sleep.S
--- v2.3.19/linux/arch/ppc/kernel/sleep.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/sleep.S	Thu Oct  7 10:17:08 1999
@@ -0,0 +1,264 @@
+/*
+ * This file contains sleep low-level functions for PowerBook G3.
+ *    Copyright (C) 1999 Benjamin Herrenschmidt (bh40@calva.net)
+ *    and Paul Mackerras (paulus@cs.anu.edu.au).
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include "ppc_asm.tmpl"
+#include <asm/processor.h>
+#include <asm/page.h>
+
+#define MAGIC	0x4c617273	/* 'Lars' */
+
+/*
+ * Structure for storing CPU registers on the stack.
+ */
+#define SL_SP		0
+#define SL_PC		4
+#define SL_MSR		8
+#define SL_SDR1		0xc
+#define SL_SPRG0	0x10	/* 4 sprg's */
+#define SL_DBAT0	0x20
+#define SL_IBAT0	0x28
+#define SL_DBAT1	0x30
+#define SL_IBAT1	0x38
+#define SL_DBAT2	0x40
+#define SL_IBAT2	0x48
+#define SL_DBAT3	0x50
+#define SL_IBAT3	0x58
+#define SL_TB		0x60
+#define SL_HID0		0x68
+#define SL_R2		0x6c
+#define SL_R12		0x70	/* r12 to r31 */
+#define SL_SIZE		(SL_R12 + 80)
+
+#define tophys(rd,rs)   addis   rd,rs,-KERNELBASE@h     
+#define tovirt(rd,rs)	addis	rd,rs,KERNELBASE@h
+
+	.text
+
+_GLOBAL(low_sleep_handler)
+	mflr	r0
+	stw	r0,4(r1)
+	stwu	r1,-SL_SIZE(r1)
+	stw	r2,SL_R2(r1)
+	stmw	r12,SL_R12(r1)
+
+	/* Save MSR, SDR1, TB  */
+	mfmsr	r4
+	stw	r4,SL_MSR(r1)
+	mfsdr1	r4
+	stw	r4,SL_SDR1(r1)
+1:	
+	mftbu	r4
+	stw	r4,SL_TB(r1)
+	mftb	r5
+	stw	r5,SL_TB+4(r1)
+	mftbu	r3
+	cmpw	r3,r4
+	bne	1b
+	
+	/* Save SPRGs */
+	mfsprg	r4,0
+	stw	r4,SL_SPRG0(r1)
+	mfsprg	r4,1
+	stw	r4,SL_SPRG0+4(r1)
+	mfsprg	r4,2
+	stw	r4,SL_SPRG0+8(r1)
+	mfsprg	r4,3
+	stw	r4,SL_SPRG0+12(r1)
+
+	/* Save BATs */
+	mfdbatu	r4,0
+	stw	r4,SL_DBAT0(r1)
+	mfdbatl	r4,0
+	stw	r4,SL_DBAT0+4(r1)
+	mfdbatu	r4,1
+	stw	r4,SL_DBAT1(r1)
+	mfdbatl	r4,1
+	stw	r4,SL_DBAT1+4(r1)
+	mfdbatu	r4,2
+	stw	r4,SL_DBAT2(r1)
+	mfdbatl	r4,2
+	stw	r4,SL_DBAT2+4(r1)
+	mfdbatu	r4,3
+	stw	r4,SL_DBAT3(r1)
+	mfdbatl	r4,3
+	stw	r4,SL_DBAT3+4(r1)
+	mfibatu	r4,0
+	stw	r4,SL_IBAT0(r1)
+	mfibatl	r4,0
+	stw	r4,SL_IBAT0+4(r1)
+	mfibatu	r4,1
+	stw	r4,SL_IBAT1(r1)
+	mfibatl	r4,1
+	stw	r4,SL_IBAT1+4(r1)
+	mfibatu	r4,2
+	stw	r4,SL_IBAT2(r1)
+	mfibatl	r4,2
+	stw	r4,SL_IBAT2+4(r1)
+	mfibatu	r4,3
+	stw	r4,SL_IBAT3(r1)
+	mfibatl	r4,3
+	stw	r4,SL_IBAT3+4(r1)
+
+	/* Save HID0 */
+	mfspr	r4,HID0
+	stw	r4,SL_HID0(r1)
+
+	/* Set up stuff at address 0 */
+	lis	r5,wake_up@ha
+	addi	r5,r5,wake_up@l
+	tophys(r5,r5)
+	stw	r5,SL_PC(r1)
+	lis	r4,KERNELBASE@h
+	tophys(r5,r1)
+	addi	r5,r5,SL_PC
+	lis	r6,MAGIC@ha
+	addi	r6,r6,MAGIC@l
+	stw	r5,0(r4)
+	stw	r6,4(r4)
+
+/*
+ * Flush the L1 data cache by reading the first 64kB of RAM
+ * and then flushing the same area with the dcbf instruction.
+ * The L2 cache has already been disabled.
+ */
+	li	r4,0x0800	/* 64kB / 32B */
+	mtctr	r4
+	lis	r4,KERNELBASE@h
+1:
+	lwz	r0,0(r4)
+	addi	r4,r4,0x0020		/* Go to start of next cache line */
+	bdnz	1b
+	sync
+	
+	li	r4,0x0800	/* 64k */
+	mtctr	r4
+	lis	r4,KERNELBASE@h
+1:
+	dcbf	r0,r4
+	addi	r4,r4,0x0020	/* Go to start of next cache line */
+	bdnz	1b
+	sync
+
+/*
+ * Set the HID0 and MSR for sleep.
+ */
+	mfspr	r2,HID0
+	rlwinm	r2,r2,0,10,7	/* clear doze, nap */
+	oris	r2,r2,HID0_SLEEP@h
+	sync
+	mtspr	HID0,r2
+	sync
+	
+	mfmsr	r2
+	oris	r2,r2,MSR_POW@h
+1:	sync
+	mtmsr	r2
+	isync
+	b	1b
+
+/* 
+ * Here is the resume code.
+ * r1 has the physical address of SL_PC(sp).
+ */
+	
+wake_up:
+	/* Restore the HID0 register.  This turns on the L1 caches. */
+	subi	r1,r1,SL_PC
+	lwz	r3,SL_HID0(r1)
+	sync
+	isync
+	mtspr	HID0,r3
+	sync
+
+	/* Restore the kernel's segment registers, the
+	   BATs, and SDR1.  Then we can turn on the MMU. */
+	li	r0,16		/* load up segment register values */
+	mtctr	r0		/* for context 0 */
+	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
+	li	r4,0
+3:	mtsrin	r3,r4
+	addi	r3,r3,1		/* increment VSID */
+	addis	r4,r4,0x1000	/* address of next segment */
+	bdnz	3b
+	
+	lwz	r4,SL_SDR1(r1)
+	mtsdr1	r4
+	lwz	r4,SL_SPRG0(r1)
+	mtsprg	0,r4
+	lwz	r4,SL_SPRG0+4(r1)
+	mtsprg	1,r4
+	lwz	r4,SL_SPRG0+8(r1)
+	mtsprg	2,r4
+	lwz	r4,SL_SPRG0+12(r1)
+	mtsprg	3,r4
+
+	lwz	r4,SL_DBAT0(r1)
+	mtdbatu	0,r4
+	lwz	r4,SL_DBAT0+4(r1)
+	mtdbatl	0,r4
+	lwz	r4,SL_DBAT1(r1)
+	mtdbatu	1,r4
+	lwz	r4,SL_DBAT1+4(r1)
+	mtdbatl	1,r4
+	lwz	r4,SL_DBAT2(r1)
+	mtdbatu	2,r4
+	lwz	r4,SL_DBAT2+4(r1)
+	mtdbatl	2,r4
+	lwz	r4,SL_DBAT3(r1)
+	mtdbatu	3,r4
+	lwz	r4,SL_DBAT3+4(r1)
+	mtdbatl	3,r4
+	lwz	r4,SL_IBAT0(r1)
+	mtibatu	0,r4
+	lwz	r4,SL_IBAT0+4(r1)
+	mtibatl	0,r4
+	lwz	r4,SL_IBAT1(r1)
+	mtibatu	1,r4
+	lwz	r4,SL_IBAT1+4(r1)
+	mtibatl	1,r4
+	lwz	r4,SL_IBAT2(r1)
+	mtibatu	2,r4
+	lwz	r4,SL_IBAT2+4(r1)
+	mtibatl	2,r4
+	lwz	r4,SL_IBAT3(r1)
+	mtibatu	3,r4
+	lwz	r4,SL_IBAT3+4(r1)
+	mtibatl	3,r4
+
+	/* restore the MSR and turn on the MMU */
+	lwz	r3,SL_MSR(r1)
+	bl	turn_on_mmu	
+
+	/* get back the stack pointer */
+	tovirt(r1,r1)
+
+	/* Restore TB */
+	lwz	r3,SL_TB(r1)
+	lwz	r4,SL_TB+4(r1)
+	mttbu	r3
+	mttbl	r4
+
+	/* Restore the callee-saved registers and return */
+	lwz	r2,SL_R2(r1)
+	lmw	r12,SL_R12(r1)
+	addi	r1,r1,SL_SIZE
+	lwz	r0,4(r1)
+	mtlr	r0
+	blr
+
+turn_on_mmu:
+	mflr	r4
+	tovirt(r4,r4)
+	mtsrr0	r4
+	mtsrr1	r3
+	sync
+	rfi
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.3.19/linux/arch/ppc/kernel/smp.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/kernel/smp.c	Thu Oct  7 10:17:08 1999
@@ -1,11 +1,13 @@
 /*
- * $Id: smp.c,v 1.62 1999/09/05 11:56:34 paulus Exp $
+ * $Id: smp.c,v 1.68 1999/09/17 19:38:05 cort Exp $
  *
  * Smp support for ppc.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
  * deal of code from the sparc and intel versions.
  *
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ *
  * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
  * (troy@microux.com, hozer@drgw.net)
  */
@@ -34,9 +36,9 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
+#include <asm/gemini.h>
 
 #include "time.h"
-int first_cpu_booted = 0;
 int smp_threads_ready = 0;
 volatile int smp_commenced = 0;
 int smp_num_cpus = 1;
@@ -251,7 +253,6 @@
 
         printk("Entering SMP Mode...\n");
 	/* let other processors know to not do certain initialization */
-	first_cpu_booted = 1;
 	smp_num_cpus = 1;
         smp_store_cpu_info(0);
 
@@ -276,7 +277,7 @@
 	 */
 	cacheflush_time = 5 * 1024;
 
-	if ( !(_machine & (_MACH_Pmac|_MACH_chrp)) )
+	if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_gemini)) )
 	{
 		printk("SMP not supported on this machine.\n");
 		return;
@@ -297,6 +298,10 @@
 #endif
 		cpu_nr = smp_chrp_cpu_nr;
 		break;
+	case _MACH_gemini:
+                cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2;
+                cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr;
+		break;
 	}
 
 	/*
@@ -307,7 +312,6 @@
 	{
 		int c;
 		struct pt_regs regs;
-		struct task_struct *idle;
 		
 		/* create a process for the processor */
 		/* we don't care about the values in regs since we'll
@@ -359,6 +363,10 @@
 				   *(ulong *)get_property(device, "reg", NULL),
 				   __pa(__secondary_start_chrp), i);
 #endif			
+			break;
+		case _MACH_gemini:
+			openpic_init_processor( 1<<i );
+			openpic_init_processor( 0 );
 			break;
 		}
 		
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.3.19/linux/arch/ppc/kernel/traps.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/traps.c	Thu Oct  7 10:17:08 1999
@@ -89,11 +89,11 @@
 {
 	if ( !user_mode(regs) )
 	{
-#ifdef CONFIG_MBX
-		/* the mbx pci read routines can cause machine checks -- Cort */
+#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
+		/* the qspan pci read routines can cause machine checks -- Cort */
 		bad_page_fault(regs,regs->dar);
 		return;
-#endif /* CONFIG_MBX */
+#endif
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		if (debugger_fault_handler) {
 			debugger_fault_handler(regs);
@@ -241,10 +241,14 @@
 		panic("Kernel Mode Software FPU Emulation");
 	}
 
+#ifdef CONFIG_MATH_EMULATION
 	if ((errcode = do_mathemu(regs))) {
+#else
+	if ((errcode = Soft_emulate_8xx(regs))) {
+#endif
 		if (errcode > 0)
 			_exception(SIGFPE, regs);
-		else if (errcode == -EFAULT;
+		else if (errcode == -EFAULT)
 			_exception(SIGSEGV, regs);
 		else
 			_exception(SIGILL, regs);
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/lib/locks.c linux/arch/ppc/lib/locks.c
--- v2.3.19/linux/arch/ppc/lib/locks.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/lib/locks.c	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: locks.c,v 1.24 1999/08/03 19:16:47 cort Exp $
+ * $Id: locks.c,v 1.25 1999/09/10 10:40:13 davem Exp $
  *
  * Locks for smp ppc 
  * 
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/mbxboot/Makefile linux/arch/ppc/mbxboot/Makefile
--- v2.3.19/linux/arch/ppc/mbxboot/Makefile	Fri Mar 19 10:50:03 1999
+++ linux/arch/ppc/mbxboot/Makefile	Thu Oct  7 10:17:08 1999
@@ -1,5 +1,5 @@
 #
-# arch/ppc/boot/Makefile
+# arch/ppc/mbxboot/Makefile
 #
 # 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
@@ -14,7 +14,7 @@
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
-	$(CC) $(CFLAGS)  -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $<
+	$(CC) $(CFLAGS)  -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $<
 .S.s:
 	$(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
 .S.o:
@@ -29,30 +29,46 @@
 ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
 GZIP_FLAGS = -v9
 
-OBJECTS := head.o misc.o ../coffboot/zlib.o mbxtty.o
-CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include -DCONFIG_MBX
+OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o
+CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include -DCONFIG_8xx
 OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O elf32-powerpc
 
+ifeq ($(CONFIG_MBX),y)
+OBJECTS += pci.o qspan_pci.o
+CFLAGS += -DCONFIG_MBX
+endif
+ifeq ($(CONFIG_RPXLITE),y)
+CFLAGS += -DCONFIG_RPXLITE
+OBJECTS += iic.o embed_config.o
+endif
+ifeq ($(CONFIG_RPXCLASSIC),y)
+CFLAGS += -DCONFIG_RPXCLASSIC
+OBJECTS += iic.o embed_config.o pci.o qspan_pci.o
+endif
+ifeq ($(CONFIG_BSEIP),y)
+CFLAGS += -DCONFIG_BSEIP
+OBJECTS += iic.o embed_config.o
+endif
+
 all:	zImage
 
 zvmlinux.initrd: zvmlinux
-	$(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
+	$(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp1 $(OBJECTS)
 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
 		--add-section=initrd=ramdisk.image.gz \
 		--add-section=image=../coffboot/vmlinux.gz \
-		zvmlinux.initrd.tmp zvmlinux.initrd
-	$(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \
-		-DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \
-		-DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \
-		-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \
-		-DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c
+		zvmlinux.initrd.tmp1 zvmlinux.initrd1
+	$(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 initrd` \
+		-DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 initrd` \
+		-DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 image` \
+		-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 image` \
+		-c -o misc.o misc.c
 	$(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
 		--add-section=initrd=ramdisk.image.gz \
 		--add-section=image=../coffboot/vmlinux.gz \
 		zvmlinux.initrd.tmp $@
-	rm zvmlinux.initrd.tmp
 
 zImage: zvmlinux
 	ln -sf zvmlinux zImage
@@ -73,7 +89,7 @@
 #
 	$(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \
 		-DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \
-		-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` -DKERNELBASE=$(KERNELBASE) \
+		-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \
 		-c -o misc.o misc.c
 	$(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/mbxboot/embed_config.c linux/arch/ppc/mbxboot/embed_config.c
--- v2.3.19/linux/arch/ppc/mbxboot/embed_config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mbxboot/embed_config.c	Thu Oct  7 10:17:08 1999
@@ -0,0 +1,207 @@
+
+/* Board specific functions for those embedded 8xx boards that do
+ * not have boot monitor support for board information.
+ */
+#include <sys/types.h>
+#include "asm/mpc8xx.h"
+
+
+/* IIC functions.
+ * These are just the basic master read/write operations so we can
+ * examine serial EEPROM.
+ */
+extern void	iic_read(uint devaddr, u_char *buf, uint offset, uint count);
+extern u_char	aschex_to_byte(u_char *cp);
+
+static void	rpx_eth(bd_t *bd, u_char *cp);
+static void	rpx_brate(bd_t *bd, u_char *cp);
+static void	rpx_memsize(bd_t *bd, u_char *cp);
+static void	rpx_cpuspeed(bd_t *bd, u_char *cp);
+
+/* Read the EEPROM on the RPX-Lite board.
+*/
+void
+rpx_cfg(bd_t *bd)
+{
+	u_char	eebuf[256], *cp;
+
+	/* Read the first 256 bytes of the EEPROM.  I think this
+	 * is really all there is, and I hope if it gets bigger the
+	 * info we want is still up front.
+	 */
+#if 1
+	iic_read(0xa8, eebuf, 0, 128);
+	iic_read(0xa8, &eebuf[128], 128, 128);
+	{
+		int i;
+		cp = (u_char *)0xfa000000;
+
+		for (i=0; i<256; i++)
+			*cp++ = eebuf[i];
+	}
+
+	/* We look for two things, the Ethernet address and the
+	 * serial baud rate.  The records are separated by
+	 * newlines.
+	 */
+	cp = eebuf;
+	for (;;) {
+		if (*cp == 'E') {
+			cp++;
+			if (*cp == 'A') {
+				cp += 2;
+				rpx_eth(bd, cp);
+			}
+		}
+		if (*cp == 'S') {
+			cp++;
+			if (*cp == 'B') {
+				cp += 2;
+				rpx_brate(bd, cp);
+			}
+		}
+		if (*cp == 'D') {
+			cp++;
+			if (*cp == '1') {
+				cp += 2;
+				rpx_memsize(bd, cp);
+			}
+		}
+		if (*cp == 'H') {
+			cp++;
+			if (*cp == 'Z') {
+				cp += 2;
+				rpx_cpuspeed(bd, cp);
+			}
+		}
+
+		/* Scan to the end of the record.
+		*/
+		while ((*cp != '\n') && (*cp != 0xff))
+			cp++;
+
+		/* If the next character is a 0 or ff, we are done.
+		*/
+		cp++;
+		if ((*cp == 0) || (*cp == 0xff))
+			break;
+	}
+	bd->bi_memstart = 0;
+
+#else
+	bd->bi_memstart = 0;
+	bd->bi_memsize = (4 * 1024 * 1024);
+	bd->bi_intfreq = 48;
+	bd->bi_busfreq = 48;
+	bd->bi_baudrate = 9600;
+#endif
+}
+
+static void
+rpx_eth(bd_t *bd, u_char *cp)
+{
+	int	i;
+
+	for (i=0; i<6; i++) {
+		bd->bi_enetaddr[i] = aschex_to_byte(cp);
+		cp += 2;
+	}
+}
+
+static void
+rpx_brate(bd_t *bd, u_char *cp)
+{
+	uint	rate;
+
+	rate = 0;
+
+	while (*cp != '\n') {
+		rate *= 10;
+		rate += (*cp) - '0';
+		cp++;
+	}
+
+	bd->bi_baudrate = rate * 100;
+}
+
+static void
+rpx_memsize(bd_t *bd, u_char *cp)
+{
+	uint	size;
+
+	size = 0;
+
+	while (*cp != '\n') {
+		size *= 10;
+		size += (*cp) - '0';
+		cp++;
+	}
+
+	bd->bi_memsize = size * 1024 * 1024;
+}
+
+static void
+rpx_cpuspeed(bd_t *bd, u_char *cp)
+{
+	uint	num, den;
+
+	num = den = 0;
+
+	while (*cp != '\n') {
+		num *= 10;
+		num += (*cp) - '0';
+		cp++;
+		if (*cp == '/') {
+			cp++;
+			den = (*cp) - '0';
+			break;
+		}
+	}
+
+	/* I don't know why the RPX just can't state the actual
+	 * CPU speed.....
+	 */
+	if (den) {
+		num /= den;
+		num *= den;
+	}
+	bd->bi_intfreq = bd->bi_busfreq = num;
+
+	/* The 8xx can only run a maximum 50 MHz bus speed (until
+	 * Motorola changes this :-).  Greater than 50 MHz parts
+	 * run internal/2 for bus speed.
+	 */
+	if (num > 50)
+		bd->bi_busfreq /= 2;
+}
+
+/* Build a board information structure for the BSE ip-Engine.
+ * There is more to come since we will add some environment
+ * variables and a function to read them.
+ */
+void
+bseip_cfg(bd_t *bd)
+{
+	u_char	*cp;
+	int	i;
+
+	/* Baud rate and processor speed will eventually come
+	 * from the environment variables.
+	 */
+	bd->bi_baudrate = 9600;
+
+	/* Get the Ethernet station address from the Flash ROM.
+	*/
+	cp = (u_char *)0xfe003ffa;
+	for (i=0; i<6; i++) {
+		bd->bi_enetaddr[i] = *cp++;
+	}
+
+	/* The rest of this should come from the environment as well.
+	*/
+	bd->bi_memstart = 0;
+	bd->bi_memsize = (16 * 1024 * 1024);
+	bd->bi_intfreq = 48;
+	bd->bi_busfreq = 48;
+}
+
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/mbxboot/head.S linux/arch/ppc/mbxboot/head.S
--- v2.3.19/linux/arch/ppc/mbxboot/head.S	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/mbxboot/head.S	Thu Oct  7 10:17:08 1999
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include "../kernel/ppc_defs.h"
 #include "../kernel/ppc_asm.tmpl"
 #include <asm/processor.h>
@@ -6,37 +7,101 @@
 	.text
 
 /*
- * $Id: head.S,v 1.4 1999/04/22 06:32:09 davem Exp $
+ * $Id: head.S,v 1.6 1999/09/15 00:02:25 dmalek Exp $
  *	
  * This code is loaded by the ROM loader at some arbitrary location.
  * Move it to high memory so that it can load the kernel at 0x0000.
  *
- * The MBX EPPC-Bug understands ELF, so it loads us into the location
- * specified in the header.  This is a two step process.  First, EPPC-Bug
- * loads the file into the intermediate buffer memory location specified
- * by the environment parameters.  When it discovers this is an ELF
- * binary, it relocates to the link address for us.  Unfortunately, the
- * header does not move with the file, so we have to find the
- * intermediate load location and read the header from there.  From
- * information provided by Motorola (thank you), we know this intermediate
- * location can be found from the NVRAM environment.
- * All of these addresses must be somewhat carefully chosen to make sure
- * we don't overlap the regions.  I chose to load the kernel at 0, the
- * compressed image loads at 0x00100000, and the MBX intermediate buffer
- * was set to 0x00200000.  Provided the loaded kernel image never grows
- * over one megabyte (which I am going to ensure never happens :-), these
- * will work fine.  When we get called from EPPC-Bug, registers are:
+ * This is a three step process that will also work when booting from
+ * a Flash PROM normally located in high memory.
+ *
+ * First, the entire image is loaded into some high memory address.
+ * This is usually at or above 0x02000000.  This is done by a network
+ * boot function supported by the board or a debugger over BDM port.
+ *
+ * Second, the start up function here will relocate the decompress
+ * function to run at the link address of 0x01000000.
+ *
+ * Last, the decompression function will reloate the initrd, zImage, and
+ * the residual data to locations under 8 Meg.  This is necessary because
+ * the embedded kernel start up uses 8 Meg translations to access physical
+ * space before the MMU is enabled.  Finally, the zImage is uncompressed
+ * to location 0 and we jump to it.
+ *
+ * On the MBX,
  *              R1 - Stack pointer at a high memory address.
  *              R3 - Pointer to Board Information Block.
  *              R4 - Pointer to argument string.
  *              Interrupts masked, cache and MMU disabled.
+ *
+ *		...and the first and second functions listed above are
+ *			done for us (it knows ELF images).
+ *
+ * For other embedded boards we build the Board Information Block.
  */
 
 	.globl	start
 start:
 	bl	start_
 start_:
-	mr	r11,r3		/* Save pointer to residual/board data */
+#ifndef CONFIG_MBX
+	lis	r11, local_bd_info@h
+	ori	r11, r11, local_bd_info@l
+#else
+	mr	r11, r3
+#endif
+
+	mfmsr	r3		/* Turn off interrupts  */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r3,r3,r4
+	mtmsr	r3
+
+/* check if we need to relocate ourselves to the link addr or were we
+   loaded there to begin with -- Cort */
+	lis	r4,start@h
+	ori	r4,r4,start@l
+	mflr	r3
+	subi	r3,r3,4		/* we get the nip, not the ip of the branch */
+	mr	r8,r3
+#if 0
+	cmp	0,r3,r4
+	beq	start_ldr	/* Branch if loaded OK */
+#endif
+
+/* 
+ * no matter where we're loaded, move ourselves to -Ttext address
+ * This computes the sizes we need to determine other things.
+ */
+	lis	r5,end@h
+	ori	r5,r5,end@l
+	addi	r5,r5,3			/* Round up - just in case */
+	sub	r5,r5,r4		/* Compute # longwords to move */
+	srwi	r5,r5,2
+	mtctr	r5
+	mr	r7,r5
+	li	r6,0
+	subi	r3,r3,4			/* Set up for loop */
+	subi	r4,r4,4
+00:	lwzu	r5,4(r3)
+	stwu	r5,4(r4)
+	xor	r6,r6,r5
+	bdnz	00b
+
+  	lis	r3,start_ldr@h
+	ori	r3,r3,start_ldr@l
+	mtlr	r3			/* Easiest way to do an absolute jump */
+	blr
+
+start_ldr:
+/* Most 8xx boards don't boot up with the I-cache enabled.  Do that
+ * now because the decompress runs much faster that way.
+ */
+	lis	r3, IDC_INVALL@h
+	mtspr	IC_CST, r3
+	lis	r3, IDC_ENABLE@h
+	mtspr	IC_CST, r3
+
 /* Clear all of BSS */
 	lis	r3,edata@h
 	ori	r3,r3,edata@l
@@ -48,39 +113,60 @@
 50:	stwu	r0,4(r3)
 	cmp	0,r3,r4
 	bne	50b
-90:	mr	r9,r1			/* Save old stack pointer (in case it matters) */
+
 	lis	r1,.stack@h
 	ori	r1,r1,.stack@l
 	addi	r1,r1,4096*2
 	subi	r1,r1,256
 	li	r2,0x000F		/* Mask pointer to 16-byte boundary */
 	andc	r1,r1,r2
-/* Run loader */
+
+	/* Perform configuration of the various boards.  This is done
+	 * by reading some configuration data from EEPROM and building
+	 * the board information structure.
+	 */
 	mr	r3, r11
         mr      r21, r11
+	mr	r22, r8
+	mr	r23, r7
+	mr	r24, r6
+
+#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
+	bl	rpx_cfg
+	mr	r3, r21
+#endif
+#ifdef CONFIG_BSEIP
+	bl	bseip_cfg
+	mr	r3, r21
+#endif
 	bl      serial_init		/* Init MBX serial port */
 
-	lis	r8, 0xfa200000@h	/* Disable Ethernet SCC */
+	mr      r11, r21
+	mr	r8, r22
+	mr	r7, r23
+	mr	r6, r24
+
+#ifdef CONFIG_MBX
+	lis	r18, 0xfa200000@h	/* Disable Ethernet SCC */
 	li	r0, 0
-	stw	r0, 0x0a00(r8)
+	stw	r0, 0x0a00(r18)
 
-	mr      r11, r21
-	lis	r8,start@h
-	ori	r8,r8,start@l
-	lis	r9,end@h
-	ori	r9,r9,end@l
-	sub	r7,r8,r9
-	srwi	r7,r7,2
+	/* On the MBX (or anything that will TFTP load an ELF image),
+	 * we have to find the intermediate address.  The ELF loader
+	 * only moves the Linux boostrap/decompress, not the zImage.
+	 */
 #define ILAP_ADDRESS    0xfa000020
         lis     r8, ILAP_ADDRESS@h
         lwz     r8, ILAP_ADDRESS@l(r8)
         addis   r8, r8, 1               /* Add 64K */
+#endif
+
 	mr	r3,r8			/* Load point */
 	mr	r4,r7			/* Program length */
 	mr	r5,r6			/* Checksum */
 	mr	r6,r11			/* Residual data */
 	bl	decompress_kernel
-	
+
 	/* changed to use r3 (as firmware does) for kernel
 	   as ptr to residual -- Cort*/
 	lis	r6,cmd_line@h
@@ -99,14 +185,17 @@
 	ori	r2,r2,initrd_end@l
 	lwz	r5,0(r2)
 	
-	/* tell kernel we're prep */
-	/* 
-	 * get start address of kernel code which is stored as a coff
-	 * entry.  see boot/head.S -- Cort 
-	 */
+	/* The world starts from the beginning.
+	*/
 	li	r9,0x0
-	lwz	r9,0(r9)
 	mtlr	r9
+
+	/* Invalidate the instruction cache because we just copied a
+	 * bunch of kernel instructions.
+	 */
+	lis	r9, IDC_INVALL@h
+	mtspr	IC_CST, r9
+
 	blr
 hang:
 	b	hang	
@@ -117,19 +206,6 @@
  */
 	.globl	udelay
 udelay:		
-	mfspr	r4,PVR
-	srwi	r4,r4,16
-	cmpi	0,r4,1		/* 601 ? */
-	bne	.udelay_not_601
-00:	li	r0,86	/* Instructions / microsecond? */
-	mtctr	r0
-10:	addi	r0,r0,0 /* NOP */
-	bdnz	10b
-	subic.	r3,r3,1
-	bne	00b
-	blr
-
-.udelay_not_601:		
 	mulli	r4,r3,1000	/* nanoseconds */
 	addi	r4,r4,59
 	li	r5,60
@@ -150,16 +226,6 @@
 	blt	2b
 3:	blr		
 
-.globl _get_HID0
-_get_HID0:		
-	mfspr	r3,HID0
-	blr
-
-.globl _put_HID0
-_put_HID0:		
-	mtspr	HID0,r3
-	blr
-		
 .globl _get_MSR
 _get_MSR:		
 	mfmsr	r3
@@ -170,31 +236,14 @@
 	mtmsr	r3
 	blr
 
-/*
- * Flush instruction cache
- * *** I'm really paranoid here!
- */
-_GLOBAL(flush_instruction_cache)
-	mflr	r5
-	bl	flush_data_cache
-	mtlr	r5
-	blr
-	
-#define NUM_CACHE_LINES 128*8
-#define CACHE_LINE_SIZE 32 
-#define cache_flush_buffer 0x1000
-
-/*
- * Flush data cache
- * *** I'm really paranoid here!
- */
-_GLOBAL(flush_data_cache)
-	lis	r3,cache_flush_buffer@h
-	ori	r3,r3,cache_flush_buffer@l
-	li	r4,NUM_CACHE_LINES
-	mtctr	r4
-00:	lwz	r4,0(r3)
-	addi	r3,r3,CACHE_LINE_SIZE	/* Next line, please */
-	bdnz	00b	
-10:	blr
 	.comm	.stack,4096*2,4
+#ifndef CONFIG_MBX
+local_bd_info:
+	.long	0
+	.long	0x01000000
+	.long	64
+	.long	64
+	.long	0
+	.long	0
+	.long	0
+#endif
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/mbxboot/iic.c linux/arch/ppc/mbxboot/iic.c
--- v2.3.19/linux/arch/ppc/mbxboot/iic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mbxboot/iic.c	Thu Oct  7 10:17:08 1999
@@ -0,0 +1,250 @@
+
+/* Minimal support functions to read configuration from IIC EEPROMS
+ * on MPC8xx boards.  Originally written for RPGC RPX-Lite.
+ * Dan Malek (dmalek@jlc.net).
+ */
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include "asm/mpc8xx.h"
+#include "../8xx_io/commproc.h"
+
+
+/* IIC functions.
+ * These are just the basic master read/write operations so we can
+ * examine serial EEPROM.
+ */
+void	iic_read(uint devaddr, u_char *buf, uint offset, uint count);
+u_char	aschex_to_byte(u_char *cp);
+
+static	int	iic_init_done;
+
+static void
+iic_init()
+{
+	volatile iic_t *iip;
+	volatile i2c8xx_t *i2c;
+	volatile cbd_t	*tbdf, *rbdf;
+	volatile cpm8xx_t	*cp;
+	volatile immap_t	*immap;
+	uint	dpaddr;
+
+	immap = (immap_t *)IMAP_ADDR;
+	cp = (cpm8xx_t *)&(immap->im_cpm);
+
+	/* Reset the CPM.  This is necessary on the 860 processors
+	 * that may have started the SCC1 ethernet without relocating
+	 * the IIC.
+	 * This also stops the Ethernet in case we were loaded by a
+	 * BOOTP rom monitor.
+	 */
+	cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);
+
+	/* Wait for it.
+	*/
+	while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG));
+
+	iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+	i2c = (i2c8xx_t *)&(immap->im_i2c);
+
+	/* Initialize Port B IIC pins.
+	*/
+	cp->cp_pbpar |= 0x00000030;
+	cp->cp_pbdir |= 0x00000030;
+	cp->cp_pbodr |= 0x00000030;
+
+	/* Initialize the parameter ram.
+	*/
+
+	/* Allocate space for a two transmit and one receive buffer
+	 * descriptor in the DP ram.
+	 * For now, this address seems OK, but it may have to
+	 * change with newer versions of the firmware.
+	 */
+	dpaddr = 0x0840;
+
+	/* Set up the IIC parameters in the parameter ram.
+	*/
+	iip->iic_tbase = dpaddr;
+	iip->iic_rbase = dpaddr + (2 * sizeof(cbd_t));
+
+	iip->iic_tfcr = SMC_EB;
+	iip->iic_rfcr = SMC_EB;
+
+	/* This should really be done by the reader/writer.
+	*/
+	iip->iic_mrblr = 128;
+
+	/* Initialize Tx/Rx parameters.
+	*/
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG);
+
+	/* Select an arbitrary address.  Just make sure it is unique.
+	*/
+	i2c->i2c_i2add = 0x34;
+
+	/* Make clock run maximum slow.
+	*/
+	i2c->i2c_i2brg = 7;
+
+	/* Disable interrupts.
+	*/
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = 0xff;
+
+	/* Enable SDMA.
+	*/
+	immap->im_siu_conf.sc_sdcr = 1;
+
+	iic_init_done = 1;
+}
+
+/* Read from IIC.
+ * Caller provides device address, memory buffer, and byte count.
+ */
+static	u_char	iitemp[32];
+
+void
+iic_read(uint devaddr, u_char *buf, uint offset, uint count)
+{
+	volatile iic_t *iip;
+	volatile i2c8xx_t *i2c;
+	volatile cbd_t	*tbdf, *rbdf;
+	volatile cpm8xx_t	*cp;
+	volatile immap_t	*immap;
+	u_char			*tb;
+	uint	dpaddr, temp;
+
+	/* If the interface has not been initialized, do that now.
+	*/
+	if (!iic_init_done)
+		iic_init();
+
+	immap = (immap_t *)IMAP_ADDR;
+	cp = (cpm8xx_t *)&(immap->im_cpm);
+
+	iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+	i2c = (i2c8xx_t *)&(immap->im_i2c);
+
+	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
+	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
+
+	/* Send a "dummy write" operation.  This is a write request with
+	 * only the offset sent, followed by another start condition.
+	 * This will ensure we start reading from the first location
+	 * of the EEPROM.
+	 */
+	tb = iitemp;
+	tb = (u_char *)(((uint)tb + 15) & ~15);
+	tbdf->cbd_bufaddr = tb;
+	*tb = devaddr & 0xfe;	/* Device address */
+	*(tb+1) = offset;		/* Offset */
+	tbdf->cbd_datlen = 2;		/* Length */
+	tbdf->cbd_sc =
+	      BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START;
+
+	i2c->i2c_i2mod = 1;	/* Enable */
+	i2c->i2c_i2cer = 0xff;
+	i2c->i2c_i2com = 0x81;	/* Start master */
+
+	/* Wait for IIC transfer.
+	*/
+#if 0
+	while ((i2c->i2c_i2cer & 3) == 0);
+
+	if (tbdf->cbd_sc & BD_SC_READY)
+		printf("IIC ra complete but tbuf ready\n");
+#else
+	temp = 10000000;
+	while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0))
+		temp--;
+#if 0
+	/* We can't do this...there is no serial port yet!
+	*/
+	if (temp == 0) {
+		printf("Timeout reading EEPROM\n");
+		return;
+	}
+#endif
+#endif
+	
+	/* Chip errata, clear enable.
+	*/
+	i2c->i2c_i2mod = 0;
+
+	/* To read, we need an empty buffer of the proper length.
+	 * All that is used is the first byte for address, the remainder
+	 * is just used for timing (and doesn't really have to exist).
+	 */
+	tbdf->cbd_bufaddr = tb;
+	*tb = devaddr | 1;	/* Device address */
+	rbdf->cbd_bufaddr = (uint)buf;		/* Desination buffer */
+	tbdf->cbd_datlen = rbdf->cbd_datlen = count + 1;	/* Length */
+	tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START;
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+
+	/* Chip bug, set enable here.
+	*/
+	i2c->i2c_i2mod = 1;	/* Enable */
+	i2c->i2c_i2cer = 0xff;
+	i2c->i2c_i2com = 0x81;	/* Start master */
+
+	/* Wait for IIC transfer.
+	*/
+#if 0
+	while ((i2c->i2c_i2cer & 1) == 0);
+
+	if (rbdf->cbd_sc & BD_SC_EMPTY)
+		printf("IIC read complete but rbuf empty\n");
+#else
+	temp = 10000000;
+	while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0))
+		temp--;
+#endif
+	
+	/* Chip errata, clear enable.
+	*/
+	i2c->i2c_i2mod = 0;
+}
+
+/* Because I didn't find anything that would do this.......
+*/
+u_char
+aschex_to_byte(u_char *cp)
+{
+	u_char	byte, c;
+
+	c = *cp++;
+
+	if ((c >= 'A') && (c <= 'F')) {
+		c -= 'A';
+		c += 10;
+	}
+	else if ((c >= 'a') && (c <= 'f')) {
+		c -= 'a';
+		c += 10;
+	}
+	else {
+		c -= '0';
+	}
+	
+	byte = c * 16;
+
+	c = *cp;
+
+	if ((c >= 'A') && (c <= 'F')) {
+		c -= 'A';
+		c += 10;
+	}
+	else if ((c >= 'a') && (c <= 'f')) {
+		c -= 'a';
+		c += 10;
+	}
+	else {
+		c -= '0';
+	}
+	
+	byte += c;
+
+	return(byte);
+}
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/mbxboot/m8xx_tty.c linux/arch/ppc/mbxboot/m8xx_tty.c
--- v2.3.19/linux/arch/ppc/mbxboot/m8xx_tty.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mbxboot/m8xx_tty.c	Thu Oct  7 10:17:08 1999
@@ -0,0 +1,253 @@
+
+
+/* Minimal serial functions needed to send messages out the serial
+ * port on the MBX console.
+ *
+ * The MBX uxes SMC1 for the serial port.  We reset the port and use
+ * only the first BD that EPPC-Bug set up as a character FIFO.
+ *
+ * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug
+ * use COM1 instead of SMC1 as the console port.  This kinda sucks
+ * for the rest of the kernel, so here we force the use of SMC1 again.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <asm/mpc8xx.h>
+#include "../8xx_io/commproc.h"
+
+#ifdef CONFIG_MBX
+#define MBX_CSR1	((volatile u_char *)0xfa100000)
+#define CSR1_COMEN	(u_char)0x02
+#endif
+
+static cpm8xx_t	*cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
+
+void
+serial_init(bd_t *bd)
+{
+	volatile smc_t		*sp;
+	volatile smc_uart_t	*up;
+	volatile cbd_t	*tbdf, *rbdf;
+	volatile cpm8xx_t	*cp;
+	uint	dpaddr, memaddr;
+
+	cp = cpmp;
+	sp = (smc_t*)&(cp->cp_smc[0]);
+	up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1];
+
+	/* Disable transmitter/receiver.
+	*/
+	sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+#ifndef CONFIG_MBX
+	{
+	/* Initialize SMC1 and use it for the console port.
+	 */
+
+	/* Enable SDMA.
+	*/
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1;
+
+	/* Use Port B for SMCs instead of other functions.
+	*/
+	cp->cp_pbpar |= 0x00000cc0;
+	cp->cp_pbdir &= ~0x00000cc0;
+	cp->cp_pbodr &= ~0x00000cc0;
+
+	/* Allocate space for two buffer descriptors in the DP ram.
+	 * For now, this address seems OK, but it may have to
+	 * change with newer versions of the firmware.
+	 */
+	dpaddr = 0x0800;
+
+	/* Grab a few bytes from the top of memory.  EPPC-Bug isn't
+	 * running any more, so we can do this.
+	 */
+	memaddr = (bd->bi_memsize - 32) & ~15;
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
+	rbdf->cbd_bufaddr = memaddr;
+	rbdf->cbd_sc = 0;
+	tbdf = rbdf + 1;
+	tbdf->cbd_bufaddr = memaddr+4;
+	tbdf->cbd_sc = 0;
+
+	/* Set up the uart parameters in the parameter ram.
+	*/
+	up->smc_rbase = dpaddr;
+	up->smc_tbase = dpaddr+sizeof(cbd_t);
+	up->smc_rfcr = SMC_EB;
+	up->smc_tfcr = SMC_EB;
+
+	/* Set UART mode, 8 bit, no parity, one stop.
+	 * Enable receive and transmit.
+	 */
+	sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+	/* Mask all interrupts and remove anything pending.
+	*/
+	sp->smc_smcm = 0;
+	sp->smc_smce = 0xff;
+
+	/* Set up the baud rate generator.
+	 * See 8xx_io/commproc.c for details.
+	 */
+	cp->cp_simode = 0x10000000;
+	cp->cp_brgc1 =
+		((((bd->bi_intfreq * 1000000)/16) / bd->bi_baudrate) << 1) | CPM_BRG_EN;
+
+#else /* CONFIG_MBX */
+	if (*MBX_CSR1 & CSR1_COMEN) {
+		/* COM1 is enabled.  Initialize SMC1 and use it for
+		 * the console port.
+		 */
+
+		/* Enable SDMA.
+		*/
+		((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1;
+
+		/* Use Port B for SMCs instead of other functions.
+		*/
+		cp->cp_pbpar |= 0x00000cc0;
+		cp->cp_pbdir &= ~0x00000cc0;
+		cp->cp_pbodr &= ~0x00000cc0;
+
+		/* Allocate space for two buffer descriptors in the DP ram.
+		 * For now, this address seems OK, but it may have to
+		 * change with newer versions of the firmware.
+		 */
+		dpaddr = 0x0800;
+
+		/* Grab a few bytes from the top of memory.  EPPC-Bug isn't
+		 * running any more, so we can do this.
+		 */
+		memaddr = (bd->bi_memsize - 32) & ~15;
+
+		/* Set the physical address of the host memory buffers in
+		 * the buffer descriptors.
+		 */
+		rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
+		rbdf->cbd_bufaddr = memaddr;
+		rbdf->cbd_sc = 0;
+		tbdf = rbdf + 1;
+		tbdf->cbd_bufaddr = memaddr+4;
+		tbdf->cbd_sc = 0;
+
+		/* Set up the uart parameters in the parameter ram.
+		*/
+		up->smc_rbase = dpaddr;
+		up->smc_tbase = dpaddr+sizeof(cbd_t);
+		up->smc_rfcr = SMC_EB;
+		up->smc_tfcr = SMC_EB;
+
+		/* Set UART mode, 8 bit, no parity, one stop.
+		 * Enable receive and transmit.
+		 */
+		sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+		/* Mask all interrupts and remove anything pending.
+		*/
+		sp->smc_smcm = 0;
+		sp->smc_smce = 0xff;
+
+		/* Set up the baud rate generator.
+		 * See 8xx_io/commproc.c for details.
+		 */
+		cp->cp_simode = 0x10000000;
+		cp->cp_brgc1 =
+			((((bd->bi_intfreq * 1000000)/16) / 9600) << 1) | CPM_BRG_EN;
+
+		/* Enable SMC1 for console output.
+		*/
+		*MBX_CSR1 &= ~CSR1_COMEN;
+	}
+	else {
+#endif /* ndef CONFIG_MBX */
+		/* SMC1 is used as console port.
+		*/
+		tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase];
+		rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase];
+
+		/* Issue a stop transmit, and wait for it.
+		*/
+		cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1,
+					CPM_CR_STOP_TX) | CPM_CR_FLG;
+		while (cp->cp_cpcr & CPM_CR_FLG);
+	}
+
+	/* Make the first buffer the only buffer.
+	*/
+	tbdf->cbd_sc |= BD_SC_WRAP;
+	rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+	/* Single character receive.
+	*/
+	up->smc_mrblr = 1;
+	up->smc_maxidl = 0;
+
+	/* Initialize Tx/Rx parameters.
+	*/
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG);
+
+	/* Enable transmitter/receiver.
+	*/
+	sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+}
+
+void
+serial_putchar(const char c)
+{
+	volatile cbd_t		*tbdf;
+	volatile char		*buf;
+	volatile smc_uart_t	*up;
+
+	up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+	tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
+
+	/* Wait for last character to go.
+	*/
+	buf = (char *)tbdf->cbd_bufaddr;
+	while (tbdf->cbd_sc & BD_SC_READY);
+
+	*buf = c;
+	tbdf->cbd_datlen = 1;
+	tbdf->cbd_sc |= BD_SC_READY;
+}
+
+char
+serial_getc()
+{
+	volatile cbd_t		*rbdf;
+	volatile char		*buf;
+	volatile smc_uart_t	*up;
+	char			c;
+
+	up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+	rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+	/* Wait for character to show up.
+	*/
+	buf = (char *)rbdf->cbd_bufaddr;
+	while (rbdf->cbd_sc & BD_SC_EMPTY);
+	c = *buf;
+	rbdf->cbd_sc |= BD_SC_EMPTY;
+
+	return(c);
+}
+
+int
+serial_tstc()
+{
+	volatile cbd_t		*rbdf;
+	volatile smc_uart_t	*up;
+
+	up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+	rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+	return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/mbxboot/misc.c linux/arch/ppc/mbxboot/misc.c
--- v2.3.19/linux/arch/ppc/mbxboot/misc.c	Fri Mar 19 10:50:03 1999
+++ linux/arch/ppc/mbxboot/misc.c	Thu Oct  7 10:17:09 1999
@@ -1,7 +1,7 @@
 /*
  * misc.c
  *
- * $Id: misc.c,v 1.1 1999/02/17 05:00:06 cort Exp $
+ * $Id: misc.c,v 1.2 1999/09/14 05:55:29 dmalek Exp $
  * 
  * Adapted for PowerPC by Gary Thomas
  *
@@ -17,11 +17,8 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
-#ifdef CONFIG_MBX
-#include <asm/mbx.h>
-#endif
-#ifdef CONFIG_FADS
-#include <asm/fads.h>
+#ifdef CONFIG_8xx
+#include <asm/mpc8xx.h>
 #endif
 
 /*
@@ -34,41 +31,37 @@
 char *avail_ram;
 char *end_avail;
 
-/* Because of the limited amount of memory on the MBX, it presents
+/* See comment below.....
+*/
+unsigned int initrd_offset, initrd_size;
+
+/* Because of the limited amount of memory on embedded, it presents
  * loading problems.  The biggest is that we load this boot program
  * into a relatively low memory address, and the Linux kernel Bss often
  * extends into this space when it get loaded.  When the kernel starts
  * and zeros the BSS space, it also writes over the information we
  * save here and pass to the kernel (command line and board info).
- * On the MBX we grab some known memory holes to hold this information.
+ * On these boards, we grab some known memory holes to hold this information.
  */
-#if defined(CONFIG_SERIAL_CONSOLE)
-char cmd_preset[] = "console=ttyS0,9600n8";
-#else
-char cmd_preset[] = "";
-#endif
 char	cmd_buf[256];
 char	*cmd_line = cmd_buf;
 
-char	*root_string = "root=/dev/nfs";
+char	*root_string = "root=/dev/nfs rw";
 char	*nfsaddrs_string = "nfsaddrs=";
 char	*nfsroot_string = "nfsroot=";
 char	*defroot_string = "/sys/mbxroot";
+char	*ramroot_string = "root=/dev/ram";
 int	do_ipaddrs(char **cmd_cp, int echo);
 void	do_nfsroot(char **cmd_cp, char *dp);
 int	strncmp(const char * cs,const char * ct,size_t count);
 char	*strrchr(const char * s, int c);
 
-RESIDUAL hold_resid_buf;
-RESIDUAL *hold_residual = &hold_resid_buf;
+bd_t hold_resid_buf;
+bd_t *hold_residual = &hold_resid_buf;
 unsigned long initrd_start = 0, initrd_end = 0;
 char *zimage_start;
 int zimage_size;
 
-char *vidmem = (char *)0xC00B8000;
-int lines, cols;
-int orig_x, orig_y;
-
 void puts(const char *);
 void putc(const char c);
 void puthex(unsigned long val);
@@ -88,7 +81,7 @@
 	while(1); 
 }
 
-/* The MBX is just the serial port.
+/* The MPC8xx is just the serial port.
 */
 tstc(void)
 {
@@ -119,7 +112,6 @@
         }
 }
 
-
 void * memcpy(void * __dest, __const void * __src,
 			    int __n)
 {
@@ -231,45 +223,43 @@
 unsigned char sanity[0x2000];
 
 unsigned long
-decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
+decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp)
 {
 	int timer;
 	extern unsigned long start;
 	char *cp, ch;
-	unsigned long i, motorola_id = 0;
-	char needs_reloc = 0;
-	BATU *u;
-	BATL *l;
+	unsigned long i;
 	char	*dp;
 
-	lines = 25;
-	cols = 80;
-	orig_x = 0;
-	orig_y = 24;
+	/* These values must be variables.  If not, the compiler optimizer
+	 * will remove some code, causing the size of the code to vary
+	 * when these values are zero.  This is bad because we first
+	 * compile with these zero to determine the size and offsets
+	 * in an image, than compile again with these set to the proper
+	 * discovered value.....Ya know, we used to read these from the
+	 * header a long time ago.....
+	 */
+	initrd_offset = INITRD_OFFSET;
+	initrd_size = INITRD_SIZE;
 
 	/* Grab some space for the command line and board info.  Since
 	 * we no longer use the ELF header, but it was loaded, grab
 	 * that space.
 	 */
+#ifdef CONFIG_MBX
 	cmd_line = (char *)(load_addr - 0x10000);
-	hold_residual = (RESIDUAL *)(cmd_line + sizeof(cmd_buf));
+#else
+	cmd_line = (char *)(0x200000);
+#endif
+	hold_residual = (bd_t *)(cmd_line + sizeof(cmd_buf));
 	/* copy board data */
-	if (residual)
-		memcpy(hold_residual,residual,sizeof(bd_t));
+	if (bp)
+		memcpy(hold_residual,bp,sizeof(bd_t));
 
-	/* MBX/prep sometimes put the residual/board info at the end of mem 
-	 * assume 16M for now  -- Cort
-	 * To boot on standard MBX boards with 4M, we can't use initrd,
-	 * and we have to assume less memory.  -- Dan
+	/* Set end of memory available to us.  It is always the highest
+	 * memory address provided by the board information.
 	 */
-	if ( INITRD_OFFSET )
-		end_avail = (char *)0x01000000;
-	else
-		end_avail = (char *)0x00400000;
-
-	/* let residual data tell us it's higher */
-	if ( (unsigned long)residual > 0x00800000 )
-		end_avail = (char *)PAGE_ALIGN((unsigned long)residual);
+	end_avail = (char *)(bp->bi_memsize);
 
 	puts("loaded at:     "); puthex(load_addr);
 	puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
@@ -281,11 +271,11 @@
 		puts("\n");
 	}
 
-	if ( residual )
+	if ( bp )
 	{
-		puts("board data at: "); puthex((unsigned long)residual);
+		puts("board data at: "); puthex((unsigned long)bp);
 		puts(" ");
-		puthex((unsigned long)((unsigned long)residual + sizeof(bd_t)));
+		puthex((unsigned long)((unsigned long)bp + sizeof(bd_t)));
 		puts("\n");
 		puts("relocated to:  ");
 		puthex((unsigned long)hold_residual);
@@ -299,11 +289,11 @@
 	zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET);
 	zimage_size = ZIMAGE_SIZE;
 
-	if ( INITRD_OFFSET )
-		initrd_start = load_addr - 0x10000 + INITRD_OFFSET;
+	if ( initrd_offset )
+		initrd_start = load_addr - 0x10000 + initrd_offset;
 	else
 		initrd_start = 0;
-	initrd_end = INITRD_SIZE + initrd_start;
+	initrd_end = initrd_size + initrd_start;
 
 	/*
 	 * setup avail_ram - this is the first part of ram usable
@@ -321,66 +311,49 @@
 	puts("zimage at:     "); puthex((unsigned long)zimage_start);
 	puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n");
 	/*
-	 * don't relocate the zimage if it was loaded above 16M since
-	 * things get weird if we try to relocate -- Cort
-	 * We don't relocate zimage on a base MBX board because of
-	 * insufficient memory.  In this case we don't have initrd either,
-	 * so use that as an indicator.  -- Dan
+	 * There is no reason (yet) to relocate zImage for embedded boards.
+	 * To support boot from flash rom on 8xx embedded boards, I
+	 * assume if zimage start is over 16M we are booting from flash.
+	 * In this case, avilable ram will start just above the space we
+	 * have allocated for the command buffer and board information.
 	 */
-	
-	/* Determine if we have a Motorola board */
-	needs_reloc = 0;
-	if ( (( (unsigned long)zimage_start <= 0x01000000 ) && initrd_start)
-		|| needs_reloc)
-	{
-		memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size),
-			(void *)zimage_start, zimage_size );	
-		zimage_start = (char *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size);
-		end_avail = (char *)zimage_start;
-		puts("relocated to:  "); puthex((unsigned long)zimage_start);
-		puts(" ");
-		puthex((unsigned long)zimage_size+(unsigned long)zimage_start);
-		puts("\n");
-	}
+	if ((unsigned long)zimage_start > 0x01000000)
+		avail_ram = (char *)PAGE_ALIGN((unsigned long)hold_residual + sizeof(bd_t));
 
 	/* relocate initrd */
 	if ( initrd_start )
 	{
 		puts("initrd at:     "); puthex(initrd_start);
 		puts(" "); puthex(initrd_end); puts("\n");
-		/*
-		 * Memory is really tight on the MBX (we can assume 4M)
-		 * so put the initrd at the TOP of ram, and set end_avail
-		 * to right after that.
-		 *
-		 * I should do something like this for prep, too and keep
-		 * a variable end_of_DRAM to keep track of what we think the
-		 * max ram is.
-		 * -- Cort
+
+		/* We only have to relocate initrd if we find it is in Flash
+		 * rom.  This is because the kernel thinks it can toss the
+		 * pages into the free memory pool after it is done.  Use
+		 * the same 16M test.
 		 */
-		if (needs_reloc)
-		{
-			memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+
-				(unsigned long)end_avail-INITRD_SIZE),
+		if ((unsigned long)initrd_start > 0x01000000) {
+			memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE),
 				(void *)initrd_start,
-				INITRD_SIZE );
-			initrd_start = PAGE_ALIGN(-PAGE_SIZE+
-				(unsigned long)end_avail-INITRD_SIZE);
-			initrd_end = initrd_start + INITRD_SIZE;
+				initrd_size );
+			initrd_start = PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE);
+			initrd_end = initrd_start + initrd_size;
 			end_avail = (char *)initrd_start;
 			puts("relocated to:  "); puthex(initrd_start);
 			puts(" "); puthex(initrd_end); puts("\n");
 		}
+		else {
+			avail_ram = (char *)PAGE_ALIGN((unsigned long)initrd_end);
+		}
 	}
 
+
 	puts("avail ram:     "); puthex((unsigned long)avail_ram); puts(" ");
 	puthex((unsigned long)end_avail); puts("\n");
 
 	puts("\nLinux/PPC load: ");
 	timer = 0;
 	cp = cmd_line;
-	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
-	while ( *cp ) putc(*cp++);
+
 	while (timer++ < 5*1000) {
 		if (tstc()) {
 			while ((ch = getc()) != '\n' && ch != '\r') {
@@ -389,11 +362,6 @@
 						cp--;
 						puts("\b \b");
 					}
-				  } else if (ch == '?') {
-					if (!do_ipaddrs(&cp, 1)) {
-						  *cp++ = ch;
-						  putc(ch);
-					}
 				} else {
 					*cp++ = ch;
 					putc(ch);
@@ -404,188 +372,33 @@
 		udelay(1000);  /* 1 msec */
 	}
 	*cp = 0;
-	/* The MBX does not currently have any default boot strategy.
-	 * If the command line is not filled in, we will automatically
-	 * create the default network boot.
+
+	/* If the command line is not filled in, we will automatically
+	 * create the default boot.
 	 */
 	if (cmd_line[0] == 0) {
-		dp = root_string;
-		while (*dp != 0)
-			*cp++ = *dp++;
-		*cp++ = ' ';
 
-		dp = nfsaddrs_string;
+		/* An initrd on these boards means we booted from Flash
+		 * ROM and want to use the ramdisk as the root file system.
+		 * Otherwise, we perform a diskless NFS boot.
+		 */
+		if (initrd_start)
+			dp = ramroot_string;
+		else
+			dp = root_string;
 		while (*dp != 0)
 			*cp++ = *dp++;
-		dp = cp;
-		do_ipaddrs(&cp, 0);
-		*cp++ = ' ';
-
-		/* Add the server address to the root file system path.
-		*/
-		dp = strrchr(dp, ':');
-		dp++;
-		do_nfsroot(&cp, dp);
 		*cp = 0;
 	}
+
 	puts("\n");
 
-	/* mappings on early boot can only handle 16M */
-	if ( (int)(cmd_line[0]) > (16<<20))
-		puts("cmd_line located > 16M\n");
-	if ( (int)hold_residual > (16<<20))
-		puts("hold_residual located > 16M\n");
-	if ( initrd_start > (16<<20))
-		puts("initrd_start located > 16M\n");
-       
 	puts("Uncompressing Linux...");
 
 	gunzip(0, 0x400000, zimage_start, &zimage_size);
 	puts("done.\n");
 	puts("Now booting the kernel\n");
 	return (unsigned long)hold_residual;
-}
-
-int
-do_ipaddrs(char **cmd_cp, int echo)
-{
-	char	*cp, *ip, ch;
-	unsigned char	ipd;
-	int	i, j, retval;
-
-	/* We need to create the string:
-	 *	<my_ip>:<serv_ip>
-	 */
-	cp = *cmd_cp;
-	retval = 0;
-
-	if ((cp - 9) >= cmd_line) {
-		if (strncmp(cp - 9, "nfsaddrs=", 9) == 0) {
-			ip = (char *)0xfa000060;
-			retval = 1;
-			for (j=0; j<2; j++) {
-				for (i=0; i<4; i++) {
-					ipd = *ip++;
-
-					ch = ipd/100;
-					if (ch) {
-						ch += '0';
-						if (echo)
-							putc(ch);
-						*cp++ = ch;
-						ipd -= 100 * (ch - '0');
-					}
-
-					ch = ipd/10;
-					if (ch) {
-						ch += '0';
-						if (echo)
-							putc(ch);
-						*cp++ = ch;
-						ipd -= 10 * (ch - '0');
-					}
-
-					ch = ipd + '0';
-					if (echo)
-						putc(ch);
-					*cp++ = ch;
-
-					ch = '.';
-					if (echo)
-						putc(ch);
-					*cp++ = ch;
-				}
-
-				/* At the end of the string, remove the
-				 * '.' and replace it with a ':'.
-				 */
-				*(cp - 1) = ':';
-				if (echo) {
-					putc('\b'); putc(':');
-				}
-			}
-
-			/* At the end of the second string, remove the
-			 * '.' from both the command line and the
-			 * screen.
-			 */
-			--cp;
-			putc('\b'); putc(' '); putc('\b');
-		}
-	}
-	*cmd_cp = cp;
-	return(retval);
-}
-
-void
-do_nfsroot(char **cmd_cp, char *dp)
-{
-	char	*cp, *rp, *ep;
-
-	/* The boot argument (i.e /sys/mbxroot/zImage) is stored
-	 * at offset 0x0078 in NVRAM.  We use this path name to
-	 * construct the root file system path.
-	 */
-	cp = *cmd_cp;
-
-	/* build command string.
-	*/
-	rp = nfsroot_string;
-	while (*rp != 0)
-		*cp++ = *rp++;
-
-	/* Add the server address to the path.
-	*/
-	while (*dp != ' ')
-		*cp++ = *dp++;
-	*cp++ = ':';
-
-	rp = (char *)0xfa000078;
-	ep = strrchr(rp, '/');
-
-	if (ep != 0) {
-		while (rp < ep)
-			*cp++ = *rp++;
-	}
-	else {
-		rp = defroot_string;
-		while (*rp != 0)
-			*cp++ = *rp++;
-	}
-
-	*cmd_cp = cp;
-}
-
-size_t strlen(const char * s)
-{
-	const char *sc;
-
-	for (sc = s; *sc != '\0'; ++sc)
-		/* nothing */;
-	return sc - s;
-}
-
-int strncmp(const char * cs,const char * ct,size_t count)
-{
-	register signed char __res = 0;
-
-	while (count) {
-		if ((__res = *cs - *ct++) != 0 || !*cs++)
-			break;
-		count--;
-	}
-
-	return __res;
-}
-
-char * strrchr(const char * s, int c)
-{
-       const char *p = s + strlen(s);
-       do {
-           if (*p == (char)c)
-               return (char *)p;
-       } while (--p >= s);
-       return NULL;
 }
 
 void puthex(unsigned long val)
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/mbxboot/pci.c linux/arch/ppc/mbxboot/pci.c
--- v2.3.19/linux/arch/ppc/mbxboot/pci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mbxboot/pci.c	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,251 @@
+/* Stand alone funtions for QSpan Tundra support.
+ */
+#include <sys/types.h>
+#include <linux/pci.h>
+#include <asm/mpc8xx.h>
+
+/* To map PCI devices, you first write 0xffffffff into the device
+ * base address registers.  When the register is read back, the
+ * number of most significant '1' bits describes the amount of address
+ * space needed for mapping.  If the most significant bit is not set,
+ * either the device does not use that address register, or it has
+ * a fixed address that we can't change.  After the address is assigned,
+ * the command register has to be written to enable the card.
+ */
+typedef struct {
+	u_char	pci_bus;
+	u_char	pci_devfn;
+	ushort	pci_command;
+	uint	pci_addrs[6];
+} pci_map_t;
+
+/* We should probably dynamically allocate these structures.
+*/
+#define MAX_PCI_DEVS	32
+int	pci_dev_cnt;
+pci_map_t	pci_map[MAX_PCI_DEVS];
+
+void pci_conf_write(int bus, int device, int func, int reg, uint writeval);
+void pci_conf_read(int bus, int device, int func, int reg, void *readval);
+void probe_addresses(int bus, int devfn);
+void map_pci_addrs(void);
+
+/* This is a really stripped version of PCI bus scan.  All we are
+ * looking for are devices that exist.
+ */
+pci_scanner(int addr_probe)
+{
+	unsigned int devfn, l, max, class, bus_number;
+	unsigned char cmd, irq, tmp, hdr_type, is_multi;
+	int reg;
+
+	is_multi = 0;
+	bus_number = 0;
+	for (devfn = 0; devfn < 0xff; ++devfn) {
+		/* The device numbers are comprised of upper 5 bits of
+		 * device number and lower 3 bits of multi-function number.
+		 */
+		if ((devfn & 7) && !is_multi) {
+			/* Don't scan multifunction addresses if this is
+			 * not a multifunction device.
+			 */
+			continue;
+		}
+
+		/* Read the header to determine card type.
+		*/
+		qs_pci_read_config_byte(bus_number, devfn, PCI_HEADER_TYPE,
+								&hdr_type);
+
+		/* If this is a base device number, check the header to
+		 * determine if it is mulifunction.
+		 */
+		if ((devfn & 7) == 0)
+			is_multi = hdr_type & 0x80;
+
+		/* Check to see if the board is really in the slot.
+		*/
+		qs_pci_read_config_dword(bus_number, devfn, PCI_VENDOR_ID, &l);
+		/* some broken boards return 0 if a slot is empty: */
+		if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff ||
+							l == 0xffff0000) {
+			/* Nothing there.
+			*/
+			is_multi = 0;
+			continue;
+		}
+
+		/* If we are not performing an address probe,
+		 * just simply print out some information.
+		 */
+		if (!addr_probe) {
+			qs_pci_read_config_dword(bus_number, devfn,
+						PCI_CLASS_REVISION, &class);
+
+			class >>= 8;	    /* upper 3 bytes */
+
+#if 0
+			printf("Found (%3d:%d): vendor 0x%04x, device 0x%04x, class 0x%06x\n",
+				(devfn >> 3), (devfn & 7),
+				(l & 0xffff),  (l >> 16) & 0xffff, class);
+#else
+			puts("Found ("); puthex(devfn >> 3);
+			puts(":"); puthex(devfn & 7);
+			puts("): vendor "); puthex(l & 0xffff);
+			puts(", device "); puthex((l >> 16) & 0xffff);
+			puts(", class "); puthex(class); puts("\n");
+#endif
+		}
+		else {
+			/* If this is a "normal" device, build address list.
+			*/
+			if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL)
+				probe_addresses(bus_number, devfn);
+		}
+	}
+
+	/* Now map the boards.
+	*/
+	if (addr_probe)
+		map_pci_addrs();
+}
+
+/* Probe addresses for the specified device.  This is a destructive
+ * operation because it writes the registers.
+ */
+void
+probe_addresses(bus, devfn)
+{
+	int	i;
+	uint	pciaddr;
+	ushort	pcicmd;
+	pci_map_t	*pm;
+
+	if (pci_dev_cnt >= MAX_PCI_DEVS) {
+		puts("Too many PCI devices\n");
+		return;
+	}
+
+	pm = &pci_map[pci_dev_cnt++];
+
+	pm->pci_bus = bus;
+	pm->pci_devfn = devfn;
+
+	for (i=0; i<6; i++) {
+		qs_pci_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), -1);
+		qs_pci_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4),
+								&pciaddr);
+		pm->pci_addrs[i] = pciaddr;
+		qs_pci_read_config_word(bus, devfn, PCI_COMMAND, &pcicmd);
+		pm->pci_command = pcicmd;
+	}
+}
+
+/* Map the cards into the PCI space.  The PCI has separate memory
+ * and I/O spaces.  In addition, some memory devices require mapping
+ * below 1M.  The least significant 4 bits of the address register
+ * provide information.  If this is an I/O device, only the LS bit
+ * is used to indicate that, so I/O devices can be mapped to a two byte
+ * boundard.  Memory addresses can be mapped to a 32 byte boundary.
+ * The QSpan implementations usually have a 1Gbyte space for each
+ * memory and I/O spaces.
+ *
+ * This isn't a terribly fancy algorithm.  I just map the spaces from
+ * the top starting with the largest address space.  When finished,
+ * the registers are written and the card enabled.
+ *
+ * While the Tundra can map a large address space on most boards, we
+ * need to be careful because it may overlap other devices (like IMMR).
+ */
+#define MEMORY_SPACE_SIZE	0x20000000
+#define IO_SPACE_SIZE		0x20000000
+
+void
+map_pci_addrs()
+{
+	uint	pci_mem_top, pci_mem_low;
+	uint	pci_io_top;
+	uint	addr_mask, reg_addr, space;
+	int	i, j;
+	pci_map_t *pm;
+
+	pci_mem_top = MEMORY_SPACE_SIZE;
+	pci_io_top = IO_SPACE_SIZE;
+	pci_mem_low = (1 * 1024 * 1024);	/* Below one meg addresses */
+
+	/* We can't map anything more than the maximum space, but test
+	 * for it anyway to catch devices out of range.
+	 */
+	addr_mask = 0x80000000;
+
+	do {
+		space = (~addr_mask) + 1;	/* Size of the space */
+		for (i=0; i<pci_dev_cnt; i++) {
+			pm = &pci_map[i];
+			for (j=0; j<6; j++) {
+				/* If the MS bit is not set, this has either
+				 * already been mapped, or is not used.
+				 */
+				reg_addr = pm->pci_addrs[j];
+				if ((reg_addr & 0x80000000) == 0)
+					continue;
+				if (reg_addr & PCI_BASE_ADDRESS_SPACE_IO) {
+					if ((reg_addr & PCI_BASE_ADDRESS_IO_MASK) != addr_mask)
+						continue;
+					if (pci_io_top < space) {
+						puts("Out of PCI I/O space\n");
+					}
+					else {
+						pci_io_top -= space;
+						pm->pci_addrs[j] = pci_io_top;
+						pm->pci_command |= PCI_COMMAND_IO;
+					}
+				}
+				else {
+					if ((reg_addr & PCI_BASE_ADDRESS_MEM_MASK) != addr_mask)
+						continue;
+
+					/* Memory space.  Test if below 1M.
+					*/
+					if (reg_addr & PCI_BASE_ADDRESS_MEM_TYPE_1M) {
+						if (pci_mem_low < space) {
+							puts("Out of PCI 1M space\n");
+						}
+						else {
+							pci_mem_low -= space;
+							pm->pci_addrs[j] = pci_mem_low;
+						}
+					}
+					else {
+						if (pci_mem_top < space) {
+							puts("Out of PCI Mem space\n");
+						}
+						else {
+							pci_mem_top -= space;
+							pm->pci_addrs[j] = pci_mem_top;
+						}
+					}
+					pm->pci_command |= PCI_COMMAND_MEMORY;
+				}
+			}
+		}
+		addr_mask >>= 1;
+		addr_mask |= 0x80000000;
+	} while (addr_mask != 0xfffffffe);
+	
+	/* Now, run the list one more time and map everything.
+	*/
+	for (i=0; i<pci_dev_cnt; i++) {
+		pm = &pci_map[i];
+		for (j=0; j<6; j++) {
+			qs_pci_write_config_dword(pm->pci_bus, pm->pci_devfn,
+				PCI_BASE_ADDRESS_0 + (j * 4), pm->pci_addrs[j]);
+		}
+
+		/* Enable memory or address mapping.
+		*/
+		qs_pci_write_config_word(pm->pci_bus, pm->pci_devfn, PCI_COMMAND,
+			pm->pci_command);
+	}
+}
+
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/mbxboot/qspan_pci.c linux/arch/ppc/mbxboot/qspan_pci.c
--- v2.3.19/linux/arch/ppc/mbxboot/qspan_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mbxboot/qspan_pci.c	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,267 @@
+/*
+ * LinuxPPC arch/ppc/kernel/qspan_pci.c   Dan Malek (dmalek@jlc.net)
+ *
+ * QSpan Motorola bus to PCI bridge.  The config address register
+ * is located 0x500 from the base of the bridge control/status registers.
+ * The data register is located at 0x504.
+ * This is a two step operation.  First, the address register is written,
+ * then the data register is read/written as required.
+ * I don't know what to do about interrupts (yet).
+ */
+
+#include <sys/types.h>
+#include <linux/pci.h>
+#include <asm/mpc8xx.h>
+
+/*
+ * When reading the configuration space, if something does not respond
+ * the bus times out and we get a machine check interrupt.  So, the
+ * good ol' exception tables come to mind to trap it and return some
+ * value.
+ *
+ * On an error we just return a -1, since that is what the caller wants
+ * returned if nothing is present.  I copied this from __get_user_asm,
+ * with the only difference of returning -1 instead of EFAULT.
+ * There is an associated hack in the machine check trap code.
+ *
+ * The QSPAN is also a big endian device, that is it makes the PCI
+ * look big endian to us.  This presents a problem for the Linux PCI
+ * functions, which assume little endian.  For example, we see the
+ * first 32-bit word like this:
+ *	------------------------
+ *	| Device ID | Vendor ID |
+ *	------------------------
+ * If we read/write as a double word, that's OK.  But in our world,
+ * when read as a word, device ID is at location 0, not location 2 as
+ * the little endian PCI would believe.  We have to switch bits in
+ * the PCI addresses given to us to get the data to/from the correct
+ * byte lanes.
+ *
+ * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5.
+ * It always forces the MS bit to zero.  Therefore, dev_fn values
+ * greater than 128 are returned as "no device found" errors.
+ *
+ * The QSPAN can only perform long word (32-bit) configuration cycles.
+ * The "offset" must have the two LS bits set to zero.  Read operations
+ * require we read the entire word and then sort out what should be
+ * returned.  Write operations other than long word require that we
+ * read the long word, update the proper word or byte, then write the
+ * entire long word back.
+ *
+ * PCI Bridge hack.  We assume (correctly) that bus 0 is the primary
+ * PCI bus from the QSPAN.  If we are called with a bus number other
+ * than zero, we create a Type 1 configuration access that a downstream
+ * PCI bridge will interpret.
+ */
+
+#define __get_pci_config(x, addr, op)		\
+	__asm__ __volatile__(				\
+		"1:	"op" %0,0(%1)\n"		\
+		"	eieio\n"			\
+		"2:\n"					\
+		".section .fixup,\"ax\"\n"		\
+		"3:	li %0,-1\n"			\
+		"	b 2b\n"				\
+		".section __ex_table,\"a\"\n"		\
+		"	.align 2\n"			\
+		"	.long 1b,3b\n"			\
+		".text"					\
+		: "=r"(x) : "r"(addr))
+
+#define QS_CONFIG_ADDR	((volatile uint *)(PCI_CSR_ADDR + 0x500))
+#define QS_CONFIG_DATA	((volatile uint *)(PCI_CSR_ADDR + 0x504))
+
+#define mk_config_addr(bus, dev, offset) \
+	(((bus)<<16) | ((dev)<<8) | (offset & 0xfc))
+
+#define mk_config_type1(bus, dev, offset) \
+	mk_config_addr(bus, dev, offset) | 1;
+
+/* Initialize the QSpan device registers after power up.
+*/
+qspan_init()
+{
+	uint	*qptr;
+
+
+
+	qptr = (uint *)PCI_CSR_ADDR;
+
+	/* PCI Configuration/status.  Upper bits written to clear
+	 * pending interrupt or status.  Lower bits enable QSPAN as
+	 * PCI master, enable memory and I/O cycles, and enable PCI
+	 * parity error checking.
+	 * IMPORTANT:  The last two bits of this word enable PCI
+	 * master cycles into the QBus.  The QSpan is broken and can't
+	 * meet the timing specs of the PQ bus for this to work.  Therefore,
+	 * if you don't have external bus arbitration, you can't use
+	 * this function.
+	 */
+#ifdef EXTERNAL_PQ_ARB
+	qptr[1] = 0xf9000147;
+#else
+	qptr[1] = 0xf9000144;
+#endif
+
+	/* PCI Misc configuration.  Set PCI latency timer resolution
+	 * of 8 cycles, set cache size to 4 x 32.
+	 */
+	qptr[3] = 0;
+
+	/* Set up PCI Target address mapping.  Enable, Posted writes,
+	 * 2Gbyte space (processor memory controller determines actual size).
+	 */
+	qptr[64] = 0x8f000080;
+
+	/* Map processor 0x80000000 to PCI 0x00000000.
+	 * Processor address bit 1 determines I/O type access (0x80000000)
+	 * or memory type access (0xc0000000).
+	 */
+	qptr[65] = 0x80000000;
+
+	/* Enable error logging and clear any pending error status.
+	*/
+	qptr[80] = 0x90000000;
+
+	qptr[512] = 0x000c0003;
+
+	/* Set up Qbus slave image.
+	*/
+	qptr[960] = 0x01000000;
+	qptr[961] = 0x000000d1;
+	qptr[964] = 0x00000000;
+	qptr[965] = 0x000000d1;
+
+}
+
+/* Functions to support PCI bios-like features to read/write configuration
+ * space.  If the function fails for any reason, a -1 (0xffffffff) value
+ * must be returned.
+ */
+#define DEVICE_NOT_FOUND	(-1)
+#define SUCCESSFUL		0
+
+int qs_pci_read_config_byte(unsigned char bus, unsigned char dev_fn,
+				  unsigned char offset, unsigned char *val)
+{
+	uint	temp;
+	u_char	*cp;
+
+	if ((bus > 7) || (dev_fn > 127)) {
+		*val = 0xff;
+		return DEVICE_NOT_FOUND;
+	}
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	__get_pci_config(temp, QS_CONFIG_DATA, "lwz");
+
+	offset ^= 0x03;
+	cp = ((u_char *)&temp) + (offset & 0x03);
+	*val = *cp;
+	return SUCCESSFUL;
+}
+
+int qs_pci_read_config_word(unsigned char bus, unsigned char dev_fn,
+				  unsigned char offset, unsigned short *val)
+{
+	uint	temp;
+	ushort	*sp;
+
+	if ((bus > 7) || (dev_fn > 127)) {
+		*val = 0xffff;
+		return DEVICE_NOT_FOUND;
+	}
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	__get_pci_config(temp, QS_CONFIG_DATA, "lwz");
+	offset ^= 0x02;
+
+	sp = ((ushort *)&temp) + ((offset >> 1) & 1);
+	*val = *sp;
+	return SUCCESSFUL;
+}
+
+int qs_pci_read_config_dword(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned int *val)
+{
+	if ((bus > 7) || (dev_fn > 127)) {
+		*val = 0xffffffff;
+		return DEVICE_NOT_FOUND;
+	}
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	__get_pci_config(*val, QS_CONFIG_DATA, "lwz");
+	return SUCCESSFUL;
+}
+
+int qs_pci_write_config_byte(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned char val)
+{
+	uint	temp;
+	u_char	*cp;
+
+	if ((bus > 7) || (dev_fn > 127))
+		return DEVICE_NOT_FOUND;
+
+	qs_pci_read_config_dword(bus, dev_fn, offset, &temp);
+
+	offset ^= 0x03;
+	cp = ((u_char *)&temp) + (offset & 0x03);
+	*cp = val;
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	*QS_CONFIG_DATA = temp;
+
+	return SUCCESSFUL;
+}
+
+int qs_pci_write_config_word(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned short val)
+{
+	uint	temp;
+	ushort	*sp;
+
+	if ((bus > 7) || (dev_fn > 127))
+		return DEVICE_NOT_FOUND;
+
+	qs_pci_read_config_dword(bus, dev_fn, offset, &temp);
+
+	offset ^= 0x02;
+	sp = ((ushort *)&temp) + ((offset >> 1) & 1);
+	*sp = val;
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	*QS_CONFIG_DATA = temp;
+
+	return SUCCESSFUL;
+}
+
+int qs_pci_write_config_dword(unsigned char bus, unsigned char dev_fn,
+				    unsigned char offset, unsigned int val)
+{
+	if ((bus > 7) || (dev_fn > 127))
+		return DEVICE_NOT_FOUND;
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	*(unsigned int *)QS_CONFIG_DATA = val;
+
+	return SUCCESSFUL;
+}
+
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.3.19/linux/arch/ppc/mm/fault.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/mm/fault.c	Thu Oct  7 10:17:09 1999
@@ -181,38 +181,6 @@
 }
 
 #ifdef CONFIG_8xx
-/*
- * I need a va to pte function for the MPC8xx so I can set the cache
- * attributes on individual pages used by the Communication Processor
- * Module.
- */
-pte_t *va_to_pte(struct task_struct *tsk, unsigned long address)
-{
-        pgd_t *dir;
-        pmd_t *pmd;
-        pte_t *pte;
-        
-        dir = pgd_offset(tsk->mm, address & PAGE_MASK);
-        if (dir)
-        {
-                pmd = pmd_offset(dir, address & PAGE_MASK);
-                if (pmd && pmd_present(*pmd))
-                {
-                        pte = pte_offset(pmd, address & PAGE_MASK);
-                        if (pte && pte_present(*pte))
-                        {
-                                return(pte);
-                        }
-                } else
-                {
-                        return (0);
-                }
-        } else
-        {
-                return (0);
-        }
-        return (0);
-}
 
 unsigned long va_to_phys(unsigned long address)
 {
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.19/linux/arch/ppc/mm/init.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/ppc/mm/init.c	Thu Oct  7 10:17:09 1999
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.183 1999/09/05 19:29:44 cort Exp $
+ *  $Id: init.c,v 1.188 1999/09/18 18:40:44 dmalek Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -47,7 +47,7 @@
 #include <asm/residual.h>
 #include <asm/uaccess.h>
 #include <asm/8xx_immap.h>
-#include <asm/mbx.h>
+#include <asm/mpc8xx.h>
 #include <asm/smp.h>
 #include <asm/bootx.h>
 #include <asm/machdep.h>
@@ -73,7 +73,7 @@
 unsigned long ioremap_bot;
 unsigned long avail_start;
 extern int num_memory;
-extern struct mem_info memory[NUM_MEMINFO];
+extern struct mem_info memory[];
 extern boot_infos_t *boot_infos;
 #ifndef __SMP__
 struct pgtable_cache_struct quicklists;
@@ -86,9 +86,9 @@
 unsigned long *apus_find_end_of_memory(void);
 unsigned long *gemini_find_end_of_memory(void);
 extern unsigned long *find_end_of_memory(void);
-#ifdef CONFIG_MBX
-unsigned long *mbx_find_end_of_memory(void);
-#endif /* CONFIG_MBX */
+#ifdef CONFIG_8xx
+unsigned long *m8xx_find_end_of_memory(void);
+#endif /* CONFIG_8xx */
 static void mapin_ram(void);
 void map_page(unsigned long va, unsigned long pa, int flags);
 extern void die_if_kernel(char *,struct pt_regs *,long);
@@ -997,9 +997,6 @@
  */
 void __init MMU_init(void)
 {
-#ifdef __SMP__
-	if ( first_cpu_booted ) return;
-#endif /* __SMP__ */
 	if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111);
 #ifndef CONFIG_8xx
 	if (have_of)
@@ -1054,9 +1051,6 @@
 		setbat(0, 0xfff00000, 0xfff00000, 0x00020000, RAM_PAGE);
 		/* Map chip and ZorroII memory */
 		setbat(1, zTwoBase,   0x00000000, 0x01000000, IO_PAGE);
-		/* Note: a temporary hack in arch/ppc/amiga/setup.c
-		   (kernel_map) remaps individual IO regions to
-		   0x90000000. */
 		break;
 	case _MACH_gemini:
 		setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE);
@@ -1065,9 +1059,9 @@
 	}
 	ioremap_bot = ioremap_base;
 #else /* CONFIG_8xx */
-#ifdef CONFIG_MBX
-	end_of_DRAM = mbx_find_end_of_memory();
-#endif /* CONFIG_MBX */
+
+	end_of_DRAM = m8xx_find_end_of_memory();
+
         /* Map in all of RAM starting at KERNELBASE */
         mapin_ram();
 
@@ -1076,13 +1070,25 @@
          * All of this fits into the same 4Mbyte region, so it only
          * requires one page table page.
          */
+        ioremap(IMAP_ADDR, IMAP_SIZE);
+#ifdef CONFIG_MBX
         ioremap(NVRAM_ADDR, NVRAM_SIZE);
         ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE);
-        ioremap(IMAP_ADDR, IMAP_SIZE);
         ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE);
-	/* ide needs to be able to get at PCI space -- Cort */
-        ioremap(0x80000000, 0x4000);
-        ioremap(0x81000000, 0x4000);
+
+	/* Map some of the PCI/ISA I/O space to get the IDE interface.
+	*/
+        ioremap(PCI_ISA_IO_ADDR, 0x4000);
+        ioremap(PCI_IDE_ADDR, 0x4000);
+#endif
+#ifdef CONFIG_RPXLITE
+	ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE);
+	ioremap(HIOX_CSR_ADDR, HIOX_CSR_SIZE);
+#endif
+#ifdef CONFIG_RPXCLASSIC
+        ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE);
+	ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE);
+#endif
 #endif /* CONFIG_8xx */
 	if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211);
 }
@@ -1231,55 +1237,8 @@
 	mem_init_done = 1;
 }
 
-#ifdef CONFIG_MBX
-/*
- * This is a big hack right now, but it may turn into something real
- * someday.
- *
- * For the MBX860 (at this time anyway), there is nothing to initialize
- * associated the PROM.  Rather than include all of the prom.c
- * functions in the image just to get prom_init, all we really need right
- * now is the initialization of the physical memory region.
- */
-unsigned long __init *mbx_find_end_of_memory(void)
-{
-	unsigned long kstart, ksize;
-	bd_t	*binfo;
-	volatile memctl8xx_t	*mcp;
-	unsigned long *ret;
-	
-	binfo = (bd_t *)res;
-
-	/*
-	 * The MBX does weird things with the mmaps for ram.
-	 * If there's no DIMM, it puts the onboard DRAM at
-	 * 0, if there is a DIMM it sticks it at 0 and puts
-	 * the DRAM at the end of the DIMM.
-	 *
-	 * In fact, it might be the best idea to just read the DRAM
-	 * config registers and set the mem areas accordingly.
-	 */
-	mcp = (memctl8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_memctl));
-	append_mem_piece(&phys_mem, 0, binfo->bi_memsize);
-#if 0
-	phys_mem.regions[0].address = 0;
-	phys_mem.regions[0].size = binfo->bi_memsize;	
-	phys_mem.n_regions = 1;
-#endif	
-	
-	ret = __va(phys_mem.regions[0].address+
-		   phys_mem.regions[0].size);
-
-	phys_avail = phys_mem;
-
-	kstart = __pa(_stext);	/* should be 0 */
-	ksize = PAGE_ALIGN(_end - _stext);
-	remove_mem_piece(&phys_avail, kstart, ksize, 0);
-	return ret;
-}
-#endif /* CONFIG_MBX */
-
 #ifndef CONFIG_8xx
+#if defined(CONFIG_PMAC) || defined(CONFIG_PPC_ALL)
 /*
  * On systems with Open Firmware, collect information about
  * physical RAM and which pieces are already in use.
@@ -1372,7 +1331,9 @@
 #undef RAM_LIMIT
 	return __va(total);
 }
+#endif /* defined(CONFIG_PMAC) || defined(CONFIG_PPC_ALL) */
 
+#if defined(CONFIG_PREP) || defined(CONFIG_PPC_ALL)
 /*
  * This finds the amount of physical ram and does necessary
  * setup for prep.  This is pretty architecture specific so
@@ -1404,7 +1365,10 @@
 
 	return (__va(total));
 }
+#endif /* defined(CONFIG_PREP) || defined(CONFIG_PPC_ALL) */
 
+
+#if defined(CONFIG_GEMINI) || defined(CONFIG_PPC_ALL)
 unsigned long __init *gemini_find_end_of_memory(void)
 {
 	unsigned long total, kstart, ksize, *ret;
@@ -1425,6 +1389,7 @@
 	remove_mem_piece( &phys_avail, kstart, ksize, 0 );
 	return ret;
 }
+#endif /* defined(CONFIG_GEMINI) || defined(CONFIG_PPC_ALL) */
 
 #ifdef CONFIG_APUS
 #define HARDWARE_MAPPED_SIZE (512*1024)
@@ -1601,5 +1566,38 @@
 				   (unsigned long) &hash_page[1]);
 	}
 	if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
+}
+#else /* CONFIG_8xx */
+/*
+ * This is a big hack right now, but it may turn into something real
+ * someday.
+ *
+ * For the 8xx boards (at this time anyway), there is nothing to initialize
+ * associated the PROM.  Rather than include all of the prom.c
+ * functions in the image just to get prom_init, all we really need right
+ * now is the initialization of the physical memory region.
+ */
+unsigned long __init *m8xx_find_end_of_memory(void)
+{
+	unsigned long kstart, ksize;
+	bd_t	*binfo;
+	unsigned long *ret;
+	extern unsigned char __res[];
+	
+	binfo = (bd_t *)__res;
+
+	phys_mem.regions[0].address = 0;
+	phys_mem.regions[0].size = binfo->bi_memsize;	
+	phys_mem.n_regions = 1;
+	
+	ret = __va(phys_mem.regions[0].address+
+		   phys_mem.regions[0].size);
+
+	phys_avail = phys_mem;
+
+	kstart = __pa(_stext);	/* should be 0 */
+	ksize = PAGE_ALIGN(_end - _stext);
+	remove_mem_piece(&phys_avail, kstart, ksize, 0);
+	return ret;
 }
 #endif /* ndef CONFIG_8xx */
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/vmlinux.lds linux/arch/ppc/vmlinux.lds
--- v2.3.19/linux/arch/ppc/vmlinux.lds	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/vmlinux.lds	Thu Oct  7 10:17:09 1999
@@ -88,6 +88,7 @@
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
+
   . = ALIGN(4096);
   __pmac_begin = .;
   .text.pmac : { *(.text.pmac) }
@@ -101,6 +102,13 @@
   .data.prep : { *(.data.prep) }
   . = ALIGN(4096);
   __prep_end = .;
+
+  . = ALIGN(4096);
+  __apus_begin = .;
+  .text.apus : { *(.text.apus) }
+  .data.apus : { *(.data.apus) }
+  . = ALIGN(4096);
+  __apus_end = .;
 
   . = ALIGN(4096);
   __apus_begin = .;
diff -u --recursive --new-file v2.3.19/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c
--- v2.3.19/linux/arch/ppc/xmon/start.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/xmon/start.c	Thu Oct  7 10:17:09 1999
@@ -1,19 +1,26 @@
 /*
  * Copyright (C) 1996 Paul Mackerras.
  */
+#include <linux/config.h>
 #include <linux/string.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/adb.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
 #include <asm/prom.h>
+#include <asm/bootx.h>
 
 static volatile unsigned char *sccc, *sccd;
 unsigned long TXRDY, RXRDY;
 extern void xmon_printf(const char *fmt, ...);
+extern void map_bootx_text(void);
+extern void drawchar(char);
+extern void drawstring(const char *str);
 
-static int console = 1;
+static int console = 0;
+static int use_screen = 0;
 
 void buf_access(void)
 {
@@ -29,10 +36,21 @@
 	if ( _machine == _MACH_Pmac )
 	{
 		struct device_node *np;
+		extern boot_infos_t *boot_infos;
+		unsigned long addr;
+
+#ifdef CONFIG_BOOTX_TEXT
+		if (boot_infos != 0 && find_via_pmu()) {
+			printk(KERN_INFO "xmon uses screen and keyboard\n");
+			use_screen = 1;
+			map_bootx_text();
+			return;
+		}
+#endif
 #ifdef CHRP_ESCC
-		unsigned long addr = 0xc1013020;
+		addr = 0xc1013020;
 #else
-		unsigned long addr = 0xf3013020;
+		addr = 0xf3013020;
 #endif
 		TXRDY = 4;
 		RXRDY = 1;
@@ -73,11 +91,19 @@
     char *p = ptr;
     int i, ct;
 
+#ifdef CONFIG_BOOTX_TEXT
+    if (use_screen) {
+	/* write it on the screen */
+	for (i = 0; i < nb; ++i)
+	    drawchar(*p++);
+	return nb;
+    }
+#endif
     if (!scc_initialized)
 	xmon_init_scc();
     for (i = 0; i < nb; ++i) {
 	while ((*sccc & TXRDY) == 0)
-	    if (adb_hardware == ADB_VIAPMU)
+	    if (sys_ctrler == SYS_CTRLER_PMU)
 		pmu_poll();
 	buf_access();
 	if ( console && (*p != '\r'))
@@ -92,17 +118,85 @@
     return i;
 }
 
+int xmon_wants_key;
+int xmon_pmu_keycode;
+
+#ifdef CONFIG_BOOTX_TEXT
+static int xmon_pmu_shiftstate;
+
+static unsigned char xmon_keytab[128] =
+	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
+	"yt123465=97-80o]"				/* 0x10 - 0x1f */
+	"u[ip\rlj'k;\\,/nm."				/* 0x20 - 0x2f */
+	"\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"		/* 0x30 - 0x3f */
+	"\0.\0*\0+\0\0\0\0\0/\r\0-\0"			/* 0x40 - 0x4f */
+	"\0\0000123456789\0\0\0";			/* 0x50 - 0x5f */
+
+static unsigned char xmon_shift_keytab[128] =
+	"ASDFHGZXCV\000BQWER"				/* 0x00 - 0x0f */
+	"YT!@#$^%+(&=*)}O"				/* 0x10 - 0x1f */
+	"U{IP\rLJ\"K:|<?NM>"				/* 0x20 - 0x2f */
+	"\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"		/* 0x30 - 0x3f */
+	"\0.\0*\0+\0\0\0\0\0/\r\0-\0"			/* 0x40 - 0x4f */
+	"\0\0000123456789\0\0\0";			/* 0x50 - 0x5f */
+
+static int
+xmon_get_pmu_key(void)
+{
+	int k, t, on;
+
+	xmon_wants_key = 1;
+	for (;;) {
+		xmon_pmu_keycode = -1;
+		t = 0;
+		on = 0;
+		do {
+			if (--t < 0) {
+				on = 1 - on;
+				drawchar(on? 0xdb: 0x20);
+				drawchar('\b');
+				t = 200000;
+			}
+			pmu_poll();
+		} while (xmon_pmu_keycode == -1);
+		k = xmon_pmu_keycode;
+		if (on)
+			drawstring(" \b");
+
+		/* test for shift keys */
+		if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
+			xmon_pmu_shiftstate = (k & 0x80) == 0;
+			continue;
+		}
+		if (k >= 0x80)
+			continue;	/* ignore up transitions */
+		k = (xmon_pmu_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
+		if (k != 0)
+			break;
+	}
+	xmon_wants_key = 0;
+	return k;
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
 int
 xmon_read(void *handle, void *ptr, int nb)
 {
     char *p = ptr;
     int i;
 
+#ifdef CONFIG_BOOTX_TEXT
+    if (use_screen) {
+	for (i = 0; i < nb; ++i)
+	    *p++ = xmon_get_pmu_key();
+	return i;
+    }
+#endif
     if (!scc_initialized)
 	xmon_init_scc();
     for (i = 0; i < nb; ++i) {
 	while ((*sccc & RXRDY) == 0)
-	    if (adb_hardware == ADB_VIAPMU)
+	    if (sys_ctrler == SYS_CTRLER_PMU)
 		pmu_poll();
 	buf_access();
 #if 0	
diff -u --recursive --new-file v2.3.19/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.19/linux/arch/sparc64/config.in	Fri Sep 10 23:57:28 1999
+++ linux/arch/sparc64/config.in	Thu Oct  7 12:50:23 1999
@@ -146,14 +146,10 @@
 	if [ "$CONFIG_PCI" != "n" ]; then
 	  dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 	  if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
-	    bool '   Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
-	    bool '   Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
-	    if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
-	      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
-	    fi
-	    bool '   Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
+	    bool '   Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+	    int  '   Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8
 	    bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
-	    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+	    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
 	  fi
 	  dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
 	  if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then
diff -u --recursive --new-file v2.3.19/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.19/linux/arch/sparc64/defconfig	Fri Sep 10 23:57:28 1999
+++ linux/arch/sparc64/defconfig	Thu Oct  7 12:50:23 1999
@@ -207,10 +207,9 @@
 CONFIG_SCSI_SUNESP=y
 CONFIG_SCSI_QLOGICPTI=m
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TAGGED_QUEUEING is not set
-# CONFIG_OVERRIDE_CMDS is not set
-# CONFIG_AIC7XXX_PAGE_ENABLE is not set
-# CONFIG_AIC7XXX_PROC_STATS is not set
+# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+# CONFIG_CMDS_PER_DEVICE is not set
+CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=5
 CONFIG_SCSI_NCR53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
diff -u --recursive --new-file v2.3.19/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c
--- v2.3.19/linux/arch/sparc64/kernel/pci.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/sparc64/kernel/pci.c	Thu Oct  7 12:23:21 1999
@@ -202,11 +202,6 @@
 {
 }
 
-int pcibios_assign_resource(struct pci_dev *pdev, int resource)
-{
-	return 0;
-}
-
 char * __init pcibios_setup(char *str)
 {
 	if (!strcmp(str, "onboardfirst")) {
diff -u --recursive --new-file v2.3.19/linux/drivers/Makefile linux/drivers/Makefile
--- v2.3.19/linux/drivers/Makefile	Tue Sep  7 12:14:06 1999
+++ linux/drivers/Makefile	Thu Oct  7 14:53:43 1999
@@ -11,7 +11,7 @@
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \
 				macintosh video dio zorro fc4 usb \
-				nubus tc ap1000 atm
+				nubus tc ap1000 atm pcmcia
 
 ifdef CONFIG_DIO
 SUB_DIRS += dio
@@ -22,8 +22,12 @@
 SUB_DIRS += pci
 endif
 
-ifdef CONFIG_PCMCIA
+ifeq ($(CONFIG_PCMCIA),y)
 SUB_DIRS += pcmcia
+else
+  ifeq ($(CONFIG_PCMCIA),m)
+  MOD_SUB_DIRS += pcmcia
+  endif
 endif
 
 ifdef CONFIG_SBUS
@@ -117,7 +121,6 @@
 
 ifeq ($(CONFIG_AP1000),y)
 SUB_DIRS += ap1000
-ALL_SUB_DIRS += ap1000
 endif
 
 ifeq ($(CONFIG_FC4),y)
diff -u --recursive --new-file v2.3.19/linux/drivers/atm/Config.in linux/drivers/atm/Config.in
--- v2.3.19/linux/drivers/atm/Config.in	Fri Sep 10 23:57:28 1999
+++ linux/drivers/atm/Config.in	Thu Oct  7 10:17:09 1999
@@ -4,44 +4,44 @@
 mainmenu_option next_comment
 comment 'ATM drivers'
 if [ "$CONFIG_INET" = "y" ]; then
-  tristate 'ATM over TCP' CONFIG_ATM_TCP y
+   tristate 'ATM over TCP' CONFIG_ATM_TCP
 fi
 if [ "$CONFIG_PCI" = "y" ]; then
-  tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI y
-  if [ ! "$CONFIG_ATM_ENI" = "n" ]; then
-    bool '  Enable extended debugging' CONFIG_ATM_ENI_DEBUG n
-    bool '  Fine-tune burst settings' CONFIG_ATM_ENI_TUNE_BURST n
-    if [ "$CONFIG_ATM_ENI_TUNE_BURST" = "y" ]; then
-      bool '    Enable 16W TX bursts (discouraged)' CONFIG_ATM_ENI_BURST_TX_16W n
-      bool '    Enable 8W TX bursts (recommended)' CONFIG_ATM_ENI_BURST_TX_8W y
-      bool '    Enable 4W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_4W n
-      bool '    Enable 2W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_2W n
-      bool '    Enable 16W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_16W n
-      bool '    Enable 8W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_8W n
-      bool '    Enable 4W RX bursts (recommended)' CONFIG_ATM_ENI_BURST_RX_4W y
-      bool '    Enable 2W RX bursts (optional)' CONFIG_ATM_ENI_BURST_RX_2W n
-    fi
-  fi
-  tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM y
-  if [ ! "$CONFIG_ATM_ZATM" = "n" ]; then
-    bool '  Enable extended debugging' CONFIG_ATM_ZATM_DEBUG n
-    bool '  Enable usec resolution timestamps' CONFIG_ATM_ZATM_EXACT_TS y
-  fi
-#  bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y
-#  if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then
-#    bool '  Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n
-#  fi
-  tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR
-  if [ "$CONFIG_ATM_NICSTAR" != "n" ]; then
-    bool '  Use suni PHY driver' CONFIG_ATM_NICSTAR_USE_SUNI
-  fi
-  tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR
-  if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then
-    bool '  Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG
-  fi
-  tristate 'Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)' CONFIG_ATM_HORIZON y
-  if [ "$CONFIG_ATM_HORIZON" != "n" ]; then
-    bool '  Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG
-  fi
+   tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI
+   if [ ! "$CONFIG_ATM_ENI" = "n" ]; then
+      bool '  Enable extended debugging' CONFIG_ATM_ENI_DEBUG
+      bool '  Fine-tune burst settings' CONFIG_ATM_ENI_TUNE_BURST
+      if [ "$CONFIG_ATM_ENI_TUNE_BURST" = "y" ]; then
+	 bool '    Enable 16W TX bursts (discouraged)' CONFIG_ATM_ENI_BURST_TX_16W
+	 bool '    Enable 8W TX bursts (recommended)' CONFIG_ATM_ENI_BURST_TX_8W
+	 bool '    Enable 4W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_4W
+	 bool '    Enable 2W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_2W
+	 bool '    Enable 16W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_16W
+	 bool '    Enable 8W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_8W
+	 bool '    Enable 4W RX bursts (recommended)' CONFIG_ATM_ENI_BURST_RX_4W
+	 bool '    Enable 2W RX bursts (optional)' CONFIG_ATM_ENI_BURST_RX_2W
+      fi
+   fi
+   tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM
+   if [ ! "$CONFIG_ATM_ZATM" = "n" ]; then
+      bool '  Enable extended debugging' CONFIG_ATM_ZATM_DEBUG
+      bool '  Enable usec resolution timestamps' CONFIG_ATM_ZATM_EXACT_TS
+   fi
+#   bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y
+#   if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then
+#      bool '  Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n
+#   fi
+   tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR
+   if [ "$CONFIG_ATM_NICSTAR" != "n" ]; then
+      bool '  Use suni PHY driver' CONFIG_ATM_NICSTAR_USE_SUNI
+   fi
+   tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR
+   if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then
+      bool '  Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG
+   fi
+   tristate 'Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)' CONFIG_ATM_HORIZON
+   if [ "$CONFIG_ATM_HORIZON" != "n" ]; then
+      bool '  Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG
+   fi
 fi
 endmenu
diff -u --recursive --new-file v2.3.19/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.3.19/linux/drivers/block/ide-pci.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/ide-pci.c	Fri Oct  8 10:06:21 1999
@@ -507,7 +507,7 @@
 		if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
 			continue;	/* no room in ide_hwifs[] */
 		if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
-			ide_init_hwif_ports(&hwif->hw, base, (ctl + 2), NULL);
+			ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
 			memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
 			hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
 		}
diff -u --recursive --new-file v2.3.19/linux/drivers/char/defkeymap.c linux/drivers/char/defkeymap.c
--- v2.3.19/linux/drivers/char/defkeymap.c	Thu Aug 12 10:17:17 1999
+++ linux/drivers/char/defkeymap.c	Thu Oct  7 10:17:09 1999
@@ -233,7 +233,6 @@
 	{'A', 'A', '\305'},	{'a', 'a', '\345'},
 	{'A', 'E', '\306'},	{'a', 'e', '\346'},
 	{',', 'C', '\307'},	{',', 'c', '\347'},
-	{'\'', 'C', '\307'},	{'\'', 'c', '\347'},
 	{'`', 'E', '\310'},	{'`', 'e', '\350'},
 	{'\'', 'E', '\311'},	{'\'', 'e', '\351'},
 	{'^', 'E', '\312'},	{'^', 'e', '\352'},
@@ -260,4 +259,4 @@
 	{'s', 'z', '\337'},	{'i', 'j', '\377'},
 };
 
-unsigned int accent_table_size = 70;
+unsigned int accent_table_size = 68;
diff -u --recursive --new-file v2.3.19/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.3.19/linux/drivers/char/mem.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/char/mem.c	Thu Oct  7 10:17:09 1999
@@ -50,7 +50,7 @@
 #ifdef CONFIG_MDA_CONSOLE
 extern void mda_console_init(void);
 #endif
-#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
+#if defined(CONFIG_ADB)
 extern void adbdev_init(void);
 #endif
 #ifdef CONFIG_USB
@@ -667,7 +667,7 @@
 #ifdef CONFIG_VIDEO_BT848
 	i2c_init();
 #endif
-#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
+#if defined(CONFIG_ADB)
 	adbdev_init();
 #endif
 #ifdef CONFIG_VIDEO_DEV
diff -u --recursive --new-file v2.3.19/linux/drivers/char/pms.c linux/drivers/char/pms.c
--- v2.3.19/linux/drivers/char/pms.c	Wed Jun  2 11:29:13 1999
+++ linux/drivers/char/pms.c	Fri Oct  8 10:06:12 1999
@@ -22,6 +22,7 @@
 #include <linux/malloc.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
@@ -1024,21 +1025,11 @@
 	return 0;
 }
 
-static void shutdown_mediavision(void)
-{
-	release_region(io_port,3);
-	release_region(0x9A01, 1);
-}
-
 /*
- *	Module stuff
+ *	Initialization and module stuff
  */
  
-#ifdef MODULE
-int init_module(void)
-#else
-int init_pms_cards(struct video_init *v)
-#endif
+static int __init init_pms_cards(void)
 {
 	printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
 	
@@ -1057,15 +1048,21 @@
 	return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER);
 }
 
-#ifdef MODULE
-
 MODULE_PARM(io_port,"i");
 MODULE_PARM(mem_base,"i");
 
-void cleanup_module(void)
+static void __exit shutdown_mediavision(void)
+{
+	release_region(io_port,3);
+	release_region(0x9A01, 1);
+}
+
+static void __exit cleanup_pms_module(void)
 {
 	shutdown_mediavision();
 	video_unregister_device((struct video_device *)&pms_device);
 }
 
-#endif
+module_init(init_pms_cards);
+module_exit(cleanup_pms_module);
+
diff -u --recursive --new-file v2.3.19/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.3.19/linux/drivers/char/ppdev.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/ppdev.c	Thu Oct  7 14:10:06 1999
@@ -34,8 +34,12 @@
  *   YIELD	parport_yield_blocking
  *   WCTLONIRQ	on interrupt, set control lines
  *   CLRIRQ	clear (and return) interrupt count
+ *   SETTIME	sets device timeout (struct timeval)
+ *   GETTIME    gets device timeout (struct timeval)
  * read/write	read or write in current IEEE 1284 protocol
  * select	wait for interrupt (in readfds)
+ *
+ * Added SETTIME/GETTIME ioctl, Fred Barnes 1999.
  */
 
 #include <linux/module.h>
@@ -74,6 +78,9 @@
 #define PP_BUFFER_SIZE 256
 #define PARDEVICE_MAX 8
 
+/* ROUND_UP macro from fs/select.c */
+#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
+
 static inline void enable_irq (struct pp_struct *pp)
 {
 	struct parport *port = pp->pdev->port;
@@ -356,6 +363,8 @@
 		unsigned char mask;
 		int mode;
 		int ret;
+		struct timeval par_timeout;
+		long to_jiffies;
 
 	case PPRSTATUS:
 		reg = parport_read_status (port);
@@ -449,6 +458,33 @@
 		if (copy_to_user ((int *) arg, &ret, sizeof (ret)))
 			return -EFAULT;
 		atomic_sub (ret, &pp->irqc);
+		return 0;
+
+	case PPSETTIME:
+		if (copy_from_user (&par_timeout, (struct timeval *)arg,
+				    sizeof(struct timeval))) {
+			return -EFAULT;
+		}
+		/* Convert to jiffies, place in pp->pdev->timeout */
+		if ((par_timeout.tv_sec < 0) || (par_timeout.tv_usec < 0)) {
+			return -EINVAL;
+		}
+		to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
+		to_jiffies += par_timeout.tv_sec * (long)HZ;
+		if (to_jiffies <= 0) {
+			return -EINVAL;
+		}
+		pp->pdev->timeout = to_jiffies;
+		return 0;
+
+	case PPGETTIME:
+		to_jiffies = pp->pdev->timeout;
+		par_timeout.tv_sec = to_jiffies / HZ;
+		par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ);
+		if (copy_to_user ((struct timeval *)arg, &par_timeout,
+				  sizeof(struct timeval))) {
+			return -EFAULT;
+		}
 		return 0;
 
 	default:
diff -u --recursive --new-file v2.3.19/linux/drivers/char/ppdev.h linux/drivers/char/ppdev.h
--- v2.3.19/linux/drivers/char/ppdev.h	Fri Jul 30 12:28:26 1999
+++ linux/drivers/char/ppdev.h	Thu Oct  7 14:10:06 1999
@@ -10,6 +10,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
+ * Added PPGETTIME/PPSETTIME, Fred Barnes, 1999
  */
 
 #define PP_MAJOR	99
@@ -72,3 +73,9 @@
 
 /* Set the IEEE 1284 phase that we're in (e.g. IEEE1284_PH_FWD_IDLE) */
 #define PPSETPHASE	_IOW(PP_IOCTL, 0x94, int)
+
+/* Set and get port timeout (struct timeval's) */
+#define PPGETTIME	_IOW(PP_IOCTL, 0x95, struct timeval)
+#define PPSETTIME	_IOR(PP_IOCTL, 0x96, struct timeval)
+
+
diff -u --recursive --new-file v2.3.19/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile
--- v2.3.19/linux/drivers/macintosh/Makefile	Mon Jun  7 12:12:32 1999
+++ linux/drivers/macintosh/Makefile	Thu Oct  7 10:17:09 1999
@@ -13,13 +13,11 @@
 MOD_SUB_DIRS := $(SUB_DIRS)
 
 L_TARGET := macintosh.a
+L_OBJS   :=
 M_OBJS   :=
 
-ifndef CONFIG_MBX
-L_OBJS   := via-cuda.o macio-adb.o via-pmu.o mediabay.o
-endif
-ifeq ($(CONFIG_MAC_KEYBOARD),y)
-LX_OBJS  := adb.o
+ifeq ($(CONFIG_PMAC_PBOOK),y)
+  L_OBJS += mediabay.o
 endif
 
 ifeq ($(CONFIG_MAC_SERIAL),y)
@@ -38,8 +36,36 @@
   endif
 endif
 
-ifdef CONFIG_MAC_KEYBOARD
-L_OBJS += mac_keyb.o
+ifdef CONFIG_ADB
+  LX_OBJS  := adb.o
+endif
+
+ifdef CONFIG_ADB_KEYBOARD
+  L_OBJS += mac_keyb.o
+endif
+
+ifdef CONFIG_ADB_MACII
+  L_OBJS += via-macii.o
+endif
+
+ifdef CONFIG_ADB_MACIISI
+  L_OBJS += via-maciisi.o
+endif
+
+ifdef CONFIG_ADB_CUDA
+  L_OBJS += via-cuda.o
+endif
+
+ifdef CONFIG_ADB_IOP
+  L_OBJS += adb-iop.o
+endif
+
+ifdef CONFIG_ADB_PMU
+  L_OBJS += via-pmu.o
+endif
+
+ifdef CONFIG_ADB_MACIO
+  L_OBJS += macio-adb.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.19/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
--- v2.3.19/linux/drivers/macintosh/adb.c	Wed Aug  4 16:36:41 1999
+++ linux/drivers/macintosh/adb.c	Thu Oct  7 10:17:09 1999
@@ -24,29 +24,59 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/notifier.h>
 #include <linux/wait.h>
-#include <asm/prom.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
-#include <asm/pmu.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_PPC
+#include <asm/prom.h>
 #include <asm/hydra.h>
-#include <linux/init.h>
+#endif
 
 EXPORT_SYMBOL(adb_controller);
 EXPORT_SYMBOL(adb_client_list);
-EXPORT_SYMBOL(adb_hardware);
 
-struct adb_controller *adb_controller = NULL;
+extern struct adb_driver via_macii_driver;
+extern struct adb_driver via_maciisi_driver;
+extern struct adb_driver via_cuda_driver;
+extern struct adb_driver adb_iop_driver;
+extern struct adb_driver via_pmu_driver;
+extern struct adb_driver macio_adb_driver;
+
+static struct adb_driver *adb_driver_list[] = {
+#ifdef CONFIG_ADB_MACII
+	&via_macii_driver,
+#endif
+#ifdef CONFIG_ADB_MACIISI
+	&via_maciisi_driver,
+#endif
+#ifdef CONFIG_ADB_CUDA
+	&via_cuda_driver,
+#endif
+#ifdef CONFIG_ADB_IOP
+	&adb_iop_driver,
+#endif
+#ifdef CONFIG_ADB_PMU
+	&via_pmu_driver,
+#endif
+#ifdef CONFIG_ADB_MACIO
+	&macio_adb_driver,
+#endif
+	NULL
+};
+
+struct adb_driver *adb_controller;
 struct notifier_block *adb_client_list = NULL;
-enum adb_hw adb_hardware = ADB_NONE;
+static int adb_got_sleep = 0;
 
 #ifdef CONFIG_PMAC_PBOOK
-static int adb_notify_sleep(struct notifier_block *, unsigned long, void *);
-static struct notifier_block adb_sleep_notifier = {
+static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier adb_sleep_notifier = {
 	adb_notify_sleep,
-	NULL,
-	0
+	SLEEP_LEVEL_ADB,
 };
 #endif
 
@@ -109,6 +139,15 @@
 			adb_request(&req, NULL, ADBREQ_SYNC, 3,
 				    (i<< 4) | 0xb, (highFree | 0x60), 0xfe);
 			/*
+			 * See if anybody actually moved. This is suggested
+			 * by HW TechNote 01:
+			 *
+			 * http://developer.apple.com/technotes/hw/hw_01.html
+			 */
+			adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+				    (highFree << 4) | 0xf);
+			if (req.reply_len <= 1) continue;
+			/*
 			 * Test whether there are any device(s) left
 			 * at address i.
 			 */
@@ -159,49 +198,73 @@
 	return devmask;
 }
 
-void adb_init(void)
+int __init adb_init(void)
 {
+	struct adb_driver *driver;
+	int i;
+
+#ifdef CONFIG_PPC
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-		return;
+		return 0;
+#endif
+#ifdef CONFIG_MAC
+	if (!MACH_IS_MAC)
+		return 0;
+#endif
 
-	via_cuda_init();
-	via_pmu_init();
-	macio_adb_init();
-	
-	if (adb_controller == NULL)
+	adb_controller = NULL;
+
+	i = 0;
+	while ((driver = adb_driver_list[i++]) != NULL) {
+		if (!driver->probe()) {
+			adb_controller = driver;
+			break;
+		}
+	}
+	if ((adb_controller == NULL) || adb_controller->init()) {
 		printk(KERN_WARNING "Warning: no ADB interface detected\n");
-	else
-	{
-		adb_hardware = adb_controller->kind;
+	} else {
 #ifdef CONFIG_PMAC_PBOOK
-		notifier_chain_register(&sleep_notifier_list,
-					&adb_sleep_notifier);
+		pmu_register_sleep_notifier(&adb_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 
 		adb_reset_bus();
 	}
+	return 0;
 }
 
+__initcall(adb_init);
 
 #ifdef CONFIG_PMAC_PBOOK
 /*
  * notify clients before sleep and reset bus afterwards
  */
 int
-adb_notify_sleep(struct notifier_block *this, unsigned long code, void *x)
+adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
 	int ret;
 	
-	switch (code) {
-		case PBOOK_SLEEP:
-			ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
-			if (ret & NOTIFY_STOP_MASK)
-				return -EBUSY;
-		case PBOOK_WAKE:
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		adb_got_sleep = 1;
+		ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
+		if (ret & NOTIFY_STOP_MASK)
+			return PBOOK_SLEEP_REFUSE;
+		break;
+	case PBOOK_SLEEP_REJECT:
+		if (adb_got_sleep) {
+			adb_got_sleep = 0;
 			adb_reset_bus();
-			break;
+		}
+		break;
+		
+	case PBOOK_SLEEP_NOW:
+		break;
+	case PBOOK_WAKE:
+		adb_reset_bus();
+		break;
 	}
-	return NOTIFY_DONE;
+	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
@@ -277,6 +340,9 @@
 		req->data[i+1] = va_arg(list, int);
 	va_end(list);
 
+	if (flags & ADBREQ_NOSEND)
+		return 0;
+
 	return adb_controller->send_request(req, flags & ADBREQ_SYNC);
 }
 
@@ -413,7 +479,7 @@
 {
 	struct adbdev_state *state;
 
-	if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/)
+	if (MINOR(inode->i_rdev) > 0 || adb_controller == NULL)
 		return -ENXIO;
 	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
 	if (state == 0)
@@ -540,6 +606,7 @@
 		goto out;
 
 	atomic_inc(&state->n_pending);
+	if (adb_controller == NULL) return -ENXIO;
 
 	/* Special case for ADB_BUSRESET request, all others are sent to
 	   the controller */
@@ -582,8 +649,15 @@
 
 void adbdev_init()
 {
+#ifdef CONFIG_PPC
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-		return;		
+		return;
+#endif
+#ifdef CONFIG_MAC
+	if (!MACH_IS_MAC)
+		return;
+#endif
+
 	if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
 		printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
 }
diff -u --recursive --new-file v2.3.19/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- v2.3.19/linux/drivers/macintosh/mac_keyb.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/macintosh/mac_keyb.c	Thu Oct  7 10:17:09 1999
@@ -39,12 +39,13 @@
 #include <linux/init.h>
 #include <linux/tty_flip.h>
 #include <linux/config.h>
+#include <linux/notifier.h>
 
 #include <asm/bitops.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
-#include <asm/pmu.h>
 
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
 #include <linux/kbd_kern.h>
 #include <linux/kbd_ll.h>
 
@@ -239,7 +240,7 @@
 static void init_turbomouse(int id);
 static void init_microspeed(int id);
 
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
 /* XXX: Hook for mouse driver */
 void (*adb_mouse_interrupt_hook)(unsigned char *, int);
 int adb_emulate_buttons = 0;
@@ -250,6 +251,7 @@
 extern int console_loglevel;
 
 extern struct kbd_struct kbd_table[];
+extern wait_queue_head_t keypress_wait;
 
 extern void handle_scancode(unsigned char, int);
 
@@ -334,7 +336,7 @@
 	if (!repeat)
 		del_timer(&repeat_timer);
 
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
 	/*
 	 * XXX: Add mouse button 2+3 fake codes here if mouse open.
 	 *	Keep track of 'button' states here as we only send 
@@ -364,7 +366,7 @@
 		}
 		return;
 	}
-#endif /* CONFIG_ADBMOUSE */
+#endif /* CONFIG_ADB_MOUSE */
 
 	if (kbd->kbdmode != VC_RAW) {
 		if (!up_flag && !dont_repeat[keycode]) {
@@ -420,7 +422,7 @@
 	}
 }
 
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
 static void
 mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
 {
@@ -552,7 +554,7 @@
 		}
 	}
 }
-#endif /* CONFIG_ADBMOUSE */
+#endif /* CONFIG_ADB_MOUSE */
 
 /* XXX Needs to get rid of this, see comments in pmu.c */
 extern int backlight_level;
@@ -566,7 +568,11 @@
 	 */
 	 
 	/* Ignore data from register other than 0 */
+#if 0
 	if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2))
+#else
+	if ((data[0] & 0x3) || (nb < 2))
+#endif
 		return;
 		
 	switch (data[1]&0xf )
@@ -592,22 +598,26 @@
 		/* brightness decrease */
 		case 0xa:
 			/* down event */
+#ifdef CONFIG_PPC
 			if ( data[1] == (data[1]&0xf) ) {
 				if (backlight_level > 2)
 					pmu_set_brightness(backlight_level-2);
 				else
 					pmu_set_brightness(0);
 			}
+#endif
 			break;
 		/* brightness increase */
 		case 0x9:
 			/* down event */
+#ifdef CONFIG_PPC
 			if ( data[1] == (data[1]&0xf) ) {
 				if (backlight_level < 0x1e)
 					pmu_set_brightness(backlight_level+2);
 				else 
 					pmu_set_brightness(0x1f);
 			}
+#endif
 			break;
 	}
 }
@@ -672,8 +682,14 @@
 
 void __init mackbd_init_hw(void)
 {
+#ifdef CONFIG_PPC
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-	    return;
+		return;
+#endif
+#ifdef CONFIG_MAC
+	if (!MACH_IS_MAC)
+		return;
+#endif
 
 	/* setup key map */
 	memcpy(key_maps[0], macplain_map, sizeof(plain_map));
@@ -684,7 +700,7 @@
 	memcpy(key_maps[8], macalt_map, sizeof(plain_map));
 	memcpy(key_maps[12], macctrl_alt_map, sizeof(plain_map));
 
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
 	/* initialize mouse interrupt hook */
 	adb_mouse_interrupt_hook = NULL;
 #endif
@@ -720,9 +736,9 @@
 	struct adb_request req;
 	int i;
 
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
 	adb_register(ADB_MOUSE, 0, &mouse_ids, mouse_input);
-#endif /* CONFIG_ADBMOUSE */
+#endif /* CONFIG_ADB_MOUSE */
 
 	adb_register(ADB_KEYBOARD, 0, &keyboard_ids, keyboard_input);
 	adb_register(0x07, 0x1F, &buttons_ids, buttons_input);
diff -u --recursive --new-file v2.3.19/linux/drivers/macintosh/macio-adb.c linux/drivers/macintosh/macio-adb.c
--- v2.3.19/linux/drivers/macintosh/macio-adb.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/macintosh/macio-adb.c	Thu Oct  7 10:17:09 1999
@@ -8,7 +8,7 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <asm/prom.h>
-#include <asm/adb.h>
+#include <linux/adb.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/hydra.h>
@@ -59,28 +59,38 @@
 static struct adb_request *current_req, *last_req;
 static unsigned char adb_rbuf[16];
 
+static int macio_probe(void);
+static int macio_init(void);
 static void macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs);
-static int macio_adb_send_request(struct adb_request *req, int sync);
+static int macio_send_request(struct adb_request *req, int sync);
 static int macio_adb_autopoll(int devs);
 static void macio_adb_poll(void);
 static int macio_adb_reset_bus(void);
 static void completed(void);
 
-static struct adb_controller	macio_controller = {
-	ADB_MACIO,
-	macio_adb_send_request,
+struct adb_driver macio_adb_driver = {
+	"MACIO",
+	macio_probe,
+	macio_init,
+	macio_send_request,
+	/*macio_write,*/
 	macio_adb_autopoll,
-	macio_adb_reset_bus,
-	macio_adb_poll
+	macio_adb_poll,
+	macio_adb_reset_bus
 };
 
-void macio_adb_init(void)
+int macio_probe(void)
+{
+	return find_compatible_devices("adb", "chrp,adb0")? 0: -ENODEV;
+}
+
+int macio_init(void)
 {
 	struct device_node *adbs;
 
 	adbs = find_compatible_devices("adb", "chrp,adb0");
 	if (adbs == 0)
-		return;
+		return -ENXIO;
 
 #if 0
 	{ int i;
@@ -101,7 +111,7 @@
 			0, "ADB", (void *)0)) {
 		printk(KERN_ERR "ADB: can't get irq %d\n",
 		       adbs->intrs[0].line);
-		return;
+		return -EAGAIN;
 	}
 
 	out_8(&adb->ctrl.r, 0);
@@ -112,12 +122,7 @@
 	out_8(&adb->autopoll.r, APE);
 	out_8(&adb->intr_enb.r, DFB | TAG);
 
-	adb_controller = &macio_controller;
-//	adb_hardware = ADB_MACIO;
-
-//	adb_send_request = macio_adb_send_request;
-//	adb_autopoll = macio_adb_autopoll;
-//	adb_reset_bus = macio_reset_bus;
+	return 0;
 }
 
 static int macio_adb_autopoll(int devs)
@@ -143,7 +148,7 @@
 }
 
 /* Send an ADB command */
-static int macio_adb_send_request(struct adb_request *req, int sync)
+static int macio_send_request(struct adb_request *req, int sync)
 {
 	unsigned long mflags;
 	int i;
diff -u --recursive --new-file v2.3.19/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.3.19/linux/drivers/macintosh/macserial.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/macintosh/macserial.c	Thu Oct  7 10:17:09 1999
@@ -36,14 +36,22 @@
 #include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/feature.h>
-#include <asm/adb.h>
-#include <asm/pmu.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
 
 #include "macserial.h"
 
+#ifdef CONFIG_PMAC_PBOOK
+static int serial_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier serial_sleep_notifier = {
+	serial_notify_sleep,
+	SLEEP_LEVEL_MISC,
+};
+#endif
+
 /*
  * It would be nice to dynamically allocate everything that
  * depends on NUM_SERIAL, so we could support any number of
@@ -1909,6 +1917,10 @@
 	}
 	*pp = 0;
 	zs_channels_found = n;
+#ifdef CONFIG_PMAC_PBOOK
+	if (n)
+		pmu_register_sleep_notifier(&serial_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
 }
 
 /* rs_init inits the driver */
@@ -2470,3 +2482,40 @@
 	set_debug_traps(); /* init stub */
 }
 #endif /* ifdef CONFIG_KGDB */
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * notify clients before sleep and reset bus afterwards
+ */
+int
+serial_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+	int i;
+	
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+	case PBOOK_SLEEP_REJECT:
+		break;
+		
+	case PBOOK_SLEEP_NOW:
+		for (i=0; i<zs_channels_found; i++) {
+			struct mac_serial *info = &zs_soft[i];
+			if (info->flags & ZILOG_INITIALIZED) {
+				shutdown(info);
+				info->flags |= ZILOG_SLEEPING;
+			}
+		}
+		break;
+	case PBOOK_WAKE:
+		for (i=0; i<zs_channels_found; i++) {
+			struct mac_serial *info = &zs_soft[i];
+			if (info->flags & ZILOG_SLEEPING) {
+				info->flags &= ~ZILOG_SLEEPING;
+				startup(info, 0);
+			}
+		}
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -u --recursive --new-file v2.3.19/linux/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h
--- v2.3.19/linux/drivers/macintosh/macserial.h	Sat May 15 15:05:36 1999
+++ linux/drivers/macintosh/macserial.h	Thu Oct  7 10:17:09 1999
@@ -68,6 +68,7 @@
 #define ZILOG_CLOSING		0x08000000 /* Serial port is closing */
 #define ZILOG_CTS_FLOW		0x04000000 /* Do CTS flow control */
 #define ZILOG_CHECK_CD		0x02000000 /* i.e., CLOCAL */
+#define ZILOG_SLEEPING		0x01000000 /* have shut it down for sleep */
 
 /* Software state per channel */
 
diff -u --recursive --new-file v2.3.19/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c
--- v2.3.19/linux/drivers/macintosh/mediabay.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/macintosh/mediabay.c	Thu Oct  7 10:17:09 1999
@@ -26,7 +26,16 @@
 #include <asm/feature.h>
 #include <asm/mediabay.h>
 #include <asm/init.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
 
+#ifdef CONFIG_PMAC_PBOOK
+static int mb_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier mb_sleep_notifier = {
+	mb_notify_sleep,
+	SLEEP_LEVEL_MEDIABAY,
+};
+#endif
 
 #undef MB_USE_INTERRUPTS
 
@@ -77,13 +86,13 @@
  * Hold the media-bay reset signal true for this many ticks
  * after a device is inserted before releasing it.
  */
-#define MB_RESET_COUNT	20
+#define MB_RESET_COUNT	40
 
 /*
  * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted
  * (or until the device is ready) before registering the IDE interface.
  */
-#define MB_IDE_WAIT	1000
+#define MB_IDE_WAIT	1500
 
 static void poll_media_bay(int which);
 static void set_media_bay(int which, int id);
@@ -157,6 +166,10 @@
 	{
 		printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count);
 
+#ifdef CONFIG_PMAC_PBOOK
+		pmu_register_sleep_notifier(&mb_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
 		kernel_thread(media_bay_task, NULL, 0);
 	}
 }
@@ -298,9 +311,16 @@
 	int id = MB_CONTENTS(which);
 
 	if (id == media_bays[which].last_value) {
-		if (id != media_bays[which].content_id
-		    && ++media_bays[which].value_count >= MB_STABLE_COUNT)
- 			set_media_bay(which, id);
+	    if (id != media_bays[which].content_id
+	        && ++media_bays[which].value_count >= MB_STABLE_COUNT) {
+	        /* If the device type changes without going thru "MB_NO", we force
+	           a pass by "MB_NO" to make sure things are properly reset */
+	        if ((id != MB_NO) && (media_bays[which].content_id != MB_NO)) {
+		    set_media_bay(which, MB_NO);
+		    udelay(500);
+		}
+ 		set_media_bay(which, id);
+ 	    }
 	} else {
 		media_bays[which].last_value = id;
 		media_bays[which].value_count = 0;
@@ -319,27 +339,28 @@
 	
 	switch (id) {
 	case MB_CD:
-		feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
 		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-		feature_set(bay->dev_node, FEATURE_CD_power);
 		feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable);
+		udelay(500);
+		feature_set(bay->dev_node, FEATURE_CD_power);
 		printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
 		break;
 	case MB_FD:
-		feature_clear(bay->dev_node, FEATURE_CD_power);
 		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
 		feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable);
 		feature_set(bay->dev_node, FEATURE_SWIM3_enable);
 		printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which);
 		break;
 	case MB_NO:
-		feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
 		feature_clear(bay->dev_node, FEATURE_CD_power);
+		feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
+		feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+		feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
+		feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
+		feature_set(bay->dev_node, FEATURE_Mediabay_reset);
 		printk(KERN_INFO "media bay %d is empty\n", which);
 		break;
 	default:
-		feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
-		feature_clear(bay->dev_node, FEATURE_CD_power);
 		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
 		printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
 		       which, id);
@@ -348,3 +369,62 @@
 	
 	udelay(500);
 }
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * notify clients before sleep and reset bus afterwards
+ */
+int __pmac
+mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+	volatile struct media_bay_info* bay;
+	int i;
+	
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+	case PBOOK_SLEEP_REJECT:
+		break;
+		
+	case PBOOK_SLEEP_NOW:
+		for (i=0; i<media_bay_count; i++) {
+			bay = &media_bays[i];
+			feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
+			feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
+			feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
+			feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+			feature_set(bay->dev_node, FEATURE_Mediabay_reset);
+			feature_clear(bay->dev_node, FEATURE_CD_power);
+			out_8(&media_bays[i].addr->contents, 0x70);
+		}
+		break;
+	case PBOOK_WAKE:
+		for (i=0; i<media_bay_count; i++) {
+			bay = &media_bays[i];
+			feature_set(bay->dev_node, FEATURE_Mediabay_enable);
+			/* I suppose this is enough delay to stabilize MB_CONTENT ... */
+			mdelay(10);
+			/* We re-enable the bay using it's previous content only if
+			   it did not change */
+			if (MB_CONTENTS(i) == bay->content_id) {
+				set_media_bay(i, bay->content_id);
+				if (bay->content_id != MB_NO) {
+					mdelay(400);
+					/* Clear the bay reset */
+					feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+					/* This small delay makes sure the device has time
+					   to assert the BUSY bit (used by IDE sleep) */
+					udelay(100);
+					/* We reset the state machine timers in case we were in the
+					   middle of a wait loop */
+					if (bay->reset_timer)
+						bay->reset_timer = MB_RESET_COUNT;
+					if (bay->cd_timer)
+						bay->cd_timer = MB_IDE_WAIT;
+				}
+			}
+		}
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -u --recursive --new-file v2.3.19/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c
--- v2.3.19/linux/drivers/macintosh/via-cuda.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/macintosh/via-cuda.c	Thu Oct  7 10:17:09 1999
@@ -14,16 +14,31 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#ifdef CONFIG_PPC
 #include <asm/prom.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
+#include <asm/machdep.h>
+#else
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+#endif
 #include <asm/io.h>
-#include <asm/pgtable.h>
 #include <asm/system.h>
 #include <linux/init.h>
 
 static volatile unsigned char *via;
 
+#ifdef CONFIG_MAC
+#define CUDA_IRQ IRQ_MAC_ADB
+#define __openfirmware
+#define eieio()
+#else
+#define CUDA_IRQ vias->intrs[0].line
+#endif
+
 /* VIA registers - spaced 0x200 bytes apart */
 #define RS		0x200		/* skip between registers */
 #define B		0		/* B-side data */
@@ -73,27 +88,38 @@
 static unsigned char *reply_ptr;
 static int reading_reply;
 static int data_index;
+#ifdef CONFIG_PPC
 static struct device_node *vias;
+#endif
 static int cuda_fully_inited = 0;
 
-static int init_via(void);
+static int cuda_probe(void);
+static int cuda_init(void);
+static int cuda_init_via(void);
 static void cuda_start(void);
-static void via_interrupt(int irq, void *arg, struct pt_regs *regs);
+static void cuda_interrupt(int irq, void *arg, struct pt_regs *regs);
 static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
-static int cuda_adb_send_request(struct adb_request *req, int sync);
+static int cuda_send_request(struct adb_request *req, int sync);
 static int cuda_adb_autopoll(int devs);
-static int cuda_adb_reset_bus(void);
-static int cuda_send_request(struct adb_request *req);
-
-
-static struct adb_controller	cuda_controller = {
-	ADB_VIACUDA,
-	cuda_adb_send_request,
+void cuda_poll(void);
+static int cuda_reset_adb_bus(void);
+static int cuda_write(struct adb_request *req);
+
+int cuda_request(struct adb_request *req,
+		 void (*done)(struct adb_request *), int nbytes, ...);
+
+struct adb_driver via_cuda_driver = {
+	"CUDA",
+	cuda_probe,
+	cuda_init,
+	cuda_send_request,
+	/*cuda_write,*/
 	cuda_adb_autopoll,
-	cuda_adb_reset_bus,
-	cuda_poll
+	cuda_poll,
+	cuda_reset_adb_bus
 };
 
+#ifdef CONFIG_PPC
 void
 find_via_cuda()
 {
@@ -106,7 +132,7 @@
 #if 0
     { int i;
 
-    printk("via_cuda_init: node = %p, addrs =", vias->node);
+    printk("find_via_cuda: node = %p, addrs =", vias->node);
     for (i = 0; i < vias->n_addrs; ++i)
 	printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
     printk(", intrs =");
@@ -124,31 +150,56 @@
     via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
 
     cuda_state = idle;
+    sys_ctrler = SYS_CTRLER_CUDA;
+}
+#endif /* CONFIG_PPC */
 
-    if (!init_via()) {
-	printk(KERN_ERR "init_via failed\n");
-	via = NULL;
-    }
-
-   adb_controller = &cuda_controller;
+static int
+cuda_probe()
+{
+#ifdef CONFIG_PPC
+    if (sys_ctrler != SYS_CTRLER_CUDA)
+	return -ENODEV;
+#else
+    if (macintosh_config->adb_type != MAC_ADB_CUDA)
+	return -ENODEV;
+    via = via1;
+#endif
+    return 0;
 }
 
-void
-via_cuda_init(void)
+static int
+cuda_init(void)
 {
+    int err;
+
     if (via == NULL)
-	return;
+	return -ENODEV;
 
-    if (request_irq(vias->intrs[0].line, via_interrupt, 0, "VIA", (void *)0)) {
-	printk(KERN_ERR "VIA: can't get irq %d\n", vias->intrs[0].line);
-	return;
+    err = cuda_init_via();
+    if (err) {
+	printk(KERN_ERR "cuda_probe: init_via() failed\n");
+	via = NULL;
+	return err;
     }
 
-    /* Clear and enable interrupts */
+    /* Clear and enable interrupts, but only on PPC. On 68K it's done  */
+    /* for us by the the main VIA driver in arch/m68k/mac/via.c        */
+
+#ifndef CONFIG_MAC
     via[IFR] = 0x7f; eieio();	/* clear interrupts by writing 1s */
     via[IER] = IER_SET|SR_INT; eieio();	/* enable interrupt from SR */
+#endif
+
+    if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
+	printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ);
+	return -EAGAIN;
+    }
+
+    printk("adb: CUDA driver v0.5 for Unified ADB.\n");
 
     cuda_fully_inited = 1;
+    return 0;
 }
 
 #define WAIT_FOR(cond, what)				\
@@ -156,14 +207,14 @@
 	for (x = 1000; !(cond); --x) {			\
 	    if (x == 0) {				\
 		printk("Timeout waiting for " what);	\
-		return 0;				\
+		return -ENXIO;				\
 	    }						\
 	    udelay(100);					\
 	}						\
     } while (0)
 
 static int
-init_via()
+cuda_init_via()
 {
     int x;
 
@@ -172,7 +223,9 @@
     via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;		/* SR data in */
     eieio();
     x = via[SR]; eieio();	/* clear any left-over data */
+#ifndef CONFIG_MAC
     via[IER] = 0x7f; eieio();	/* disable interrupts from VIA */
+#endif
     eieio();
 
     /* delay 4ms and then clear any pending interrupt */
@@ -198,12 +251,12 @@
     x = via[SR]; eieio();
     via[B] |= TIP; eieio();	/* should be unnecessary */
 
-    return 1;
+    return 0;
 }
 
 /* Send an ADB command */
 static int
-cuda_adb_send_request(struct adb_request *req, int sync)
+cuda_send_request(struct adb_request *req, int sync)
 {
     int i;
 
@@ -214,7 +267,7 @@
   
     req->reply_expected = 1;
 
-    i = cuda_send_request(req);
+    i = cuda_write(req);
     if (i)
 	return i;
 
@@ -243,7 +296,7 @@
 
 /* Reset adb bus - how do we do this?? */
 static int
-cuda_adb_reset_bus(void)
+cuda_reset_adb_bus(void)
 {
     struct adb_request req;
 
@@ -276,11 +329,11 @@
 	req->data[i] = va_arg(list, int);
     va_end(list);
     req->reply_expected = 1;
-    return cuda_send_request(req);
+    return cuda_write(req);
 }
 
 static int
-cuda_send_request(struct adb_request *req)
+cuda_write(struct adb_request *req)
 {
     unsigned long flags;
 
@@ -336,17 +389,17 @@
 void
 cuda_poll()
 {
-    int ie;
+    unsigned long flags;
 
-    __save_flags(ie);
-    __cli();
+    save_flags(flags);
+    cli();
     if (via[IFR] & SR_INT)
-	via_interrupt(0, 0, 0);
-    __restore_flags(ie);
+	cuda_interrupt(0, 0, 0);
+    restore_flags(flags);
 }
 
 static void
-via_interrupt(int irq, void *arg, struct pt_regs *regs)
+cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
     int x, status;
     struct adb_request *req;
@@ -355,7 +408,7 @@
 	return;
 
     status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio();
-    /* printk("via_interrupt: state=%d status=%x\n", cuda_state, status); */
+    /* printk("cuda_interrupt: state=%d status=%x\n", cuda_state, status); */
     switch (cuda_state) {
     case idle:
 	/* CUDA has sent us the first byte of data - unsolicited */
@@ -469,7 +522,7 @@
 	break;
 
     default:
-	printk("via_interrupt: unknown cuda_state %d?\n", cuda_state);
+	printk("cuda_interrupt: unknown cuda_state %d?\n", cuda_state);
     }
 }
 
@@ -489,10 +542,4 @@
 	    printk(" %.2x", buf[i]);
 	printk("\n");
     }
-}
-
-int
-cuda_present(void)
-{
-	return (adb_controller && (adb_controller->kind == ADB_VIACUDA) && via);
 }
diff -u --recursive --new-file v2.3.19/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
--- v2.3.19/linux/drivers/macintosh/via-pmu.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/macintosh/via-pmu.c	Thu Oct  7 10:17:09 1999
@@ -21,10 +21,12 @@
 #include <linux/blkdev.h>
 #include <linux/pci.h>
 #include <linux/malloc.h>
+#include <linux/poll.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/cuda.h>
 #include <asm/prom.h>
-#include <asm/adb.h>
-#include <asm/pmu.h>
-#include <asm/cuda.h>
+#include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -32,6 +34,7 @@
 #include <asm/irq.h>
 #include <asm/feature.h>
 #include <asm/uaccess.h>
+#include <asm/mmu_context.h>
 
 /* Misc minor number allocated for /dev/pmu */
 #define PMU_MINOR	154
@@ -70,6 +73,7 @@
 #define IER_SET		0x80		/* set bits in IER */
 #define IER_CLR		0		/* clear bits in IER */
 #define SR_INT		0x04		/* Shift register full/empty */
+#define CB2_INT		0x08
 #define CB1_INT		0x10		/* transition on CB1 input */
 
 static enum pmu_state {
@@ -98,11 +102,13 @@
 int asleep;
 struct notifier_block *sleep_notifier_list;
 
+static int pmu_probe(void);
+static int pmu_init(void);
 static int init_pmu(void);
 static int pmu_queue_request(struct adb_request *req);
 static void pmu_start(void);
 static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
-static int pmu_adb_send_request(struct adb_request *req, int sync);
+static int pmu_send_request(struct adb_request *req, int sync);
 static int pmu_adb_autopoll(int devs);
 static int pmu_adb_reset_bus(void);
 static void send_byte(int x);
@@ -112,15 +118,31 @@
 static void pmu_handle_data(unsigned char *data, int len,
 			    struct pt_regs *regs);
 static void set_volume(int level);
+#ifdef CONFIG_PMAC_PBOOK
+static void pmu_pass_intr(unsigned char *data, int len);
+#endif
 
-static struct adb_controller	pmu_controller = {
-	ADB_VIAPMU,
-	pmu_adb_send_request,
+struct adb_driver via_pmu_driver = {
+	"PMU",
+	pmu_probe,
+	pmu_init,
+	pmu_send_request,
+	/*pmu_queue_request,*/
 	pmu_adb_autopoll,
-	pmu_adb_reset_bus,
-	pmu_poll
+	pmu_poll,
+	pmu_adb_reset_bus
 };
 
+extern void low_sleep_handler(void);
+extern void sleep_save_intrs(int);
+extern void sleep_restore_intrs(void);
+
+extern int grackle_pcibios_read_config_word(unsigned char bus,
+	unsigned char dev_fn, unsigned char offset, unsigned short *val);
+
+extern int grackle_pcibios_write_config_word(unsigned char bus,
+	unsigned char dev_fn, unsigned char offset, unsigned short val);
+
 /*
  * This table indicates for each PMU opcode:
  * - the number of data bytes to be sent with the command, or -1
@@ -164,13 +186,21 @@
 /*f8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
 };
 
+static char *pbook_type[] = {
+	"Unknown PowerBook",
+	"PowerBook 2400/3400/3500(G3)",
+	"PowerBook G3 Series",
+	"1999 PowerBook G3",
+};
 
-void __openfirmware
+int __openfirmware
 find_via_pmu()
 {
+	if (via != 0)
+		return 1;
 	vias = find_devices("via-pmu");
 	if (vias == 0)
-		return;
+		return 0;
 	if (vias->next != 0)
 		printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
 	
@@ -179,7 +209,7 @@
 #if 0
 	{ int i;
 
-	printk("via_pmu_init: node = %p, addrs =", vias->node);
+	printk("find_via_pmu: node = %p, addrs =", vias->node);
 	for (i = 0; i < vias->n_addrs; ++i)
 		printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
 	printk(", intrs =");
@@ -192,12 +222,14 @@
 		printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
 		       vias->n_addrs, vias->n_intrs);
 		if (vias->n_addrs < 1 || vias->n_intrs < 1)
-			return;
+			return 0;
 	}
 
 	if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
 	    || device_is_compatible(vias->parent, "ohare")))
 		pmu_kind = PMU_OHARE_BASED;
+	else if (device_is_compatible(vias->parent, "paddington"))
+		pmu_kind = PMU_PADDINGTON_BASED;
 	else if (device_is_compatible(vias->parent, "heathrow"))
 		pmu_kind = PMU_HEATHROW_BASED;
 	else
@@ -209,23 +241,28 @@
 
 	pmu_state = idle;
 
-	if (!init_pmu())
+	if (!init_pmu()) {
 		via = NULL;
+		return 0;
+	}
 
-	adb_controller = &pmu_controller;
+	printk(KERN_INFO "PMU driver initialized for %s\n",
+	       pbook_type[pmu_kind]);
+	sys_ctrler = SYS_CTRLER_PMU;
+	return 1;
+}
 
-	if (via)
-		printk(KERN_INFO "PMU driver initialized for %s\n",
-		    (pmu_kind == PMU_OHARE_BASED) ? "PowerBook 2400/3400/3500(G3)" :
-		    ((pmu_kind == PMU_HEATHROW_BASED) ? "PowerBook G3 Series" :
-		    "Unknown PowerBook"));
+static int __openfirmware
+pmu_probe()
+{
+	return vias == NULL? -ENODEV: 0;
 }
 
-void __openfirmware
-via_pmu_init(void)
+static int __openfirmware
+pmu_init(void)
 {
 	if (vias == NULL)
-		return;
+		return -ENXIO;
 
 	bright_req_1.complete = 1;
 	bright_req_2.complete = 1;
@@ -235,7 +272,7 @@
 			(void *)0)) {
 		printk(KERN_ERR "VIA-PMU: can't get irq %d\n",
 		       vias->intrs[0].line);
-		return;
+		return -ENXIO;
 	}
 
 	/* Enable interrupts */
@@ -245,6 +282,8 @@
 	
 	/* Enable backlight */
 	pmu_enable_backlight(1);
+
+	return 0;
 }
 
 static int __openfirmware
@@ -292,20 +331,19 @@
 
 /* Send an ADB command */
 static int __openfirmware
-pmu_adb_send_request(struct adb_request *req, int sync)
+pmu_send_request(struct adb_request *req, int sync)
 {
-    int i, ret;
+	int i, ret;
 
-    if ((vias == NULL) || (!pmu_fully_inited))
-    {
- 	req->complete = 1;
-   	return -ENXIO;
-   }
+	if ((vias == NULL) || (!pmu_fully_inited)) {
+		req->complete = 1;
+		return -ENXIO;
+	}
 
-    ret = -EINVAL;
-	
-    switch (req->data[0]) {
-    case PMU_PACKET:
+	ret = -EINVAL;
+
+	switch (req->data[0]) {
+	case PMU_PACKET:
 		for (i = 0; i < req->nbytes - 1; ++i)
 			req->data[i] = req->data[i+1];
 		--req->nbytes;
@@ -316,7 +354,7 @@
 			req->reply_len = 0;
 		ret = pmu_queue_request(req);
 		break;
-    case CUDA_PACKET:
+	case CUDA_PACKET:
 		switch (req->data[1]) {
 		case CUDA_GET_TIME:
 			if (req->nbytes != 2)
@@ -344,7 +382,7 @@
 			break;
 		}
 		break;
-    case ADB_PACKET:
+	case ADB_PACKET:
 		for (i = req->nbytes - 1; i > 1; --i)
 			req->data[i+2] = req->data[i];
 		req->data[3] = req->nbytes - 2;
@@ -356,19 +394,17 @@
 		req->reply_len = 0;
 		ret = pmu_queue_request(req);
 		break;
-    }
-    if (ret)
-    {
-    	req->complete = 1;
-    	return ret;
-    }
-    	
-    if (sync) {
-	while (!req->complete)
-		pmu_poll();
-    }
+	}
+	if (ret) {
+		req->complete = 1;
+		return ret;
+	}
+
+	if (sync)
+		while (!req->complete)
+			pmu_poll();
 
-    return 0;
+	return 0;
 }
 
 /* Enable/disable autopolling */
@@ -513,19 +549,25 @@
 static void __openfirmware
 send_byte(int x)
 {
-	out_8(&via[ACR], 0x1c);
-	out_8(&via[SR], x);
-	out_8(&via[B], via[B] & ~0x10);		/* assert TREQ */
+	volatile unsigned char *v = via;
+
+	out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT);
+	out_8(&v[SR], x);
+	out_8(&v[B], in_8(&v[B]) & ~TREQ);		/* assert TREQ */
 }
 
 static void __openfirmware
 recv_byte()
 {
-	out_8(&via[ACR], 0x0c);
-	in_8(&via[SR]);		/* resets SR */
-	out_8(&via[B], via[B] & ~0x10);
+	volatile unsigned char *v = via;
+
+	out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT);
+	in_8(&v[SR]);		/* resets SR */
+	out_8(&v[B], in_8(&v[B]) & ~0x10);
 }
 
+static int disable_poll;
+
 static void __openfirmware
 pmu_start()
 {
@@ -545,7 +587,9 @@
 	data_len = pmu_data_len[req->data[0]][0];
 
 	/* set the shift register to shift out and send a byte */
+	++disable_poll;
 	send_byte(req->data[0]);
+	--disable_poll;
 
 out:
 	restore_flags(flags);
@@ -554,13 +598,15 @@
 void __openfirmware
 pmu_poll()
 {
-	int ie;
+	unsigned long flags;
 
-	__save_flags(ie);
-	__cli();
+	if (disable_poll)
+		return;
+	save_flags(flags);
+	cli();
 	if (via[IFR] & (SR_INT | CB1_INT))
 		via_pmu_interrupt(0, 0, 0);
-	__restore_flags(ie);
+	restore_flags(flags);
 }
 
 static void __openfirmware
@@ -569,6 +615,7 @@
 	int intr;
 	int nloop = 0;
 
+	++disable_poll;
 	while ((intr = in_8(&via[IFR])) != 0) {
 		if (++nloop > 1000) {
 			printk(KERN_DEBUG "PMU: stuck in intr loop, "
@@ -580,11 +627,9 @@
 		else if (intr & CB1_INT) {
 			adb_int_pending = 1;
 			out_8(&via[IFR], CB1_INT);
-		} else
-		{
-			/* -- Disabled printk, will happen _really_ often on
-				  PowerBooks ((CB2 interrupts) --
-			printk(KERN_DEBUG "PMU: spurrious interrupt intr=%x\n", intr); */
+		}
+		intr &= ~(SR_INT | CB1_INT);
+		if (intr != 0) {
 			out_8(&via[IFR], intr);
 		}
 	}
@@ -597,6 +642,7 @@
 			pmu_start();
 		}
 	}
+	--disable_poll;
 }
 
 static void __openfirmware
@@ -605,17 +651,17 @@
 	struct adb_request *req;
 	int bite, timeout;
 
+	if (via[B] & TREQ) {
+		printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]);
+		out_8(&via[IFR], SR_INT);
+		return;
+	}
 	if (via[B] & TACK)
-		printk(KERN_DEBUG "PMU: sr_intr but ack still high! (%x)\n",
+		printk(KERN_ERR "PMU: sr_intr but ack still high! (%x)\n",
 		       via[B]);
 
-	/* if reading grab the byte, and reset the interrupt */
-	if ((via[ACR] & SR_OUT) == 0)
-		bite = in_8(&via[SR]);
-	out_8(&via[IFR], SR_INT);
-
 	/* reset TREQ and wait for TACK to go high */
-	out_8(&via[B], via[B] | TREQ);
+	out_8(&via[B], in_8(&via[B]) | TREQ);
 	timeout = 3200;
 	while ((in_8(&via[B]) & TACK) == 0) {
 		if (--timeout < 0) {
@@ -625,6 +671,11 @@
 		udelay(10);
 	}
 
+	/* if reading grab the byte, and reset the interrupt */
+	if (pmu_state == reading || pmu_state == reading_intr)
+		bite = in_8(&via[SR]);
+	out_8(&via[IFR], SR_INT);
+
 	switch (pmu_state) {
 	case sending:
 		req = current_req;
@@ -707,8 +758,6 @@
 static void __openfirmware
 pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
 {
-	static int show_pmu_ints = 1;
-
 	asleep = 0;
 	if (len < 1) {
 		adb_int_pending = 0;
@@ -730,21 +779,34 @@
 			}
 			pmu_done(req);
 		} else {
-			adb_input(data+1, len-1, regs, 1);
+#ifdef CONFIG_XMON
+			if (len == 4 && data[1] == 0x2c) {
+				extern int xmon_wants_key, xmon_pmu_keycode;
+				if (xmon_wants_key) {
+					xmon_pmu_keycode = data[2];
+					return;
+				}
+			}
+#endif /* CONFIG_XMON */
+			/*
+			 * XXX On the [23]400 the PMU gives us an up
+			 * event for keycodes 0x74 or 0x75 when the PC
+			 * card eject buttons are released, so we
+			 * ignore those events.
+			 */
+			if (!(pmu_kind == PMU_OHARE_BASED && len == 4
+			      && data[1] == 0x2c && data[3] == 0xff
+			      && (data[2] & ~1) == 0xf4))
+				adb_input(data+1, len-1, regs, 1);
 		}
+	} else if (data[0] == 0x08 && len == 3) {
+		/* sound/brightness buttons pressed */
+		pmu_set_brightness(data[1] >> 3);
+		set_volume(data[2]);
 	} else {
-		if (data[0] == 0x08 && len == 3) {
-			/* sound/brightness buttons pressed */
-			pmu_set_brightness(data[1] >> 3);
-			set_volume(data[2]);
-		} else if (show_pmu_ints
-			   && !(data[0] == PMU_INT_TICK && len == 1)) {
-			int i;
-			printk(KERN_DEBUG "pmu intr");
-			for (i = 0; i < len; ++i)
-				printk(" %.2x", data[i]);
-			printk("\n");
-		}
+#ifdef CONFIG_PMAC_PBOOK
+		pmu_pass_intr(data, len);
+#endif
 	}
 }
 
@@ -759,38 +821,46 @@
 	struct adb_request req;
 
 	if (vias == NULL)
-		return ;
+		return;
 		
-	if (on) {
-	    /* first call: get current backlight value */
-	    if (backlight_level < 0) {
-		switch(pmu_kind) {
-		    case PMU_OHARE_BASED:
+	/* first call: get current backlight value */
+	if (on && backlight_level < 0) {
+		switch (pmu_kind) {
+		case PMU_OHARE_BASED:
 			pmu_request(&req, NULL, 2, 0xd9, 0);
 			while (!req.complete)
 				pmu_poll();
 			backlight_level = req.reply[1] >> 3;
-			printk(KERN_DEBUG "pmu: controls returned bright: %d\n", (int)req.reply[1]);
 			break;
-		    case PMU_HEATHROW_BASED:
+		case PMU_HEATHROW_BASED:
+			/* We cannot use nvram_read_byte here (not yet initialized) */
 			pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);
 			while (!req.complete)
 				pmu_poll();
-			printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]);
 			backlight_level = req.reply[1];
+			printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level);
 			break;
-		    default:
+		case PMU_PADDINGTON_BASED:
+			/* the G3 PB 1999 has a backlight node
+			   and chrp-structured nvram */
+			/* XXX should read macos's "blkt" property in nvram
+			   for this node.  For now this ensures that the
+			   backlight doesn't go off as soon as linux boots. */
+			backlight_level = 20;
+			break;
+		default:
 		        backlight_enabled = 0;
 		        return;
 		}
-	    }
-	    pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
-	    	LEVEL_TO_BRIGHT(backlight_level));
-	    while (!req.complete)
-		pmu_poll();
+	}
+	if (on) {
+		pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+			    LEVEL_TO_BRIGHT(backlight_level));
+		while (!req.complete)
+			pmu_poll();
 	}
 	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
-	    PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
+		    PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
 	while (!req.complete)
 		pmu_poll();
 	backlight_enabled = on;
@@ -847,7 +917,7 @@
 {
 	struct adb_request req;
 
-	__cli();
+	cli();
 	
 	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
 					PMU_INT_TICK );
@@ -866,7 +936,7 @@
 {
 	struct adb_request req;
 
-	__cli();
+	cli();
 	
 	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
 					PMU_INT_TICK );
@@ -881,13 +951,69 @@
 		;
 }
 
+#ifdef CONFIG_PMAC_PBOOK
+
+static LIST_HEAD(sleep_notifiers);
+
 int
-pmu_present(void)
+pmu_register_sleep_notifier(struct pmu_sleep_notifier *n)
 {
-	return (adb_controller && (adb_controller->kind == ADB_VIAPMU) && vias);
+	struct list_head *list;
+	struct pmu_sleep_notifier *current;
+
+	for (list = sleep_notifiers.next; list != &sleep_notifiers;
+	     list = list->next) {
+		current = list_entry(list, struct pmu_sleep_notifier, list);
+		if (n->priority > current->priority)
+			break;
+	}
+	__list_add(&n->list, list->prev, list);
+	return 0;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+int
+pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
+{
+	if (n->list.next == 0)
+		return -ENOENT;
+	list_del(&n->list);
+	n->list.next = 0;
+	return 0;
+}
+
+/* Sleep is broadcast last-to-first */
+static int
+broadcast_sleep(int when, int can_cancel)
+{
+	int ret = PBOOK_SLEEP_OK;
+	struct list_head *list;
+	struct pmu_sleep_notifier *current;
+
+	for (list = sleep_notifiers.prev; list != &sleep_notifiers;
+	     list = list->prev) {
+		current = list_entry(list, struct pmu_sleep_notifier, list);
+		ret = current->notifier_call(current, when);
+		if (can_cancel && (ret != PBOOK_SLEEP_OK))
+			return ret;
+	}
+	return ret;
+}
+
+/* Wake is broadcast first-to-last */
+static int
+broadcast_wake(void)
+{
+	int ret = PBOOK_SLEEP_OK;
+	struct list_head *list;
+	struct pmu_sleep_notifier *current;
+
+	for (list = sleep_notifiers.next; list != &sleep_notifiers;
+	     list = list->next) {
+		current = list_entry(list, struct pmu_sleep_notifier, list);
+		current->notifier_call(current, PBOOK_WAKE);
+	}
+	return ret;
+}
 
 /*
  * This struct is used to store config register values for
@@ -897,10 +1023,11 @@
 	u16	command;
 	u16	cache_lat;
 	u16	intr;
+	u32	rom_address;
 } *pbook_pci_saves;
 static int n_pbook_pci_saves;
 
-static inline void __openfirmware
+static void __openfirmware
 pbook_pci_save(void)
 {
 	int npci;
@@ -922,12 +1049,13 @@
 		pci_read_config_word(pd, PCI_COMMAND, &ps->command);
 		pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
 		pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
+		pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address);
 		++ps;
 		--npci;
 	}
 }
 
-static inline void __openfirmware
+static void __openfirmware
 pbook_pci_restore(void)
 {
 	u16 cmd;
@@ -948,7 +1076,7 @@
 					PCI_BASE_ADDRESS_0 + j*4,
 					pd->resource[j].start);
 			pci_write_config_dword(pd, PCI_ROM_ADDRESS,
-			       pd->resource[PCI_ROM_RESOURCE].start);
+				ps->rom_address);
 			pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
 				ps->cache_lat);
 			pci_write_config_word(pd, PCI_INTERRUPT_LINE,
@@ -963,43 +1091,147 @@
 /*
  * Put the powerbook to sleep.
  */
-#define IRQ_ENABLE	((unsigned int *)0xf3000024)
-#define MEM_CTRL	((unsigned int *)0xf8000070)
+ 
+#define FEATURE_CTRL(base)	((unsigned int *)(base + 0x38))
+#define	GRACKLE_PM	(1<<7)
+#define GRACKLE_DOZE	(1<<5)
+#define	GRACKLE_NAP	(1<<4)
+#define	GRACKLE_SLEEP	(1<<3)
+
+int __openfirmware powerbook_sleep_G3(void)
+{
+	int ret;
+	unsigned long save_l2cr;
+	unsigned long save_fcr;
+	unsigned long wait;
+	unsigned short pmcr1;
+	struct adb_request sleep_req;
+	struct device_node *macio;
+	unsigned long macio_base = 0;
 
-int __openfirmware powerbook_sleep(void)
+	macio = find_devices("mac-io");
+	if (macio != 0 && macio->n_addrs > 0)
+		macio_base = (unsigned long)
+			ioremap(macio->addrs[0].address, 0x40);
+
+	/* Sync the disks. */
+	/* XXX It would be nice to have some way to ensure that
+	 * nobody is dirtying any new buffers while we wait. */
+	fsync_dev(0);
+
+	/* Notify device drivers */
+	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
+	if (ret != PBOOK_SLEEP_OK) {
+		broadcast_sleep(PBOOK_SLEEP_REJECT, 0);
+		printk("pmu: sleep rejected\n");
+		return -EBUSY;
+	}
+	broadcast_sleep(PBOOK_SLEEP_NOW, 0);
+
+	/* Give the disks a little time to actually finish writing */
+	for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
+		mb();
+
+	/* Disable all interrupts except pmu */
+	sleep_save_intrs(vias->intrs[0].line);
+
+	/* Make sure the decrementer won't interrupt us */
+	asm volatile("mtdec %0" : : "r" (0x7fffffff));
+#if 0
+	/* Save the state of PCI config space for some slots */
+	pbook_pci_save();
+#endif
+	/* For 750, save backside cache setting and disable it */
+	save_l2cr = _get_L2CR();	/* (returns 0 if not 750) */
+	if (save_l2cr)
+		_set_L2CR(0);
+
+	if (macio_base != 0) {
+		save_fcr = in_le32(FEATURE_CTRL(macio_base));
+		/* Check if this is still valid on older powerbooks */
+		out_le32(FEATURE_CTRL(macio_base), save_fcr & ~(0x00000140UL));
+	}
+
+	if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)
+		giveup_fpu(current);
+
+	grackle_pcibios_read_config_word(0,0,0x70,&pmcr1);
+	/* Apparently, MacOS uses NAP mode for Grackle ??? */
+	pmcr1 &= ~(GRACKLE_DOZE|GRACKLE_SLEEP); 
+	pmcr1 |= GRACKLE_PM|GRACKLE_NAP;
+	grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
+
+	/* Ask the PMU to put us to sleep */
+	pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+	while (!sleep_req.complete)
+		mb();
+
+	cli();
+	while (pmu_state != idle)
+		pmu_poll();
+
+	/* Call low-level ASM sleep handler */
+	low_sleep_handler();
+
+	/* We're awake again, stop grackle PM */
+	grackle_pcibios_read_config_word(0, 0, 0x70, &pmcr1);
+	pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); 
+	grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
+
+	sti();
+#if 0
+	/* According to someone from Apple, this should not be needed,
+	   at least not for all devices. Let's keep it for now until we
+	   have something that works. */
+	pbook_pci_restore();
+#endif
+	set_context(current->mm->context);
+
+	/* Restore L2 cache */
+	if (save_l2cr)
+		_set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
+	
+	/* reenable interrupts */
+	sleep_restore_intrs();
+
+	/* Notify drivers */
+	broadcast_wake();
+
+	return 0;
+}
+
+#define PB3400_MEM_CTRL		((unsigned int *)0xf8000070)
+
+int __openfirmware powerbook_sleep_3400(void)
 {
 	int ret, i, x;
-	static int save_backlight;
-	static unsigned int save_irqen;
 	unsigned long msr;
 	unsigned int hid0;
 	unsigned long p, wait;
 	struct adb_request sleep_req;
 
-	/* Notify device drivers */
-	ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL);
-	if (ret & NOTIFY_STOP_MASK)
-		return -EBUSY;
-
 	/* Sync the disks. */
 	/* XXX It would be nice to have some way to ensure that
 	 * nobody is dirtying any new buffers while we wait. */
 	fsync_dev(0);
 
-	/* Turn off the display backlight */
-	save_backlight = backlight_enabled;
-	if (save_backlight)
-		pmu_enable_backlight(0);
+	/* Notify device drivers */
+	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
+	if (ret != PBOOK_SLEEP_OK) {
+		broadcast_sleep(PBOOK_SLEEP_REJECT, 0);
+		printk("pmu: sleep rejected\n");
+		return -EBUSY;
+	}
+	broadcast_sleep(PBOOK_SLEEP_NOW, 0);
 
 	/* Give the disks a little time to actually finish writing */
 	for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
 		mb();
 
 	/* Disable all interrupts except pmu */
-	save_irqen = in_le32(IRQ_ENABLE);
-	for (i = 0; i < 32; ++i)
-		if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
-			disable_irq(i);
+	sleep_save_intrs(vias->intrs[0].line);
+
+	/* Make sure the decrementer won't interrupt us */
 	asm volatile("mtdec %0" : : "r" (0x7fffffff));
 
 	/* Save the state of PCI config space for some slots */
@@ -1008,9 +1240,9 @@
 	/* Set the memory controller to keep the memory refreshed
 	   while we're asleep */
 	for (i = 0x403f; i >= 0x4000; --i) {
-		out_be32(MEM_CTRL, i);
+		out_be32(PB3400_MEM_CTRL, i);
 		do {
-			x = (in_be32(MEM_CTRL) >> 16) & 0x3ff;
+			x = (in_be32(PB3400_MEM_CTRL) >> 16) & 0x3ff;
 		} while (x == 0);
 		if (x >= 0x100)
 			break;
@@ -1020,6 +1252,7 @@
 	pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
 	while (!sleep_req.complete)
 		mb();
+
 	/* displacement-flush the L2 cache - necessary? */
 	for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
 		i = *(volatile int *)p;
@@ -1035,7 +1268,7 @@
 	udelay(10);
 
 	/* OK, we're awake again, start restoring things */
-	out_be32(MEM_CTRL, 0x3f);
+	out_be32(PB3400_MEM_CTRL, 0x3f);
 	pbook_pci_restore();
 
 	/* wait for the PMU interrupt sequence to complete */
@@ -1043,21 +1276,10 @@
 		mb();
 
 	/* reenable interrupts */
-	for (i = 0; i < 32; ++i)
-		if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
-			enable_irq(i);
+	sleep_restore_intrs();
 
 	/* Notify drivers */
-	notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
-
-	/* reenable ADB autopoll */
-	pmu_adb_autopoll(adb_dev_map);
-
-	/* Turn on the screen backlight, if it was on before */
-	if (save_backlight)
-		pmu_enable_backlight(1);
-
-	/* Wait for the hard disk to spin up */
+	broadcast_wake();
 
 	return 0;
 }
@@ -1065,15 +1287,112 @@
 /*
  * Support for /dev/pmu device
  */
+#define RB_SIZE		10
+struct pmu_private {
+	struct list_head list;
+	int	rb_get;
+	int	rb_put;
+	struct rb_entry {
+		unsigned short len;
+		unsigned char data[16];
+	}	rb_buf[RB_SIZE];
+	wait_queue_head_t wait;
+	spinlock_t lock;
+};
+
+static LIST_HEAD(all_pmu_pvt);
+static spinlock_t all_pvt_lock = SPIN_LOCK_UNLOCKED;
+
+static void pmu_pass_intr(unsigned char *data, int len)
+{
+	struct pmu_private *pp;
+	struct list_head *list;
+	int i;
+	unsigned long flags;
+
+	if (len > sizeof(pp->rb_buf[0].data))
+		len = sizeof(pp->rb_buf[0].data);
+	spin_lock_irqsave(&all_pvt_lock, flags);
+	for (list = &all_pmu_pvt; (list = list->next) != &all_pmu_pvt; ) {
+		pp = list_entry(list, struct pmu_private, list);
+		i = pp->rb_put + 1;
+		if (i >= RB_SIZE)
+			i = 0;
+		if (i != pp->rb_get) {
+			struct rb_entry *rp = &pp->rb_buf[pp->rb_put];
+			rp->len = len;
+			memcpy(rp->data, data, len);
+			pp->rb_put = i;
+			wake_up_interruptible(&pp->wait);
+		}
+	}
+	spin_unlock_irqrestore(&all_pvt_lock, flags);
+}
+
 static int __openfirmware pmu_open(struct inode *inode, struct file *file)
 {
+	struct pmu_private *pp;
+	unsigned long flags;
+
+	pp = kmalloc(sizeof(struct pmu_private), GFP_KERNEL);
+	if (pp == 0)
+		return -ENOMEM;
+	pp->rb_get = pp->rb_put = 0;
+	spin_lock_init(&pp->lock);
+	init_waitqueue_head(&pp->wait);
+	spin_lock_irqsave(&all_pvt_lock, flags);
+	list_add(&pp->list, &all_pmu_pvt);
+	spin_unlock_irqrestore(&all_pvt_lock, flags);
+	file->private_data = pp;
 	return 0;
 }
 
 static ssize_t __openfirmware pmu_read(struct file *file, char *buf,
 			size_t count, loff_t *ppos)
 {
-	return 0;
+	struct pmu_private *pp = file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+	int ret;
+
+	if (count < 1 || pp == 0)
+		return -EINVAL;
+	ret = verify_area(VERIFY_WRITE, buf, count);
+	if (ret)
+		return ret;
+
+	add_wait_queue(&pp->wait, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+
+	for (;;) {
+		ret = -EAGAIN;
+		spin_lock(&pp->lock);
+		if (pp->rb_get != pp->rb_put) {
+			int i = pp->rb_get;
+			struct rb_entry *rp = &pp->rb_buf[i];
+			ret = rp->len;
+			if (ret > count)
+				ret = count;
+			if (ret > 0 && copy_to_user(buf, rp->data, ret))
+				ret = -EFAULT;
+			if (++i >= RB_SIZE)
+				i = 0;
+			pp->rb_get = i;
+		}
+		spin_unlock(&pp->lock);
+		if (ret >= 0)
+			break;
+
+		if (file->f_flags & O_NONBLOCK)
+			break;
+		ret = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&pp->wait, &wait);
+
+	return ret;
 }
 
 static ssize_t __openfirmware pmu_write(struct file *file, const char *buf,
@@ -1082,26 +1401,65 @@
 	return 0;
 }
 
+static unsigned int pmu_fpoll(struct file *filp, poll_table *wait)
+{
+	struct pmu_private *pp = filp->private_data;
+	unsigned int mask = 0;
+
+	if (pp == 0)
+		return 0;
+	poll_wait(filp, &pp->wait, wait);
+	spin_lock(&pp->lock);
+	if (pp->rb_get != pp->rb_put)
+		mask |= POLLIN;
+	spin_unlock(&pp->lock);
+	return mask;
+}
+
+static int pmu_release(struct inode *inode, struct file *file)
+{
+	struct pmu_private *pp = file->private_data;
+	unsigned long flags;
+
+	if (pp != 0) {
+		file->private_data = 0;
+		spin_lock_irqsave(&all_pvt_lock, flags);
+		list_del(&pp->list);
+		spin_unlock_irqrestore(&all_pvt_lock, flags);
+		kfree(pp);
+	}
+	return 0;
+}
+
 /* Note: removed __openfirmware here since it causes link errors */
-static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp,
+static int pmu_ioctl(struct inode * inode, struct file *filp,
 		     u_int cmd, u_long arg)
 {
 	int error;
 	__u32 value;
 
 	switch (cmd) {
-	    case PMU_IOC_SLEEP:
-	    	if (pmu_kind != PMU_OHARE_BASED)
-	    		return -ENOSYS;
-		return powerbook_sleep();
-	    case PMU_IOC_GET_BACKLIGHT:
+	case PMU_IOC_SLEEP:
+		switch (pmu_kind) {
+		case PMU_OHARE_BASED:
+			error = powerbook_sleep_3400();
+			break;
+		case PMU_HEATHROW_BASED:
+		case PMU_PADDINGTON_BASED:
+			error = powerbook_sleep_G3();
+			break;
+		default:
+			error = ENOSYS;
+		}
+		return error;
+	case PMU_IOC_GET_BACKLIGHT:
 		return put_user(backlight_level, (__u32 *)arg);
-	    case PMU_IOC_SET_BACKLIGHT:
+	case PMU_IOC_SET_BACKLIGHT:
 		error = get_user(value, (__u32 *)arg);
 		if (!error)
 			pmu_set_brightness(value);
 		return error;
-	    case PMU_IOC_GET_MODEL:
+	case PMU_IOC_GET_MODEL:
 	    	return put_user(pmu_kind, (__u32 *)arg);
 	}
 	return -EINVAL;
@@ -1112,12 +1470,12 @@
 	pmu_read,
 	pmu_write,
 	NULL,		/* no readdir */
-	NULL,		/* no poll yet */
+	pmu_fpoll,
 	pmu_ioctl,
 	NULL,		/* no mmap */
 	pmu_open,
 	NULL,		/* flush */
-	NULL		/* no release */
+	pmu_release,
 };
 
 static struct miscdevice pmu_device = {
diff -u --recursive --new-file v2.3.19/linux/drivers/misc/Config.in linux/drivers/misc/Config.in
--- v2.3.19/linux/drivers/misc/Config.in	Mon Oct  4 15:49:29 1999
+++ linux/drivers/misc/Config.in	Thu Oct  7 10:17:09 1999
@@ -4,13 +4,6 @@
 mainmenu_option next_comment
 comment 'Misc devices'
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Generic ACPI support' CONFIG_ACPI
-fi
-
-# PIIX4 ACPI requires PCI for setup and a hardcoded TSC for timing
-if [ "$CONFIG_PCI" = "y" -a "$CONFIG_X86_TSC" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'PIIX4 ACPI support' CONFIG_PIIX4_ACPI
-fi
+tristate 'Generic ACPI support' CONFIG_ACPI
 
 endmenu
diff -u --recursive --new-file v2.3.19/linux/drivers/misc/Makefile linux/drivers/misc/Makefile
--- v2.3.19/linux/drivers/misc/Makefile	Mon Oct  4 15:49:29 1999
+++ linux/drivers/misc/Makefile	Thu Oct  7 10:17:09 1999
@@ -26,10 +26,6 @@
   endif
 endif
 
-ifdef CONFIG_PIIX4_ACPI
-O_OBJS += piix4_acpi.o
-endif
-
 include $(TOPDIR)/Rules.make
 
 fastdep:
diff -u --recursive --new-file v2.3.19/linux/drivers/misc/acpi.c linux/drivers/misc/acpi.c
--- v2.3.19/linux/drivers/misc/acpi.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/misc/acpi.c	Fri Oct  8 13:36:46 1999
@@ -18,6 +18,11 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/*
+ * See http://www.geocities.com/SiliconValley/Hardware/3165/
+ * for the user-level ACPI stuff
+ */
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
@@ -46,6 +51,10 @@
 static struct acpi_facp *acpi_facp = NULL;
 static unsigned long acpi_facp_addr = 0;
 static unsigned long acpi_dsdt_addr = 0;
+
+static volatile u32 acpi_pm1_status = 0;
+static volatile u32 acpi_gpe_status = 0;
+static volatile u32 acpi_gpe_level = 0;
 static DECLARE_WAIT_QUEUE_HEAD(acpi_wait_event);
 
 /*
@@ -73,6 +82,19 @@
 }
 
 /*
+ * Get the value of the fixed event enable register
+ */
+static u32 acpi_read_pm1_enable(struct acpi_facp *facp)
+{
+	int offset = facp->pm1_evt_len >> 1;
+	u32 value = inw(facp->pm1a_evt + offset);
+	if (facp->pm1b_evt) {
+		value |= inw(facp->pm1b_evt + offset);
+	}
+	return value;
+}
+
+/*
  * Set the value of the fixed event enable register (enable events)
  */
 static void acpi_write_pm1_enable(struct acpi_facp *facp, u32 value)
@@ -128,6 +150,28 @@
 }
 
 /*
+ * Get the value of the general-purpose event enable register
+ */
+static u32 acpi_read_gpe_enable(struct acpi_facp *facp)
+{
+	u32 value = 0;
+	int i, size, offset;
+	
+	offset = facp->gpe0_len >> 1;
+	if (facp->gpe1) {
+		size = facp->gpe1_len >> 1;
+		for (i = size - 1; i >= 0; i--) {
+			value = (value << 8) | inb(facp->gpe1 + offset + i);
+		}
+	}
+	size = facp->gpe0_len >> 1;
+	for (i = size - 1; i >= 0; i--) {
+		value = (value << 8) | inb(facp->gpe0 + offset + i);
+	}
+	return value;
+}
+
+/*
  * Set the value of the general-purpose event enable register (enable events)
  */
 static void acpi_write_gpe_enable(struct acpi_facp *facp, u32 value)
@@ -157,7 +201,8 @@
 	if (addr) {
 		// map table header to determine size
 		table = (struct acpi_table *)
-		    ioremap_nocache((unsigned long) addr, sizeof(struct acpi_table));
+		    ioremap_nocache((unsigned long) addr,
+				    sizeof(struct acpi_table));
 		if (table) {
 			unsigned long table_size = table->length;
 			iounmap(table);
@@ -201,10 +246,13 @@
 			// strip trailing space and print OEM identifier
 			memcpy_fromio(oem, rsdp->oem, 6);
 			oem[6] = '\0';
-			for (j = 5; j > 0 && (oem[j] == '\0' || oem[j] == ' '); j--) {
+			for (j = 5;
+			     j > 0 && (oem[j] == '\0' || oem[j] == ' ');
+			     j--) {
 				oem[j] = '\0';
 			}
-			printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n", oem, (void *) i);
+			printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n",
+			       oem, (void *) i);
 
 			break;
 		}
@@ -252,6 +300,7 @@
  */
 static void acpi_unmap_tables(void)
 {
+	acpi_idle = NULL;
 	acpi_dsdt_addr = 0;
 	acpi_facp_addr = 0;
 	acpi_unmap_table((struct acpi_table *) acpi_facp);
@@ -263,17 +312,32 @@
  */
 static void acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
-	u32 status;
-
-	// detect and disable any fixed events
-	status = acpi_read_pm1_status(acpi_facp);
-	acpi_write_pm1_enable(acpi_facp, ~status);
-
-	// detect and disable any general-purpose events
-	status = acpi_read_gpe_status(acpi_facp);
-	acpi_write_gpe_enable(acpi_facp, ~status);
-
+	u32 pm1_status, gpe_status, gpe_level, gpe_edge;
+	// detect and clear fixed events
+	pm1_status = (acpi_read_pm1_status(acpi_facp)
+		      & acpi_read_pm1_enable(acpi_facp));
+	acpi_write_pm1_status(acpi_facp, pm1_status);
+	
+	// detect and handle general-purpose events
+	gpe_status = (acpi_read_gpe_status(acpi_facp)
+		      & acpi_read_gpe_enable(acpi_facp));
+	gpe_level = gpe_status & acpi_gpe_level;
+	if (gpe_level) {
+		// disable level-triggered events
+		acpi_write_gpe_enable(
+			acpi_facp,
+			acpi_read_gpe_enable(acpi_facp) & ~gpe_level);
+	}
+	gpe_edge = gpe_status & ~gpe_level;
+	if (gpe_edge) {
+		// clear edge-triggered events
+		while (acpi_read_gpe_status(acpi_facp) & gpe_edge)
+			acpi_write_gpe_status(acpi_facp, gpe_edge);
+	}
+	
 	// notify process reading /dev/acpi
+	acpi_pm1_status |= pm1_status;
+	acpi_gpe_status |= gpe_status;
 	wake_up_interruptible(&acpi_wait_event);
 }
 
@@ -311,17 +375,79 @@
 				     (void *) arg,
 				     sizeof(struct acpi_find_tables));
 		if (!status) {
-			struct acpi_find_tables *rqst = (struct acpi_find_tables *) arg;
+			struct acpi_find_tables *rqst
+				= (struct acpi_find_tables *) arg;
 			put_user(acpi_facp_addr, &rqst->facp);
 			put_user(acpi_dsdt_addr, &rqst->dsdt);
 			status = 0;
 		}
 		break;
+	case ACPI_ENABLE_EVENT:
+		status = verify_area(VERIFY_READ,
+				     (void *) arg,
+				     sizeof(struct acpi_enable_event));
+		if (!status) {
+			struct acpi_enable_event *rqst
+				= (struct acpi_enable_event *) arg;
+			u32 pm1_enable, gpe_enable, gpe_level;
+			u32 pm1_enabling, gpe_enabling;
+			
+			get_user(pm1_enable, &rqst->pm1_enable);
+			get_user(gpe_enable, &rqst->gpe_enable);
+			get_user(gpe_level, &rqst->gpe_level);
+			gpe_level &= gpe_enable;
+			
+			// clear previously disabled events before enabling
+			pm1_enabling = (pm1_enable
+					& ~acpi_read_pm1_enable(acpi_facp));
+			acpi_write_pm1_status(acpi_facp, pm1_enabling);
+			gpe_enabling = (gpe_enable &
+					~acpi_read_gpe_enable(acpi_facp));
+			while (acpi_read_gpe_status(acpi_facp) & gpe_enabling)
+				acpi_write_gpe_status(acpi_facp, gpe_enabling);
+			
+			acpi_write_pm1_enable(acpi_facp, pm1_enable);
+			acpi_write_gpe_enable(acpi_facp, gpe_enable);
+			acpi_gpe_level = gpe_level;
+			
+			status = 0;
+		}
+		break;
 	case ACPI_WAIT_EVENT:
-		interruptible_sleep_on(&acpi_wait_event);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		status = 0;
+		status = verify_area(VERIFY_WRITE,
+				     (void *) arg,
+				     sizeof(struct acpi_wait_event));
+		if (!status) {
+			struct acpi_wait_event *rqst
+				= (struct acpi_wait_event *) arg;
+			u32 pm1_status = 0;
+			u32 gpe_status = 0;
+			
+			for (;;) {
+				unsigned long flags;
+				
+				// we need an atomic exchange here
+				save_flags(flags);
+				cli();
+				pm1_status = acpi_pm1_status;
+				acpi_pm1_status = 0;
+				gpe_status = acpi_gpe_status;
+				acpi_gpe_status = 0;
+				restore_flags(flags);
+
+				if (pm1_status || gpe_status)
+					break;
+
+				// wait for an event to arrive
+				interruptible_sleep_on(&acpi_wait_event);
+				if (signal_pending(current))
+					return -ERESTARTSYS;
+			}
+
+			put_user(pm1_status, &rqst->pm1_status);
+			put_user(gpe_status, &rqst->gpe_status);
+			status = 0;
+		}
 		break;
 	}
 	return status;
@@ -355,6 +481,48 @@
 	NULL
 };
 
+/* Make it impossible to enter L2/L3 until after we've initialized */
+static unsigned long acpi_p_lvl2_lat = ~0UL;
+static unsigned long acpi_p_lvl3_lat = ~0UL;
+
+/* Initialize to guaranteed harmless port read */
+static u16 acpi_p_lvl2 = 0x80;
+static u16 acpi_p_lvl3 = 0x80;
+
+static void acpi_idle_handler(void)
+{
+	unsigned long time;
+	static int sleep_level = 1;
+
+	time = inl(acpi_facp->pm_tmr);
+	switch (sleep_level) {
+	case 1:
+		__asm__ __volatile__("sti ; hlt": : :"memory");
+		break;
+	case 2:
+		inb(acpi_p_lvl2);
+		break;
+	case 3:
+		/* Disable PCI arbitration while sleeping, to avoid DMA corruption? */
+		if (acpi_facp->pm2_cnt) {
+			unsigned int port = acpi_facp->pm2_cnt;
+			outb(inb(port) | ACPI_ARB_DIS, port);
+			inb(acpi_p_lvl3);
+			outb(inb(port) & ~ACPI_ARB_DIS, port);
+			break;
+		}
+		inb(acpi_p_lvl3);
+	}
+	time = (inl(acpi_facp->pm_tmr) - time) & ACPI_TMR_MASK;
+
+	if (time > acpi_p_lvl3_lat)
+		sleep_level = 3;
+	else if (time > acpi_p_lvl2_lat)
+		sleep_level = 2;
+	else
+		sleep_level = 1;
+}
+
 /*
  * Initialize and enable ACPI
  */
@@ -376,6 +544,17 @@
 	if (misc_register(&acpi_device)) {
 		printk(KERN_ERR "ACPI: misc. register failed\n");
 	}
+
+	/*
+	 * Set up the ACPI idle function. Note that we can't really
+	 * do this with multiple CPU's, we'd need a per-CPU ACPI
+	 * device..
+	 */
+#ifdef __SMP__
+	if (smp_num_cpus > 1)
+		return 0;
+#endif
+	acpi_idle = acpi_idle_handler;
 	return 0;
 }
 
@@ -389,7 +568,8 @@
 	// disable and clear any pending events
 	acpi_write_gpe_enable(acpi_facp, 0);
 	while (acpi_read_gpe_status(acpi_facp)) {
-		acpi_write_gpe_status(acpi_facp, acpi_read_gpe_status(acpi_facp));
+		acpi_write_gpe_status(acpi_facp,
+				      acpi_read_gpe_status(acpi_facp));
 	}
 	acpi_write_pm1_enable(acpi_facp, 0);
 	acpi_write_pm1_status(acpi_facp, acpi_read_pm1_status(acpi_facp));
@@ -405,6 +585,7 @@
 
 module_init(acpi_init)
 module_exit(acpi_exit)
+
 #else
 
 __initcall(acpi_init);
diff -u --recursive --new-file v2.3.19/linux/drivers/misc/piix4_acpi.c linux/drivers/misc/piix4_acpi.c
--- v2.3.19/linux/drivers/misc/piix4_acpi.c	Fri Aug 13 13:50:58 1999
+++ linux/drivers/misc/piix4_acpi.c	Wed Dec 31 16:00:00 1969
@@ -1,214 +0,0 @@
-/*
- * linux/drivers/misc/piix4_acpi.c
- *
- *	(C) Copyright 1999 Linus Torvalds
- *
- * A PM driver for the ACPI portion of the Intel PIIX4
- * chip.
- *
- * This has been known to occasionally work on some laptops.
- *
- * It probably only works on Intel PII machines that support
- * the STPCLK protocol.
- */
-
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-extern void (*acpi_idle)(void);
-
-/*
- * This first part should be common to all ACPI
- * CPU sleep functionality. Assuming we get the
- * timing heuristics in a better shape than "none" ;)
- */
-
-typedef void (*sleep_fn_t)(void);
-
-/*
- * Our "sleep mode" is a fixed point number
- * with two binary places, ranging between
- * [0 .. 3[
- */
-#define Cx_SHIFT	2
-#define MAXMODE		((3 << Cx_SHIFT)-1)
-
-/*
- * NOTE!
- *
- * Right now this always defaults to C3, which is just broken.
- * The exit latency is usually too high for much busy IO activity,
- * and generally it's not always the best thing to do.
- *
- * We should just read the cycle counter around all the cases,
- * and if we pause for a long time we go to a deeper sleep, while
- * a short wait makes us go into a lighter sleep.
- */
-static void common_acpi_idle(sleep_fn_t *sleep)
-{
-	int mode = MAXMODE;
-
-	while (1) {
-		while (!current->need_resched) {
-			unsigned int time;
-
-			time = get_cycles();
-			sleep[(mode) >> Cx_SHIFT]();
-			time = get_cycles() - time;
-
-			/*
-			 * Yeah, yeah, yeah.
-			 *  if (time > Large && mode < MAXMODE) mode++;
-			 *  if (time < Small && mode > 0) mode--;
-			 * Yadda-yadda-yadda.
-			 *
-			 * "Large" is on the order of half a timer tick.
-			 * "Small" is on the order of Large >> 2 or so.
-			 *
-			 * Somebody should _really_ look at the exact
-			 * details. The ACPI bios would give some made-up
-			 * numbers, they might be useful (or maybe not:
-			 * they are probably tuned for whatever Windows
-			 * does, so don't take them for granted).
-			 */
-		}
-		schedule();
-		check_pgt_cache();
-	}
-}		
-
-/* Ok, here starts the magic PIIX4 knowledge */
-
-/*
- * Ehh.. We "know" about the northbridge
- * bus arbitration stuff. Maybe somebody
- * should actually verify this some day?
- */
-#define NORTHBRIDGE_CONTROL	0x22
-#define		NB_ARBITRATE	0x01
-
-/*
- * PIIX4 ACPI IO offsets and defines
- */
-#define PMEN		0x02
-#define PMCNTRL		0x04
-#define PMTMR		0x08
-#define GPSTS		0x0c
-#define GPEN		0x0E
-
-#define PCNTRL		0x10
-#define   CC_EN			0x0200
-#define   BST_EN		0x0400
-#define   SLEEP_EN		0x0800
-#define   STPCLK_EN		0x1000
-#define   CLKRUN_EN		0x2000
-
-#define PLVL2		0x14
-#define PLVL3		0x15
-
-/*
- * PIIX4 ACPI PCI configurations offsets and defines
- */
-#define DEVACTB		0x58
-#define   BRLD_EN_IRQ0	0x01
-#define   BRLD_EN_IRQ	0x02
-
-#define PMREGMISC	0x80
-#define   PMIOSE		0x01
-
-static unsigned int piix4_base_address = 0;
-
-static void piix4_c1_sleep(void)
-{
-	asm volatile("sti ; hlt" : : : "memory");
-}
-
-static void piix4_c2_sleep(void)
-{
-	outl(CLKRUN_EN | CC_EN, piix4_base_address + PCNTRL);
-	inb(piix4_base_address + PLVL2);
-}
-
-static void piix4_c3_sleep(void)
-{
-	__cli();
-	outl(CLKRUN_EN | CC_EN | STPCLK_EN | SLEEP_EN, piix4_base_address + PCNTRL);
-	outb(NB_ARBITRATE, NORTHBRIDGE_CONTROL);
-	inb(piix4_base_address + PLVL3);
-	outb(0, NORTHBRIDGE_CONTROL);
-	__sti();
-}
-
-static sleep_fn_t piix4_sleep[] = {
-	piix4_c1_sleep,		/* low-latency C1 (ie "sti ; hlt") */
-	piix4_c2_sleep,		/* medium latency C2 (ie LVL2 stopckl) */
-	piix4_c3_sleep		/* high-latency C3 (ie LVL3 sleep) */
-};
-
-static void piix4_acpi_idle(void)
-{
-	common_acpi_idle(piix4_sleep);
-}
-
-static int __init piix4_acpi_init(void)
-{
-	/* This is the PIIX4 ACPI device */
-	struct pci_dev *dev;
-	u32 base, val;
-	u16 cmd;
-	u8 pmregmisc;
-
-#ifdef __SMP__
-	/*
-	 * We can't really do idle things with multiple CPU's, I'm
-	 * afraid.  We'd need a per-CPU ACPI device.
-	 */
-	if (smp_num_cpus > 1)
-		return -1;
-#endif
-	dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
-
-	if (!dev)
-		return -1;
-
-	/*
-	 * Read the IO base value, and verify that it makes sense
-	 *
-	 * We could enable this if it wasn't enabled before, but
-	 * let's walk before we run..
-	 */
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	if (!(cmd & PCI_COMMAND_IO))
-		return -1;
-
-	pci_read_config_byte(dev, PMREGMISC, &pmregmisc);
-	if (!(pmregmisc & PMIOSE))
-		return -1;
-
-	pci_read_config_dword(dev, 0x40, &base);
-	if (!(base & PCI_BASE_ADDRESS_SPACE_IO))
-		return -1;
-
-	base &= PCI_BASE_ADDRESS_IO_MASK;
-	if (!base)
-		return -1;
-
-	printk("Found PIIX4 ACPI device at %04x\n", base);
-	piix4_base_address = base;
-
-	/* Enable stopcklock, sleep and bursts, along with clock control */
-	outl(CLKRUN_EN | CC_EN | STPCLK_EN | SLEEP_EN, piix4_base_address + PCNTRL);
-
-	/* Make all unmasked interrupts be BREAK events */
-	pci_read_config_dword(dev, DEVACTB, &val);
-	pci_write_config_dword(dev, DEVACTB, val | BRLD_EN_IRQ0 | BRLD_EN_IRQ);
-
-	/* Set up the new idle handler.. */
-	acpi_idle = piix4_acpi_idle;
-	return 0;
-}
-
-__initcall(piix4_acpi_init);
diff -u --recursive --new-file v2.3.19/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
--- v2.3.19/linux/drivers/net/pcmcia/ray_cs.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/pcmcia/ray_cs.c	Thu Oct  7 11:50:26 1999
@@ -57,21 +57,17 @@
    left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
    be present but disabled -- but it can then be enabled for specific
    modules at load time with a 'pc_debug=#' option to insmod.
-
-   I found that  adding -DPCMCIA_DEBUG to the compile options during
-   the 'make config' resulted in cardmgr not finding any sockets.
-   Therefore, this module uses RAYLINK_DEBUG instead.
-   The module option to use is ray_debug=#
-    where # is 1 for modest output
-               2 for more output
-               ...
 */
 
 #ifdef RAYLINK_DEBUG
-static int ray_debug = RAYLINK_DEBUG;
-MODULE_PARM(ray_debug, "i");
-/* #define DEBUG(n, args...) if (ray_debug>(n)) printk(KERN_DEBUG args); */
-#define DEBUG(n, args...) if (ray_debug>(n)) printk(args);
+#define PCMCIA_DEBUG RAYLINK_DEBUG
+#endif
+#ifdef PCMCIA_DEBUG
+static int ray_debug = 0;
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+/* #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); */
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(args);
 #else
 #define DEBUG(n, args...)
 #endif
@@ -137,7 +133,6 @@
 /* void start_net(ray_dev_t *local); */
 
 int ray_cs_proc_read(char *buf, char **start, off_t off, int len, int spare);
-
 /* Create symbol table for registering with kernel in init_module */
 EXPORT_SYMBOL(ray_dev_ioctl);
 EXPORT_SYMBOL(ray_rx);
@@ -147,40 +142,30 @@
 /* Bit map of interrupts to choose from */
 /* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
 static u_long irq_mask = 0xdeb8;
-MODULE_PARM(irq_mask,"i");
 
 /* ADHOC=0, Infrastructure=1 */
 static int net_type = ADHOC;
-MODULE_PARM(net_type,"i");
 
 /* Hop dwell time in Kus (1024 us units defined by 802.11) */
 static int hop_dwell = 128;
-MODULE_PARM(hop_dwell,"i");
 
 /* Beacon period in Kus */
 static int beacon_period = 256;
-MODULE_PARM(beacon_period,"i");
 
 /* power save mode (0 = off, 1 = save power) */
 static int psm = 0;
-MODULE_PARM(psm,"i");
 
 /* String for network's Extended Service Set ID. 32 Characters max */
 static char *essid = NULL;
-MODULE_PARM(essid,"s");
 
 /* Default to encapsulation unless translation requested */
 static int translate = 1;
-MODULE_PARM(translate,"i");
 
 static int country = USA;
-MODULE_PARM(country,"i");
 
 static int sniffer = 0;
-MODULE_PARM(sniffer,"i");
 
 static int bc = 0;
-MODULE_PARM(bc,"i");
 
 /* 48 bit physical card address if overriding card's real physical
  * address is required.  Since IEEE 802.11 addresses are 48 bits
@@ -193,7 +178,6 @@
  * things will happen if it is not 0 in a card address.
  */
 static char *phy_addr = NULL;
-MODULE_PARM(phy_addr,"s");
 
 
 /* The dev_info variable is the "key" that is used to match up this
@@ -214,7 +198,22 @@
    'priv' pointer in a dev_link_t structure can be used to point to
    a device-specific private data structure, like this.
 */
-static const unsigned int ray_mem_speed = 0x2A;
+static unsigned int ray_mem_speed = 0x2A;
+
+MODULE_AUTHOR("Corey Thomas <corey@world.std.com>");
+MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver");
+MODULE_PARM(irq_mask,"i");
+MODULE_PARM(net_type,"i");
+MODULE_PARM(hop_dwell,"i");
+MODULE_PARM(beacon_period,"i");
+MODULE_PARM(psm,"i");
+MODULE_PARM(essid,"s");
+MODULE_PARM(translate,"i");
+MODULE_PARM(country,"i");
+MODULE_PARM(sniffer,"i");
+MODULE_PARM(bc,"i");
+MODULE_PARM(phy_addr,"s");
+MODULE_PARM(ray_mem_speed, "i");
 
 static UCHAR b5_default_startup_parms[] = {
     0,   0,                         /* Adhoc station */
@@ -284,7 +283,7 @@
 /*===========================================================================*/
 static unsigned char eth2_llc[] = {0xaa, 0xaa, 3, 0, 0, 0};
 
-static char rcsid[] = " $Id: ray_cs.c,v 1.60 1999/09/01 20:58:45 corey Exp $ - Corey Thomas corey@world.std.com";
+static char rcsid[] = "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>";
 
 #ifdef CONFIG_PROC_FS
 struct proc_dir_entry ray_cs_proc_entry = {
@@ -358,7 +357,7 @@
     local->finder = link;
     link->dev = &local->node;
     local->card_status = CARD_INSERTED;
-	local->authentication_state = UNAUTHENTICATED;
+    local->authentication_state = UNAUTHENTICATED;
     local->num_multi = 0;
     DEBUG(2,"ray_attach link = %p,  dev = %p,  local = %p, intr = %p\n",
           link,dev,local,&ray_interrupt);
@@ -442,8 +441,6 @@
     if (link->state & DEV_CONFIG) {
         ray_release((u_long)link);
         if(link->state & DEV_STALE_CONFIG) {
-            DEBUG(0,"ray_cs: detach postponed, '%s' "
-              "still locked\n", link->dev->dev_name);
             link->state |= DEV_STALE_LINK;
             return;
         }
@@ -472,7 +469,7 @@
 =============================================================================*/
 #define CS_CHECK(fn, args...) \
 while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
-#define MAX_TUPLE_SIZE 80
+#define MAX_TUPLE_SIZE 128
 void ray_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
@@ -480,7 +477,7 @@
     cisparse_t parse;
     int last_fn, last_ret;
     int i;
-    u_char buf[80];
+    u_char buf[MAX_TUPLE_SIZE];
     win_req_t req;
     memreq_t mem;
     struct net_device *dev = (struct net_device *)link->priv;
@@ -499,6 +496,19 @@
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
 
+    /* Determine card type and firmware version */
+    buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0;
+    tuple.DesiredTuple = CISTPL_VERS_1;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = MAX_TUPLE_SIZE;
+    tuple.TupleOffset = 2;
+    CS_CHECK(GetTupleData, handle, &tuple);
+
+    for (i=0; i<tuple.TupleDataLen - 4; i++) 
+        if (buf[i] == 0) buf[i] = ' ';
+    printk(KERN_INFO "ray_cs Detected: %s\n",buf);
+
     /* Configure card */
     link->state |= DEV_CONFIG;
 
@@ -562,7 +572,10 @@
     }
 
     link->state &= ~DEV_CONFIG_PENDING;
-    DEBUG(0, "ray_cs device loaded\n");
+    printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ",
+       dev->name, dev->irq);
+    for (i = 0; i < 6; i++)
+    printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
     return;
 
@@ -594,7 +607,8 @@
 
     /* Check Power up test status and get mac address from card */
     if (local->startup_res.startup_word != 0x80) {
-DEBUG(0,"ray_init ERROR card status = %2x\n", local->startup_res.startup_word);
+    printk(KERN_INFO "ray_init ERROR card status = %2x\n",
+           local->startup_res.startup_word);
         local->card_status = CARD_INIT_ERROR;
         return -1;
     }
@@ -619,16 +633,12 @@
     if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr))
     {
         p = local->sparm.b4.a_mac_addr;
-        DEBUG(1,"ray_cs phy address overridden = %2x %2x %2x %2x %2x %2x\n",\
-              p[0],p[1],p[2],p[3],p[4],p[5]);
     }
     else
     {
         memcpy(&local->sparm.b4.a_mac_addr,
                &local->startup_res.station_addr, ADDRLEN);
         p = local->sparm.b4.a_mac_addr;
-        DEBUG(1,"ray_cs phy addr= %2x %2x %2x %2x %2x %2x\n",\
-              p[0],p[1],p[2],p[3],p[4],p[5]);
     }
 
     clear_interrupt(local); /* Clear any interrupt from the card */
@@ -647,7 +657,7 @@
 
     DEBUG(1,"dl_startup_params entered\n");
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_cs dl_startup_params - device not present\n");
+        DEBUG(2,"ray_cs dl_startup_params - device not present\n");
         return -1;
     }
     
@@ -661,14 +671,15 @@
 
     
     /* Fill in the CCS fields for the ECF */
-    if ((ccsindex = get_free_ccs(local)) == -1) return -1;
+    if ((ccsindex = get_free_ccs(local)) < 0) return -1;
     local->dl_param_ccs = ccsindex;
     pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
     writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd);
     DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs);
     /* Interrupt the firmware to process the command */
     if (interrupt_ecf(local, ccsindex)) {
-        DEBUG(0,"ray dl_startup_params failed - ECF not ready for intr\n");
+        printk(KERN_INFO "ray dl_startup_params failed - "
+           "ECF not ready for intr\n");
         local->card_status = CARD_DL_PARAM_ERROR;
         writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
         return -2;
@@ -723,11 +734,11 @@
         local->sparm.b4.a_curr_country_code = country;
         local->sparm.b4.a_hop_pattern_length = 
             hop_pattern_length[(int)country] - 1;
-		if (bc)
-		{
-			local->sparm.b4.a_ack_timeout = 0x50;
-			local->sparm.b4.a_sifs = 0x3f;
-		}
+        if (bc)
+        {
+            local->sparm.b4.a_ack_timeout = 0x50;
+            local->sparm.b4.a_sifs = 0x3f;
+        }
     }
     else {    /* Version 5 uses real kus values */
         memcpy((UCHAR *)&local->sparm.b5, b5_default_startup_parms, 
@@ -756,30 +767,29 @@
     ray_dev_t *local = (ray_dev_t *)data;
     struct ccs *pccs = ((struct ccs *)(local->sram + CCS_BASE)) + local->dl_param_ccs;
     UCHAR status;
-/*    UCHAR *p = local->sram + HOST_TO_ECF_BASE; */
     dev_link_t *link = local->finder;
 
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_cs verify_dl_startup - device not present\n");
+        DEBUG(2,"ray_cs verify_dl_startup - device not present\n");
         return;
     }
-#ifdef RAYLINK_DEBUG
-    {
-	int i;
-        DEBUG(2,"verify_dl_startup parameters sent via ccs %d:\n",\
-              local->dl_param_ccs);
-        for (i=0; i<sizeof(struct b5_startup_params); i++)
-        {
-            DEBUG(1," %2x ", readb(local->sram + HOST_TO_ECF_BASE + i));
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 2) {
+    int i;
+    printk(KERN_DEBUG "verify_dl_startup parameters sent via ccs %d:\n",
+           local->dl_param_ccs);
+        for (i=0; i<sizeof(struct b5_startup_params); i++) {
+            printk(" %2x", readb(local->sram + HOST_TO_ECF_BASE + i));
         }
-        DEBUG(1,"\n");
+    printk("\n");
     }
 #endif
 
     status = readb(&pccs->buffer_status);
     if (status!= CCS_BUFFER_FREE)
     {
-        DEBUG(0,"Download startup params failed.  Status = %d\n",status);
+        printk(KERN_INFO "Download startup params failed.  Status = %d\n",
+           status);
         local->card_status = CARD_DL_PARAM_ERROR;
         return;
     }
@@ -799,11 +809,11 @@
     int ccsindex;
     dev_link_t *link = local->finder;
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_cs start_net - device not present\n");
+        DEBUG(2,"ray_cs start_net - device not present\n");
         return;
     }
     /* Fill in the CCS fields for the ECF */
-    if ((ccsindex = get_free_ccs(local)) == -1) return;
+    if ((ccsindex = get_free_ccs(local)) < 0) return;
     pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
     writeb(CCS_START_NETWORK, &pccs->cmd);
     writeb(0, &pccs->var.start_network.update_param);
@@ -827,11 +837,11 @@
     dev_link_t *link = local->finder;
     
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_cs join_net - device not present\n");
+        DEBUG(2,"ray_cs join_net - device not present\n");
         return;
     }
     /* Fill in the CCS fields for the ECF */
-    if ((ccsindex = get_free_ccs(local)) == -1) return;
+    if ((ccsindex = get_free_ccs(local)) < 0) return;
     pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
     writeb(CCS_JOIN_NETWORK, &pccs->cmd);
     writeb(0, &pccs->var.join_network.update_param);
@@ -867,7 +877,7 @@
         link->state |= DEV_STALE_CONFIG;
         return;
     }
-	del_timer(&local->timer);
+    del_timer(&local->timer);
     if (link->dev != '\0') unregister_netdev(dev);
     /* Unlink the device chain */
     link->dev = NULL;
@@ -962,13 +972,14 @@
 
     DEBUG(1,"ray_dev_init(dev=%p)\n",dev);
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_dev_init - device not present\n");
+        DEBUG(2,"ray_dev_init - device not present\n");
         return -1;
     }
     /* Download startup parameters */
     if ( (i = dl_startup_params(dev)) < 0)
     {
-        DEBUG(0,"ray_dev_init dl_startup_params failed - returns 0x%x/n",i);
+        printk(KERN_INFO "ray_dev_init dl_startup_params failed - "
+           "returns 0x%x/n",i);
         return -1;
     }
     
@@ -976,15 +987,6 @@
     memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN);
     memset(dev->broadcast, 0xff, ETH_ALEN);
 
-#ifdef RAYLINK_DEBUG
-    {
-    UCHAR *p;
-    p = (UCHAR *)(local->startup_res.station_addr);
-    DEBUG(1,"ray_dev_init card hardware mac addr = %2x %2x %2x %2x %2x %2x\n",\
-          p[0],p[1],p[2],p[3],p[4],p[5]);
-    }
-#endif
-
     DEBUG(2,"ray_dev_init ending\n");
     return 0;
 }
@@ -996,7 +998,7 @@
     /* Dummy routine to satisfy device structure */
     DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map);
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_dev_config - device not present\n");
+        DEBUG(2,"ray_dev_config - device not present\n");
         return -1;
     }
 
@@ -1010,13 +1012,13 @@
     short length;
 
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_dev_start_xmit - device not present\n");
+        DEBUG(2,"ray_dev_start_xmit - device not present\n");
         return -1;
     }
     DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev);
     if (dev->tbusy)
     {
-        DEBUG(2,"ray_dev_start_xmit busy\n");
+        printk(KERN_NOTICE "ray_dev_start_xmit busy\n");
         return 1;
     }
     if (local->authentication_state == NEED_TO_AUTH) {
@@ -1031,7 +1033,7 @@
     length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
     switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) {
         case XMIT_NO_CCS:
-	    case XMIT_NEED_AUTH:
+        case XMIT_NEED_AUTH:
             dev->tbusy = 1;
             return 1;
         case XMIT_NO_INTR:
@@ -1058,15 +1060,20 @@
     DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev);
     if (len + TX_HEADER_LENGTH > TX_BUF_SIZE)
     {
-        DEBUG(0,"ray_hw_xmit packet to large %d bytes\n",len);
+        printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",len);
         return XMIT_MSG_BAD;
     }
-    if ((ccsindex = get_free_tx_ccs(local)) == -1)
-    {
-        DEBUG(2,"ray_hw_xmit - No free tx ccs\n");
+	switch (ccsindex = get_free_tx_ccs(local)) {
+	case ECCSBUSY:
+		DEBUG(2,"ray_hw_xmit tx_ccs table busy\n");
+	case ECCSFULL:
+        DEBUG(2,"ray_hw_xmit No free tx ccs\n");
+	case ECARDGONE:
         dev->tbusy = 1;
         return XMIT_NO_CCS;
-    }
+	default:
+		break;
+	}
     addr = TX_BUF_BASE + (ccsindex << 11);
 
     if (msg_type == DATA_TYPE) {
@@ -1186,7 +1193,7 @@
     int err = 0;
 
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_dev_ioctl - device not present\n");
+        DEBUG(2,"ray_dev_ioctl - device not present\n");
         return -1;
     }
     DEBUG(2,"ray_cs IOCTL dev=%p, ifr=%p, cmd = 0x%x\n",dev,ifr,cmd);
@@ -1258,16 +1265,14 @@
 int interrupt_ecf(ray_dev_t *local, int ccs)
 {
     int i = 50;
-/*    UCHAR *p = (local->amem + CIS_OFFSET + ECF_INTR_OFFSET); */
     dev_link_t *link = local->finder;
 
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_cs interrupt_ecf - device not present\n");
+        DEBUG(2,"ray_cs interrupt_ecf - device not present\n");
         return -1;
     }
     DEBUG(2,"interrupt_ecf(local=%p, ccs = 0x%x\n",local,ccs);
 
-/*    while ( i && (*p & ECF_INTR_SET))  i--; */
     while ( i && 
             (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & ECF_INTR_SET))
         i--;
@@ -1275,8 +1280,8 @@
         DEBUG(2,"ray_cs interrupt_ecf card not ready for interrupt\n");
         return -1;
     }
-
-    *(local->sram + SCB_BASE) = ccs;
+	/* Fill the mailbox, then kick the card */
+    writeb(ccs, local->sram + SCB_BASE);
     writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET);
     return 0;
 } /* interrupt_ecf */
@@ -1290,19 +1295,26 @@
     dev_link_t *link = local->finder;
 
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_cs get_free_tx_ccs - device not present\n");
-        return -1;
+        DEBUG(2,"ray_cs get_free_tx_ccs - device not present\n");
+        return ECARDGONE;
     }
 
+    if (test_and_set_bit(0,&local->tx_ccs_lock)) {
+        DEBUG(1,"ray_cs tx_ccs_lock busy\n");
+        return ECCSBUSY;
+    } 
+
     for (i=0; i < NUMBER_OF_TX_CCS; i++) {
         if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) {
             writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status);
             writeb(CCS_END_LIST, &(pccs+i)->link);
+			local->tx_ccs_lock = 0;
             return i;
         }
     }
-    DEBUG(1,"ray_cs ERROR no free tx CCS for raylink card\n");
-    return -1;
+	local->tx_ccs_lock = 0;
+    DEBUG(2,"ray_cs ERROR no free tx CCS for raylink card\n");
+    return ECCSFULL;
 } /* get_free_tx_ccs */
 /*===========================================================================*/
 /* Get next free CCS                                                         */
@@ -1314,25 +1326,33 @@
     dev_link_t *link = local->finder;
 
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_cs get_free_ccs - device not present\n");
-        return -1;
+        DEBUG(2,"ray_cs get_free_ccs - device not present\n");
+        return ECARDGONE;
     }
+    if (test_and_set_bit(0,&local->ccs_lock)) {
+        DEBUG(1,"ray_cs ccs_lock busy\n");
+        return ECCSBUSY;
+    } 
+
     for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) {
         if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) {
             writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status);
             writeb(CCS_END_LIST, &(pccs+i)->link);
+			local->ccs_lock = 0;
             return i;
         }
     }
+	local->ccs_lock = 0;
     DEBUG(1,"ray_cs ERROR no free CCS for raylink card\n");
-    return -1;
+    return ECCSFULL;
 } /* get_free_ccs */
 /*===========================================================================*/
 void authenticate_timeout(u_long data)
 {
     ray_dev_t *local = (ray_dev_t *)data;
     del_timer(&local->timer);
-    DEBUG(0,"ray_cs Authentication with access point failed - timeout\n");
+    printk(KERN_INFO "ray_cs Authentication with access point failed"
+       " - timeout\n");
     join_net((u_long)local);
 }
 /*===========================================================================*/
@@ -1381,26 +1401,26 @@
     dev_link_t *link = local->finder;
     struct status *p = (struct status *)(local->sram + STATUS_BASE);
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_cs enet_statistics - device not present\n");
+        DEBUG(2,"ray_cs enet_statistics - device not present\n");
         return &local->stats;
     }
-    if (p->mrx_overflow_for_host)
+    if (readb(&p->mrx_overflow_for_host))
     {
-        local->stats.rx_over_errors += ntohs(p->mrx_overflow);
-        p->mrx_overflow = 0;
-        p->mrx_overflow_for_host = 0;
+        local->stats.rx_over_errors += ntohs(readb(&p->mrx_overflow));
+        writeb(0,&p->mrx_overflow);
+        writeb(0,&p->mrx_overflow_for_host);
     }
-    if (p->mrx_checksum_error_for_host)
+    if (readb(&p->mrx_checksum_error_for_host))
     {
-        local->stats.rx_crc_errors += ntohs(p->mrx_checksum_error);
-        p->mrx_checksum_error = 0;
-        p->mrx_checksum_error_for_host = 0;
+        local->stats.rx_crc_errors += ntohs(readb(&p->mrx_checksum_error));
+        writeb(0,&p->mrx_checksum_error);
+        writeb(0,&p->mrx_checksum_error_for_host);
     }
-    if (p->rx_hec_error_for_host)
+    if (readb(&p->rx_hec_error_for_host))
     {
-        local->stats.rx_frame_errors += ntohs(p->rx_hec_error);
-        p->rx_hec_error = 0;
-        p->rx_hec_error_for_host = 0;
+        local->stats.rx_frame_errors += ntohs(readb(&p->rx_hec_error));
+        writeb(0,&p->rx_hec_error);
+        writeb(0,&p->rx_hec_error_for_host);
     }
     return &local->stats;
 }
@@ -1414,11 +1434,11 @@
     struct ccs *pccs;
 
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(0,"ray_update_parm - device not present\n");
+        DEBUG(2,"ray_update_parm - device not present\n");
         return;
     }
 
-    if ((ccsindex = get_free_ccs(local)) == -1)
+    if ((ccsindex = get_free_ccs(local)) < 0)
     {
         DEBUG(0,"ray_update_parm - No free ccs\n");
         return;
@@ -1449,12 +1469,12 @@
     UCHAR *p = local->sram + HOST_TO_ECF_BASE;
 
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(1,"ray_update_multi_list - device not present\n");
+        DEBUG(2,"ray_update_multi_list - device not present\n");
         return;
     }
     else 
-        DEBUG(1,"ray_update_multi_list(%p)\n",dev);
-    if ((ccsindex = get_free_ccs(local)) == -1)
+        DEBUG(2,"ray_update_multi_list(%p)\n",dev);
+    if ((ccsindex = get_free_ccs(local)) < 0)
     {
         DEBUG(1,"ray_update_multi - No free ccs\n");
         return;
@@ -1491,7 +1511,7 @@
     ray_dev_t *local = (ray_dev_t *)dev->priv;
     UCHAR promisc;
 
-    DEBUG(1,"ray_cs set_multicast_list(%p)\n",dev);
+    DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev);
 
     if (dev->flags & IFF_PROMISC)
     {
@@ -1534,30 +1554,23 @@
     UCHAR cmd;
     UCHAR status;
 
-    if (dev == NULL) {
-        link = dev_list;
-        dev = (struct net_device *)link->priv;
-        DEBUG(4,"ray_cs interrupt dev  = %p, link = %p\n",dev,link);
-        if (dev->irq != irq)
-        {
-            DEBUG(0,"ray_cs interrupt irq %d for unknown device.\n", irq);
-            return;
-        }
-    }
+    if ((dev == NULL) || !dev->start)
+    return;
+
     DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev);
 
-    if (dev->interrupt) {
+    if (test_and_set_bit(0,&dev->interrupt)) {
         printk("ray_cs Reentering interrupt handler not allowed\n");
         return;
     }
-    dev->interrupt = 1;
+
     local = (ray_dev_t *)dev->priv;
     link = (dev_link_t *)local->finder;
     if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) {
-        DEBUG(1,"ray_cs interrupt from device not present or suspended.\n");
+        DEBUG(2,"ray_cs interrupt from device not present or suspended.\n");
         return;
     }
-    rcsindex = ((struct scb *)(local->sram))->rcs_index;
+    rcsindex = readb(&((struct scb *)(local->sram))->rcs_index);
 
     if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS))
     {
@@ -1602,7 +1615,7 @@
         case CCS_JOIN_NETWORK:
             if (status == CCS_COMMAND_COMPLETE) {
                 if (readb(&pccs->var.start_network.net_initiated) == 1) {
-                    DEBUG(0,"ray_cs interrupt network \"%s\"started\n",\
+                    DEBUG(0,"ray_cs interrupt network \"%s\" started\n",\
                           local->sparm.b4.a_current_ess_id);
                 }
                 else {
@@ -1741,16 +1754,16 @@
     switch(readb(pmsg))
     {
     case DATA_TYPE:
-	    DEBUG(4,"ray_rx data type\n");
+        DEBUG(4,"ray_rx data type\n");
         rx_data(dev, prcs, pkt_addr, rx_len);
         break;
     case AUTHENTIC_TYPE:
-	    DEBUG(4,"ray_rx authentic type\n");
+        DEBUG(4,"ray_rx authentic type\n");
         if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
         else rx_authenticate(local, prcs, pkt_addr, rx_len);
         break;
     case DEAUTHENTIC_TYPE:
-	    DEBUG(4,"ray_rx deauth type\n");
+        DEBUG(4,"ray_rx deauth type\n");
         if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
         else rx_deauthenticate(local, prcs, pkt_addr, rx_len);
         break;
@@ -1758,7 +1771,7 @@
         DEBUG(3,"ray_cs rx NULL msg\n");
         break;
     case BEACON_TYPE:
-	    DEBUG(4,"ray_rx beacon type\n");
+        DEBUG(4,"ray_rx beacon type\n");
         if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
 
         copy_from_rx_buff(local, (UCHAR *)&local->last_bcn, pkt_addr, 
@@ -1909,19 +1922,24 @@
     struct ethhdr *peth;
     UCHAR srcaddr[ADDRLEN];
     UCHAR destaddr[ADDRLEN];
-    int i;
 
-    if (local->sparm.b5.a_acting_as_ap_status != TYPE_STA)  
+    if (local->sparm.b5.a_acting_as_ap_status != TYPE_STA)
         memcpy(destaddr, pmac->addr_3, ADDRLEN);
     else
         memcpy(destaddr, pmac->addr_1, ADDRLEN);
     memcpy(srcaddr, pmac->addr_2, ADDRLEN);
 
-    DEBUG(3,"skb->data before untranslate");
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 3) {
+    int i;
+    printk(KERN_DEBUG "skb->data before untranslate");
     for (i=0;i<64;i++) 
-        DEBUG(3,"%02x ",skb->data[i]);
-    DEBUG(3,"\ntype = %08x, xsap = %08x, org = %08x\n",type,xsap,org);
-    DEBUG(3,"untranslate skb->data = %p\n",skb->data);
+        printk("%02x ",skb->data[i]);
+    printk("\n" KERN_DEBUG "type = %08x, xsap = %08x, org = %08x\n",
+           type,xsap,org);
+    printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data);
+    }
+#endif
 
     if ( xsap != SNAP_ID) {
         /* not a snap type so leave it alone */
@@ -1971,10 +1989,15 @@
     DEBUG(3,"untranslate after skb_pull(%d), skb->data = %p\n",delta,skb->data);
     memcpy(peth->h_dest, destaddr, ADDRLEN);
     memcpy(peth->h_source, srcaddr, ADDRLEN);
-    DEBUG(3,"skb->data after untranslate:");
-    for (i=0;i<64;i++) 
-        DEBUG(3,"%02x ",skb->data[i]);
-    DEBUG(3,"\n");
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 3) {
+    int i;
+    printk(KERN_DEBUG "skb->data after untranslate:");
+    for (i=0;i<64;i++)
+        printk("%02x ",skb->data[i]);
+    printk("\n");
+    }
+#endif
 } /* end untranslate */
 /*===========================================================================*/
 /* Copy data from circular receive buffer to PC memory.
@@ -2020,7 +2043,7 @@
     dev_link_t *link = local->finder;
     DEBUG(0,"ray_cs Starting authentication.\n");
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(1,"ray_cs authenticate - device not present\n");
+        DEBUG(2,"ray_cs authenticate - device not present\n");
         return;
     }
 
@@ -2046,37 +2069,37 @@
     del_timer(&local->timer);
 
     copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
-	/* if we are trying to get authenticated */
+    /* if we are trying to get authenticated */
     if (local->sparm.b4.a_network_type == ADHOC) {
-		DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]);
-		if (msg->var[2] == 1) {
+        DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]);
+        if (msg->var[2] == 1) {
                     DEBUG(0,"ray_cs Sending authentication response.\n");
                     if (!build_auth_frame (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) {
                         local->authentication_state = NEED_TO_AUTH;
                         memcpy(local->auth_id, msg->mac.addr_2, ADDRLEN);
                     }
-		}
-	}
-	else /* Infrastructure network */
-	{
-		if (local->authentication_state == AWAITING_RESPONSE) {
-			/* Verify authentication sequence #2 and success */
-			if (msg->var[2] == 2) {
-				if ((msg->var[3] | msg->var[4]) == 0) {
-					DEBUG(1,"Authentication successful\n");
-					local->card_status = CARD_AUTH_COMPLETE;
-					associate(local);
-					local->authentication_state = AUTHENTICATED;
-				}
-				else {
-					DEBUG(0,"Authentication refused\n");
-					local->card_status = CARD_AUTH_REFUSED;
-					join_net((u_long)local);
-					local->authentication_state = UNAUTHENTICATED;
-				}
-			}
-		}
-	}
+        }
+    }
+    else /* Infrastructure network */
+    {
+        if (local->authentication_state == AWAITING_RESPONSE) {
+            /* Verify authentication sequence #2 and success */
+            if (msg->var[2] == 2) {
+                if ((msg->var[3] | msg->var[4]) == 0) {
+                    DEBUG(1,"Authentication successful\n");
+                    local->card_status = CARD_AUTH_COMPLETE;
+                    associate(local);
+                    local->authentication_state = AUTHENTICATED;
+                }
+                else {
+                    DEBUG(0,"Authentication refused\n");
+                    local->card_status = CARD_AUTH_REFUSED;
+                    join_net((u_long)local);
+                    local->authentication_state = UNAUTHENTICATED;
+                }
+            }
+        }
+    }
 
 } /* end rx_authenticate */
 /*===========================================================================*/
@@ -2087,11 +2110,11 @@
     struct net_device *dev = link->priv;
     int ccsindex;
     if (!(link->state & DEV_PRESENT)) {
-        DEBUG(1,"ray_cs associate - device not present\n");
+        DEBUG(2,"ray_cs associate - device not present\n");
         return;
     }
     /* If no tx buffers available, return*/
-    if ((ccsindex = get_free_ccs(local)) == -1)
+    if ((ccsindex = get_free_ccs(local)) < 0)
     {
 /* TBD should never be here but... what if we are? */
         DEBUG(1,"ray_cs associate - No free ccs\n");
@@ -2125,7 +2148,7 @@
     struct rx_msg *msg = (struct rx_msg *)buff;
 */
     DEBUG(0,"Deauthentication frame received\n");
-	local->authentication_state = UNAUTHENTICATED;
+    local->authentication_state = UNAUTHENTICATED;
     /* Need to reauthenticate or rejoin depending on reason code */
 /*  copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
  */
@@ -2256,9 +2279,8 @@
     int ccsindex;
 
     /* If no tx buffers available, return */
-    if ((ccsindex = get_free_tx_ccs(local)) == -1)
+    if ((ccsindex = get_free_tx_ccs(local)) < 0)
     {
-/* TBD should never be here but... what if we are? */
         DEBUG(1,"ray_cs send authenticate - No free tx ccs\n");
         return -1;
     }
diff -u --recursive --new-file v2.3.19/linux/drivers/net/pcmcia/ray_cs.h linux/drivers/net/pcmcia/ray_cs.h
--- v2.3.19/linux/drivers/net/pcmcia/ray_cs.h	Fri Sep 10 23:57:30 1999
+++ linux/drivers/net/pcmcia/ray_cs.h	Thu Oct  7 11:50:26 1999
@@ -17,9 +17,14 @@
                   + sizeof(struct tim_element)];
 };
 
+/* Return values for get_free{,_tx}_ccs */
+#define ECCSFULL  (-1)
+#define ECCSBUSY  (-2)
+#define ECARDGONE (-3)
+
 typedef struct ray_dev_t {
     int card_status;
-	int authentication_state;
+    int authentication_state;
     dev_node_t  node;
     window_handle_t amem_handle;   /* handle to window for attribute memory  */
     window_handle_t rmem_handle;   /* handle to window for rx buffer on card */
@@ -28,6 +33,8 @@
     UCHAR *rmem;                   /* pointer to receive buffer window       */
     dev_link_t *finder;            /* pointer back to dev_link_t for card    */
     struct timer_list timer;
+    int tx_ccs_lock;
+    int ccs_lock;
     int   dl_param_ccs;
     union {
         struct b4_startup_params b4;
diff -u --recursive --new-file v2.3.19/linux/drivers/net/pcmcia/rayctl.h linux/drivers/net/pcmcia/rayctl.h
--- v2.3.19/linux/drivers/net/pcmcia/rayctl.h	Fri Sep 10 23:57:30 1999
+++ linux/drivers/net/pcmcia/rayctl.h	Thu Oct  7 11:50:26 1999
@@ -142,8 +142,6 @@
 };
 /*****************************************************************************/
 /*****************************************************************************/
-
-
 /* #define C_MAC_HDR_2_WEP 0x40 */
 /* TX/RX CCS constants */
 #define TX_HEADER_LENGTH 0x1C
@@ -151,6 +149,9 @@
 #define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6)
 #define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
 #define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
+#define TX_DEAUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 2)
+#define TX_DEAUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
+#define TX_DEAUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
 #define FCS_LEN           4
 
 #define ADHOC                 0
@@ -324,17 +325,23 @@
 #define CARD_ASSOC_COMPLETE (6)
 #define CARD_ASSOC_FAILED   (16)
 
-/*** Values for authentication_state */
+/*** Values for authentication_state ***********************************/
 #define UNAUTHENTICATED     (0)
 #define AWAITING_RESPONSE   (1)
 #define AUTHENTICATED       (2)
 #define NEED_TO_AUTH        (3)
 
-/*** Values for authentication type */
+/*** Values for authentication type ************************************/
 #define OPEN_AUTH_REQUEST   (1)
 #define OPEN_AUTH_RESPONSE  (2)
-
-
+#define BROADCAST_DEAUTH    (0xc0)
+/*** Values for timer functions ****************************************/
+#define TODO_NOTHING              (0)
+#define TODO_VERIFY_DL_START      (-1)
+#define TODO_START_NET            (-2)
+#define TODO_JOIN_NET             (-3)
+#define TODO_AUTHENTICATE_TIMEOUT (-4)
+#define TODO_SEND_CCS             (-5)
 /***********************************************************************/
 /* Parameter passing structure for update/report parameter CCS's */
 struct object_id {
diff -u --recursive --new-file v2.3.19/linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c
--- v2.3.19/linux/drivers/parport/ieee1284.c	Fri Aug  6 15:25:47 1999
+++ linux/drivers/parport/ieee1284.c	Fri Oct  8 15:46:35 1999
@@ -151,8 +151,6 @@
 {
 	port = port->physport;
 
-	port->ieee1284.phase = IEEE1284_PH_TERMINATE;
-
 	/* EPP terminates differently. */
 	switch (port->ieee1284.mode) {
 	case IEEE1284_MODE_EPP:
@@ -161,17 +159,42 @@
 		/* Terminate from EPP mode. */
 
 		/* Event 68: Set nInit low */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_INIT,
-				      PARPORT_CONTROL_INIT);
+		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
 		udelay (50);
 
 		/* Event 69: Set nInit high, nSelectIn low */
 		parport_frob_control (port,
-				      PARPORT_CONTROL_SELECT,
-				      PARPORT_CONTROL_SELECT);
+				      PARPORT_CONTROL_SELECT
+				      | PARPORT_CONTROL_INIT,
+				      PARPORT_CONTROL_SELECT
+				      | PARPORT_CONTROL_INIT);
 		break;
-		
+
+	case IEEE1284_MODE_ECP:
+	case IEEE1284_MODE_ECPRLE:
+	case IEEE1284_MODE_ECPSWE:
+		/* In ECP we can only terminate from fwd idle phase. */
+		if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
+			/* Event 47: Set nInit high */
+			parport_frob_control (port,
+					      PARPORT_CONTROL_INIT
+					      | PARPORT_CONTROL_AUTOFD,
+					      PARPORT_CONTROL_INIT
+					      | PARPORT_CONTROL_AUTOFD);
+
+			/* Event 49: PError goes high */
+			parport_wait_peripheral (port,
+						 PARPORT_STATUS_PAPEROUT,
+						 PARPORT_STATUS_PAPEROUT);
+
+			parport_data_forward (port);
+			DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+				 port->name);
+			port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+		}
+
+		/* fall-though.. */
+
 	default:
 		/* Terminate from all other modes. */
 
diff -u --recursive --new-file v2.3.19/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- v2.3.19/linux/drivers/parport/ieee1284_ops.c	Thu Aug 12 11:53:18 1999
+++ linux/drivers/parport/ieee1284_ops.c	Thu Oct  7 10:17:09 1999
@@ -9,8 +9,10 @@
  * Note: Make no assumptions about hardware or architecture in this file!
  *
  * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Fixed AUTOFD polarity in ecp_forward_to_reverse().  Fred Barnes, 1999
  */
 
+
 #include <linux/config.h>
 #include <linux/parport.h>
 #include <linux/delay.h>
@@ -336,7 +338,7 @@
 	/* Event 38: Set nAutoFd low */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_AUTOFD,
-			      0);
+			      PARPORT_CONTROL_AUTOFD);
 	parport_data_reverse (port);
 	udelay (5);
 
@@ -524,12 +526,12 @@
 			if (count && dev->port->irq != PARPORT_IRQ_NONE) {
 				parport_release (dev);
 				current->state = TASK_INTERRUPTIBLE;
-				schedule_timeout ((HZ + 99) / 25);
+				schedule_timeout ((HZ + 24) / 25);
 				parport_claim_or_block (dev);
 			}
 			else
 				/* We must have the device claimed here. */
-				parport_wait_event (port, (HZ + 99) / 25);
+				parport_wait_event (port, (HZ + 24) / 25);
 
 			/* Is there a signal pending? */
 			if (signal_pending (current))
@@ -610,10 +612,11 @@
 			count += rle_count;
 			DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n",
 				 port->name, rle_count);
-		}
-		else
+		} else {
 			/* Normal data byte. */
-			*buf++ = byte, count++;
+			*buf = byte;
+			buf++, count++;
+		}
 	}
 
  out:
diff -u --recursive --new-file v2.3.19/linux/drivers/parport/init.c linux/drivers/parport/init.c
--- v2.3.19/linux/drivers/parport/init.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/parport/init.c	Thu Oct  7 14:10:06 1999
@@ -91,6 +91,8 @@
 	if (sep++) {
 		if (!strncmp (sep, "auto", 4))
 			dma[parport_setup_ptr] = PARPORT_DMA_AUTO;
+		else if (!strncmp (sep, "nofifo", 6))
+			dma[parport_setup_ptr] = PARPORT_DMA_NOFIFO;
 		else if (strncmp (sep, "none", 4)) {
 			val = simple_strtoul (sep, &endptr, 0);
 			if (endptr == sep) {
@@ -209,6 +211,8 @@
 EXPORT_SYMBOL(parport_daisy_deselect_all);
 EXPORT_SYMBOL(parport_daisy_select);
 EXPORT_SYMBOL(parport_daisy_init);
+EXPORT_SYMBOL(parport_find_device);
+EXPORT_SYMBOL(parport_find_class);
 #endif
 
 void inc_parport_count(void)
diff -u --recursive --new-file v2.3.19/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.3.19/linux/drivers/parport/parport_pc.c	Thu Aug 12 11:53:22 1999
+++ linux/drivers/parport/parport_pc.c	Fri Oct  8 10:06:21 1999
@@ -10,6 +10,7 @@
  *
  * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
  * DMA support - Bert De Jonghe <bert@sophis.be>
+ * Many ECP bugs fixed.  Fred Barnes & Jamie Lokier, 1999
  */
 
 /* This driver should work with any hardware that is broadly compatible
@@ -73,7 +74,12 @@
 static void frob_econtrol (struct parport *pb, unsigned char m,
 			   unsigned char v)
 {
-	outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
+	unsigned char ectr = inb (ECONTROL (pb));
+#ifdef DEBUG_PARPORT
+	printk (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
+		m, v, ectr, (ectr & ~m) ^ v);
+#endif
+	outb ((ectr & ~m) ^ v, ECONTROL (pb));
 }
 
 #ifdef CONFIG_PARPORT_PC_FIFO
@@ -94,11 +100,8 @@
 	oecr = inb (ecr);
 	mode = (oecr >> 5) & 0x7;
 	if (mode == m) return 0;
-	if (mode && m)
-		/* We have to go through mode 000 */
-		change_mode (p, ECR_SPP);
 
-	if (m < 2 && !(parport_read_control (p) & 0x20)) {
+	if (mode >= 2 && !(priv->ctr & 0x20)) {
 		/* This mode resets the FIFO, so we may
 		 * have to wait for it to drain first. */
 		long expire = jiffies + p->physport->cad->timeout;
@@ -127,6 +130,13 @@
 		}
 	}
 
+	if (mode >= 2 && m >= 2) {
+		/* We have to go through mode 001 */
+		oecr &= ~(7 << 5);
+		oecr |= ECR_PS2 << 5;
+		outb (oecr, ecr);
+	}
+
 	/* Set the mode. */
 	oecr &= ~(7 << 5);
 	oecr |= m << 5;
@@ -160,11 +170,11 @@
 		residue);
 
 	/* Reset the FIFO. */
-	frob_econtrol (p, 0xe0, 0x20);
+	frob_econtrol (p, 0xe0, ECR_PS2 << 5);
 	parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
 
 	/* Now change to config mode and clean up. FIXME */
-	frob_econtrol (p, 0xe0, 0xe0);
+	frob_econtrol (p, 0xe0, ECR_CNF << 5);
 	cnfga = inb (CONFIGA (p));
 	printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
 
@@ -177,7 +187,7 @@
 	 * PWord != 1 byte. */
 
 	/* Back to PS2 mode. */
-	frob_econtrol (p, 0xe0, 0x20);
+	frob_econtrol (p, 0xe0, ECR_PS2 << 5);
 
 	return residue;
 }
@@ -209,9 +219,9 @@
 /*
  * Access functions.
  *
- * These aren't static because they may be used by the parport_xxx_yyy
- * macros.  extern __inline__ versions of several of these are in
- * parport_pc.h.
+ * Most of these aren't static because they may be used by the
+ * parport_xxx_yyy macros.  extern __inline__ versions of several
+ * of these are in parport_pc.h.
  */
 
 static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -229,21 +239,6 @@
 	return inb (DATA (p));
 }
 
-unsigned char __frob_control (struct parport *p, unsigned char mask,
-			      unsigned char val)
-{
-	const unsigned char wm = (PARPORT_CONTROL_STROBE |
-				  PARPORT_CONTROL_AUTOFD |
-				  PARPORT_CONTROL_INIT |
-				  PARPORT_CONTROL_SELECT);
-	struct parport_pc_private *priv = p->physport->private_data;
-	unsigned char ctr = priv->ctr;
-	ctr = (ctr & ~mask) ^ val;
-	ctr &= priv->ctr_writable; /* only write writable bits. */
-	outb (ctr, CONTROL (p));
-	return priv->ctr = ctr & wm; /* update soft copy */
-}
-
 void parport_pc_write_control(struct parport *p, unsigned char d)
 {
 	const unsigned char wm = (PARPORT_CONTROL_STROBE |
@@ -253,18 +248,22 @@
 
 	/* Take this out when drivers have adapted to the newer interface. */
 	if (d & 0x20) {
-			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
-					p->name, p->cad->name);
-			parport_pc_data_reverse (p);
+		printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+			p->name, p->cad->name);
+		parport_pc_data_reverse (p);
 	}
 
-	__frob_control (p, wm, d & wm);
+	__parport_pc_frob_control (p, wm, d & wm);
 }
 
 unsigned char parport_pc_read_control(struct parport *p)
 {
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
 	const struct parport_pc_private *priv = p->physport->private_data;
-	return priv->ctr; /* Use soft copy */
+	return priv->ctr & wm; /* Use soft copy */
 }
 
 unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
@@ -277,16 +276,20 @@
 
 	/* Take this out when drivers have adapted to the newer interface. */
 	if (mask & 0x20) {
-			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
-					p->name, p->cad->name);
+		printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
+			p->name, p->cad->name,
+			(val & 0x20) ? "reverse" : "forward");
+		if (val & 0x20)
 			parport_pc_data_reverse (p);
+		else
+			parport_pc_data_forward (p);
 	}
 
 	/* Restrict mask and val to control lines. */
 	mask &= wm;
 	val &= wm;
 
-	return __frob_control (p, mask, val);
+	return __parport_pc_frob_control (p, mask, val);
 }
 
 unsigned char parport_pc_read_status(struct parport *p)
@@ -296,22 +299,22 @@
 
 void parport_pc_disable_irq(struct parport *p)
 {
-	__frob_control (p, 0x10, 0);
+	__parport_pc_frob_control (p, 0x10, 0);
 }
 
 void parport_pc_enable_irq(struct parport *p)
 {
-	__frob_control (p, 0x10, 0x10);
+	__parport_pc_frob_control (p, 0x10, 0x10);
 }
 
 void parport_pc_data_forward (struct parport *p)
 {
-	__frob_control (p, 0x20, 0);
+	__parport_pc_frob_control (p, 0x20, 0);
 }
 
 void parport_pc_data_reverse (struct parport *p)
 {
-	__frob_control (p, 0x20, 0x20);
+	__parport_pc_frob_control (p, 0x20, 0x20);
 }
 
 void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
@@ -469,7 +472,7 @@
 	frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
 
 	/* Forward mode. */
-	parport_pc_data_forward (port);
+	parport_pc_data_forward (port); /* Must be in PS2 mode */
 
 	while (left) {
 		unsigned char byte;
@@ -559,7 +562,7 @@
 	frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
 
 	/* Forward mode. */
-	parport_pc_data_forward (port);
+	parport_pc_data_forward (port); /* Must be in PS2 mode */
 
 	while (left) {
 		long expire = jiffies + port->physport->cad->timeout;
@@ -656,8 +659,8 @@
 						      length, flags);
 
 	/* Set up parallel port FIFO mode.*/
+	parport_pc_data_forward (port); /* Must be in PS2 mode */
 	change_mode (port, ECR_PPF); /* Parallel port FIFO */
-	parport_pc_data_forward (port);
 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 
 	/* Write the data to the FIFO. */
@@ -687,8 +690,8 @@
 			outb (0, FIFO (port));
 		}
 
-		/* Reset the FIFO. */
-		frob_econtrol (port, 0xe0, 0);
+		/* Reset the FIFO and return to PS2 mode. */
+		frob_econtrol (port, 0xe0, ECR_PS2 << 5);
 
 		/* De-assert strobe. */
 		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
@@ -727,8 +730,8 @@
 	}
 
 	/* Set up ECP parallel port mode.*/
+	parport_pc_data_forward (port); /* Must be in PS2 mode */
 	change_mode (port, ECR_ECP); /* ECP FIFO */
-	parport_pc_data_forward (port);
 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 
 	/* Write the data to the FIFO. */
@@ -758,17 +761,20 @@
 			outb (0, FIFO (port));
 		}
 
-		/* Reset the FIFO. */
-		frob_econtrol (port, 0xe0, 0);
+		/* Reset the FIFO and return to PS2 mode. */
+		frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+		/* De-assert strobe. */
 		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
 
 		/* Host transfer recovery. */
+		parport_pc_data_reverse (port); /* Must be in PS2 mode */
+		udelay (5);
+		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+		parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
 		parport_frob_control (port,
 				      PARPORT_CONTROL_INIT,
 				      PARPORT_CONTROL_INIT);
-		parport_pc_data_reverse (port);
-		parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
-		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
 		parport_wait_peripheral (port,
 					 PARPORT_STATUS_PAPEROUT,
 					 PARPORT_STATUS_PAPEROUT);
@@ -819,21 +825,21 @@
 		parport_frob_control (port,
 				      PARPORT_CONTROL_AUTOFD,
 				      PARPORT_CONTROL_AUTOFD);
-		parport_pc_data_reverse (port);
+		parport_pc_data_reverse (port); /* Must be in PS2 mode */
 		udelay (5);
 
 		/* Event 39: Set nInit low to initiate bus reversal */
 		parport_frob_control (port,
 				      PARPORT_CONTROL_INIT,
-				      PARPORT_CONTROL_INIT);
+				      0);
 
 		/* Event 40: PError goes low */
 		parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
 	}
 
 	/* Set up ECP parallel port mode.*/
+	parport_pc_data_reverse (port); /* Must be in PS2 mode */
 	change_mode (port, ECR_ECP); /* ECP FIFO */
-	parport_pc_data_reverse (port);
 	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
 
 	/* Do the transfer. */
@@ -1054,7 +1060,6 @@
 	struct parport_pc_private *priv = pb->private_data;
 	unsigned char r = 0xc;
 
-	priv->ecr = 0;
 	outb (r, CONTROL (pb));
 	if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
 		outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
@@ -1120,9 +1125,9 @@
 	/* cancel input mode */
 	parport_pc_data_forward (pb);
 
-	if (ok)
+	if (ok) {
 		pb->modes |= PARPORT_MODE_TRISTATE;
-	else {
+	} else {
 		struct parport_pc_private *priv = pb->private_data;
 		priv->ctr_writable &= ~0x20;
 	}
@@ -1180,8 +1185,8 @@
 	priv->writeIntrThreshold = i;
 
 	/* Find out readIntrThreshold */
-	frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */
-	parport_pc_data_reverse (pb);
+	frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO and enable PS2 */
+	parport_pc_data_reverse (pb); /* Must be in PS2 mode */
 	frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
 	frob_econtrol (pb, 1<<2, 1<<2);
 	frob_econtrol (pb, 1<<2, 0);
@@ -1544,12 +1549,10 @@
 	if (base_hi && !check_region(base_hi,3)) {
 		parport_ECR_present(p);
 		parport_ECP_supported(p);
-		parport_ECPPS2_supported(p);
 	}
 	if (base != 0x3bc) {
 		if (!check_region(base+0x3, 5)) {
-			parport_EPP_supported(p);
-			if (!(p->modes & PARPORT_MODE_EPP))
+			if (!parport_EPP_supported(p))
 				parport_ECPEPP_supported(p);
 		}
 	}
@@ -1558,8 +1561,10 @@
 		kfree (priv);
 		return NULL;
 	}
-
-	parport_PS2_supported (p);
+	if (priv->ecr)
+		parport_ECPPS2_supported(p);
+	else
+		parport_PS2_supported (p);
 
 	if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
 					PARPORT_DMA_NONE, ops))) {
@@ -1599,7 +1604,8 @@
 		p->dma = PARPORT_DMA_NONE;
 
 #ifdef CONFIG_PARPORT_PC_FIFO
-	if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
+	if (p->dma != PARPORT_DMA_NOFIFO &&
+	    priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
 		p->ops->compat_write_data = parport_pc_compat_write_block_pio;
 #ifdef CONFIG_PARPORT_1284
 		p->ops->ecp_write_data = parport_pc_ecp_write_block_pio;
@@ -1672,9 +1678,10 @@
 	/* Done probing.  Now put the port into a sensible start-up state.
 	 * SELECT | INIT also puts IEEE1284-compliant devices into
 	 * compatibility mode. */
-	if (p->modes & PARPORT_MODE_ECP)
+	if (priv->ecr)
 		/*
 		 * Put the ECP detected port in PS2 mode.
+		 * Do this also for ports that have ECR but don't do ECP.
 		 */
 		outb (0x34, ECONTROL (p));
 
@@ -1751,6 +1758,8 @@
 		  { { 0, -1 }, } },
 		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1,
 		  { { 0, -1 }, } },
+		{ PCI_VENDOR_ID_EXSYS, PCI_DEVICE_ID_EXSYS_4014, 2,
+		  { { 2, -1 }, { 3, -1 }, } },
 		{ 0, }
 	};
 
diff -u --recursive --new-file v2.3.19/linux/drivers/parport/share.c linux/drivers/parport/share.c
--- v2.3.19/linux/drivers/parport/share.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/parport/share.c	Thu Oct  7 14:10:06 1999
@@ -633,7 +633,7 @@
 }
 
 static int parport_parse_params (int nports, const char *str[], int val[],
-				 int automatic, int none)
+				 int automatic, int none, int nofifo)
 {
 	unsigned int i;
 	for (i = 0; i < nports && str[i]; i++) {
@@ -641,6 +641,8 @@
 			val[i] = automatic;
 		else if (!strncmp(str[i], "none", 4))
 			val[i] = none;
+		else if (nofifo && !strncmp(str[i], "nofifo", 4))
+			val[i] = nofifo;
 		else {
 			char *ep;
 			unsigned long r = simple_strtoul(str[i], &ep, 0);
@@ -659,11 +661,11 @@
 int parport_parse_irqs(int nports, const char *irqstr[], int irqval[])
 {
 	return parport_parse_params (nports, irqstr, irqval, PARPORT_IRQ_AUTO,
-				     PARPORT_IRQ_NONE);
+				     PARPORT_IRQ_NONE, 0);
 }
 
 int parport_parse_dmas(int nports, const char *dmastr[], int dmaval[])
 {
 	return parport_parse_params (nports, dmastr, dmaval, PARPORT_DMA_AUTO,
-				     PARPORT_DMA_NONE);
+				     PARPORT_DMA_NONE, PARPORT_DMA_NOFIFO);
 }
diff -u --recursive --new-file v2.3.19/linux/drivers/pci/Makefile linux/drivers/pci/Makefile
--- v2.3.19/linux/drivers/pci/Makefile	Tue Sep  7 12:14:06 1999
+++ linux/drivers/pci/Makefile	Thu Oct  7 18:07:25 1999
@@ -25,6 +25,10 @@
 L_OBJS   += proc.o
 endif
 
-L_OBJS   += compat.o quirks.o names.o syscall.o setup.o
+L_OBJS   += compat.o quirks.o names.o helper.o
+
+ifndef CONFIG_X86
+L_OBJS   += syscall.o setup.o
+endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.19/linux/drivers/pci/devlist.h linux/drivers/pci/devlist.h
--- v2.3.19/linux/drivers/pci/devlist.h	Fri Sep 10 23:57:30 1999
+++ linux/drivers/pci/devlist.h	Fri Oct  8 10:06:21 1999
@@ -989,6 +989,10 @@
 	DEVICE( ATRONICS,	ATRONICS_2015,	"IDE-2015PL")
 ENDVENDOR()
 
+VENDOR( EXSYS, "Exsys" )
+	DEVICE( EXSYS,		EXSYS_4014,	"EX-4014")
+ENDVENDOR()
+
 VENDOR( TIGERJET, "TigerJet" )
 	DEVICE( TIGERJET,	TIGERJET_300,	"Tiger300 ISDN")
 ENDVENDOR()
diff -u --recursive --new-file v2.3.19/linux/drivers/pci/helper.c linux/drivers/pci/helper.c
--- v2.3.19/linux/drivers/pci/helper.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pci/helper.c	Thu Oct  7 18:07:25 1999
@@ -0,0 +1,69 @@
+/*
+ * $Id$
+ *
+ * drivers/pci/helper.c
+ *
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * This software is free.  See the file COPYING for licensing details.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+
+int pci_simple_probe (struct pci_simple_probe_entry *list, size_t match_limit,
+		      pci_simple_probe_callback cb, void *drvr_data)
+{
+	struct pci_dev *dev;
+	struct pci_simple_probe_entry *ent;
+	size_t matches = 0;
+	unsigned short vendor, device;
+	int rc;
+
+	if (!list || !cb)
+		return -1;
+
+	dev = pci_find_device (PCI_ANY_ID, PCI_ANY_ID, NULL);
+	while (dev) {
+		ent = list;
+		while (ent->vendor && ent->device) {
+			vendor = ent->vendor;
+			device = ent->device;
+
+			if (((vendor != 0xFFFF) &&
+			     (vendor != dev->vendor)) ||
+			    ((device != 0xFFFF) &&
+			     (device != dev->device))) {
+			     	ent++;
+				continue;
+			}
+			    
+			if (((ent->subsys_vendor) &&
+			     (ent->subsys_vendor != dev->subsystem_vendor)) ||
+			    ((ent->subsys_device) &&
+			     (ent->subsys_device != dev->subsystem_device))) {
+			     	ent++;
+				continue;
+			}
+			    
+			rc = (* cb) (dev, matches, ent, drvr_data);
+			if (rc < 0)
+				return rc;
+
+			matches++;
+
+			if (match_limit && match_limit == matches)
+				return matches;
+
+			ent++;
+		}
+
+		dev = pci_find_device (PCI_ANY_ID, PCI_ANY_ID, dev);
+	}
+
+	return matches;
+}
+
+
diff -u --recursive --new-file v2.3.19/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.3.19/linux/drivers/pci/pci.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/pci/pci.c	Thu Oct  7 12:23:21 1999
@@ -17,7 +17,6 @@
 #include <linux/malloc.h>
 #include <linux/ioport.h>
 
-#include <asm/pci.h>
 #include <asm/page.h>
 
 #undef DEBUG
@@ -125,26 +124,20 @@
 	int i;
 	struct resource *best = NULL;
 
-	while (bus) {
-		for(i=0; i<4; i++) {
-			struct resource *r = bus->resource[i];
-			if (!r)
-				continue;
-			if (res->start && !(res->start >= r->start && res->end <= r->end))
-				continue;	/* Not contained */
-			if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
-				continue;	/* Wrong type */
-			if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
-				return r;	/* Exact match */
-			if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))
-				best = r;	/* Approximating prefetchable by non-prefetchable */
-		}
-		if (best)
-			return best;
-		bus = bus->parent;
+	for(i=0; i<4; i++) {
+		struct resource *r = bus->resource[i];
+		if (!r)
+			continue;
+		if (res->start && !(res->start >= r->start && res->end <= r->end))
+			continue;	/* Not contained */
+		if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
+			continue;	/* Wrong type */
+		if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
+			return r;	/* Exact match */
+		if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))
+			best = r;	/* Approximating prefetchable by non-prefetchable */
 	}
-	printk(KERN_ERR "PCI: Bug: Parent resource not found!\n");
-	return NULL;
+	return best;
 }
 
 
@@ -193,47 +186,18 @@
 
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	if (! (cmd & PCI_COMMAND_MASTER)) {
-		printk("PCI: Enabling bus mastering for device %s\n", dev->name);
+		printk("PCI: Enabling bus mastering for device %s\n", dev->slot_name);
 		cmd |= PCI_COMMAND_MASTER;
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
 	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
 	if (lat < 16) {
-		printk("PCI: Increasing latency timer of device %s to 64\n", dev->name);
+		printk("PCI: Increasing latency timer of device %s to 64\n", dev->slot_name);
 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
 	}
 }
 
 /*
- * Assign new address to PCI resource.  We hope our resource information
- * is complete.  On the PC, we don't re-assign resources unless we are
- * forced to do so or the driver asks us to.
- *
- * Expects start=0, end=size-1, flags=resource type.
- */
-int __init pci_assign_resource(struct pci_dev *dev, int i)
-{
-	struct resource *r = &dev->resource[i];
-	struct resource *pr = pci_find_parent_resource(dev, r);
-	unsigned long size = r->end + 1;
-
-	if (!pr)
-		return -EINVAL;
-	if (r->flags & IORESOURCE_IO) {
-		if (size > 0x100)
-			return -EFBIG;
-		if (allocate_resource(pr, r, size, 0x1000, ~0, 1024))
-			return -EBUSY;
-	} else {
-		if (allocate_resource(pr, r, size, 0x10000000, ~0, size))
-			return -EBUSY;
-	}
-	if (i < 6)
-		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start);
-	return 0;
-}
-
-/*
  * Translate the low bits of the PCI base
  * to the resource type
  */
@@ -296,7 +260,7 @@
 				res->end = res->start + (((unsigned long) ~l) << 32);
 #else
 			if (l) {
-				printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->name);
+				printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
 				res->start = 0;
 				res->flags = 0;
 				continue;
@@ -305,6 +269,7 @@
 		}
 	}
 	if (rom) {
+		dev->rom_base_reg = rom;
 		res = &dev->resource[PCI_ROM_RESOURCE];
 		pci_read_config_dword(dev, rom, &l);
 		pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
@@ -324,8 +289,9 @@
 	pci_write_config_word(dev, PCI_COMMAND, cmd);
 }
 
-void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child)
+void __init pci_read_bridge_bases(struct pci_bus *child)
 {
+	struct pci_dev *dev = child->self;
 	u8 io_base_lo, io_limit_lo;
 	u16 mem_base_lo, mem_limit_lo, io_base_hi, io_limit_hi;
 	u32 mem_base_hi, mem_limit_hi;
@@ -333,6 +299,9 @@
 	struct resource *res;
 	int i;
 
+	if (!dev)		/* It's a host bus, nothing to read */
+		return;
+
 	for(i=0; i<3; i++)
 		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
 
@@ -425,31 +394,27 @@
 		dev_cache = NULL;
 		dev->vendor = l & 0xffff;
 		dev->device = (l >> 16) & 0xffff;
-		sprintf(dev->name, "%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
+		sprintf(dev->slot_name, "%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
 		pci_name_device(dev);
 
 		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
 		class >>= 8;				    /* upper 3 bytes */
 		dev->class = class;
 		class >>= 8;
-		dev->hdr_type = hdr_type;
+		dev->hdr_type = hdr_type & 0x7f;
 
-		switch (hdr_type & 0x7f) {		    /* header type */
+		switch (dev->hdr_type) {		    /* header type */
 		case PCI_HEADER_TYPE_NORMAL:		    /* standard header */
 			if (class == PCI_CLASS_BRIDGE_PCI)
 				goto bad;
 			/*
-			 * If the card generates interrupts, read IRQ number
-			 * (some architectures change it during pcibios_fixup())
+			 * Read interrupt line and base address registers.
+			 * The architecture-dependent code can tweak these, of course.
 			 */
 			pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
 			if (irq)
 				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
 			dev->irq = irq;
-			/*
-			 * read base address registers, again pcibios_fixup() can
-			 * tweak these
-			 */
 			pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
 			pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
 			pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
@@ -468,8 +433,8 @@
 			break;
 		default:				    /* unknown header */
 		bad:
-			printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
-			       bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);
+			printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
+				dev->slot_name, hdr_type);
 			continue;
 		}
 
diff -u --recursive --new-file v2.3.19/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c
--- v2.3.19/linux/drivers/pci/quirks.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/pci/quirks.c	Thu Oct  7 12:23:21 1999
@@ -31,7 +31,7 @@
 	while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
 		pci_read_config_byte(d, 0x82, &dlc);
 		if (!(dlc & 1<<1)) {
-			printk("PCI: PIIX3: Enabling Passive Release on %s\n", d->name);
+			printk("PCI: PIIX3: Enabling Passive Release on %s\n", d->slot_name);
 			dlc |= 1<<1;
 			pci_write_config_byte(d, 0x82, dlc);
 		}
@@ -99,7 +99,7 @@
  		    (f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
  		    (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
 #ifdef DEBUG
-			printk("PCI: Calling quirk %p for %s\n", f->hook, dev->name);
+			printk("PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name);
 #endif
 			f->hook(dev);
 		}
diff -u --recursive --new-file v2.3.19/linux/drivers/pci/setup.c linux/drivers/pci/setup.c
--- v2.3.19/linux/drivers/pci/setup.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/pci/setup.c	Thu Oct  7 12:23:21 1999
@@ -16,7 +16,6 @@
 #include <linux/ioport.h>
 
 #include <asm/cache.h>
-#include <asm/pci.h>
 
 
 #define DEBUG_CONFIG 0
@@ -108,9 +107,12 @@
 	   (ie. do not respond to memory space writes) when it is left
 	   enabled.  A good example are QlogicISP adapters.  */
 
-	pci_read_config_dword(dev, PCI_ROM_ADDRESS, &reg);
-	reg &= ~PCI_ROM_ADDRESS_ENABLE;
-	pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg);
+	if (dev->rom_base_reg) {
+		pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+		reg &= ~PCI_ROM_ADDRESS_ENABLE;
+		pci_write_config_dword(dev, dev->rom_base_reg, reg);
+		dev->resource[PCI_ROM_RESOURCE].flags &= ~PCI_ROM_ADDRESS_ENABLE;
+	}
 
 	/* All of these (may) have I/O scattered all around and may not
 	   use I/O base address registers at all.  So we just have to
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.3.19/linux/drivers/scsi/ChangeLog.ncr53c8xx	Mon Apr 12 09:51:04 1999
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Thu Oct  7 10:17:09 1999
@@ -1,3 +1,33 @@
+Sat Sep 11  18:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2c
+	- Handle correctly (hopefully) jiffies wrap-around.
+	- Restore the entry used to detect 875 until revision 0xff.
+	  (I removed it inadvertently, it seems :) )
+	- Replace __initfunc() which is deprecated stuff by __init which 
+	  is not yet so. ;-)
+	- Add support of some 'resource handling' for linux-2.3.13.
+	  Basically the BARs have been changed to something more complex 
+	  in the pci_dev structure.
+	- Remove some deprecated code.
+
+Sat May 10  11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* revision pre-3.2b-1
+	- Support for the 53C895A by Pamela Delaney <pam.delaney@lsil.com>
+	  The 53C895A contains all of the features of the 896 but has only 
+	  one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing 
+	  using dual cycle PCI data transfers.
+	- Miscellaneous minor fixes.
+	- Some additions to the README.ncr53c8xx file.
+
+Sun Apr 11  10:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2a
+	- Add 'hostid:#id' boot option. This option allows to change the 
+	  default SCSI id the driver uses for controllers.
+	- Remove nvram layouts and driver set-up structures from the C source,
+	  and use the one defined in sym53c8xx_defs.h file.
+	  (shared by both drivers).
+	- Set for now MAX LUNS to 16 (instead of 8).
+
 Thu Mar 11  23:00 1999 Gerard Roudier (groudier@club-internet.fr)
 	* revision 3.2	  (8xx-896 driver bundle)
 	- Only define the host template in ncr53c8xx.h and include the 
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx
--- v2.3.19/linux/drivers/scsi/ChangeLog.sym53c8xx	Mon Apr 12 09:51:04 1999
+++ linux/drivers/scsi/ChangeLog.sym53c8xx	Thu Oct  7 10:17:09 1999
@@ -1,3 +1,132 @@
+Sat Sep 11  11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5e
+	- New linux-2.3.13 __setup scheme support added.
+	- Cleanup of the extended error status handling:
+	  Use 1 bit per error type.
+	- Also save the extended error status prior to auto-sense.
+	- Add the FE_DIFF chip feature bit to indicate support of 
+	  diff probing from GPIO3 (825/825A/876/875).
+	- Remove the quirk handling that has been useless since day one.
+	- Work-around PCI chips being reported twice on some platforms.
+	- Add some redundant PCI reads in order to deal with common 
+	  bridge misbehaviour regarding posted write flushing.
+	- Add some other conditionnal code for people who have to deal 
+	  with really broken bridges (they will have to edit a source 
+	  file to try these options).
+	- Handle correctly (hopefully) jiffies wrap-around.
+	- Restore the entry used to detect 875 until revision 0xff.
+	  (I removed it inadvertently, it seems :) )
+	- Replace __initfunc() which is deprecated stuff by __init which 
+	  is not yet so. ;-)
+	- Rewrite the MESSAGE IN scripts more generic by using a MOVE 
+	  table indirect. Extended messages of any size are accepted now.
+	  (Size is limited to 8 for now, but a constant is just to be 
+	  increased if necessary)
+	- Fix some bug in the fully untested MDP handling:) and share 
+	  some code between MDP handling and residual calculation.
+	- Calculate the data transfer residual as the 2's complement 
+	  integer (A positive value in returned on data overrun, and 
+	  a negative one on underrun).
+	- Add support of some 'resource handling' for linux-2.3.13.
+	  Basically the BARs have been changed to something more complex 
+	  in the pci_dev structure.
+	- Remove some deprecated code.
+
+Sat Jun  5  11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5c
+	- Donnot negotiate on auto-sense if we are currently using 8 bit 
+	  async transfer for the target.
+	- Only check for SISL/RAID on i386 platforms.
+	  (A problem has been reported on PPC with that code).
+	- On MSG REJECT for a negotiation, the driver attempted to restart 
+	  the SCRIPT processor when this one was already running.
+
+Sat May 29  12:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5b
+	- Force negotiation prior auto-sense.
+	  This ensures that the driver will be able to grab the sense data 
+	  from a device that has received a BUS DEVICE RESET message from 
+	  another initiator.
+	- Complete all disconnected CCBs for a logical UNIT if we are told 
+	  about a UNIT ATTENTION for a RESET condition by this target.
+	- Add the control command 'cleardev' that allows to send a ABORT  
+	  message to a logical UNIT (for test purpose).
+
+Tue May 25  23:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5a
+	- Add support for task abort and bus device reset SCSI message 
+	  and implement proper synchonisation with SCRIPTS to handle 
+          correctly task abortion without races.
+	- Send an ABORT message (if untagged) or ABORT TAG message (if tagged)
+	  when the driver is told to abort a command that is disconnected and 
+	  complete the command with appropriate error.
+	  If the aborted command is not yet started, remove it from the start 
+	  queue and complete it with error.
+	- Add the control command 'resetdev' that allows to send a BUS 
+	  DEVICE RESET message to a target (for test purpose).
+	- Clean-up some unused or useless code.
+
+Fri May 21  23:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5
+	- Add support for CHMOV with Wide controllers.
+	- Handling of the SWIDE (low byte residue at the end of a CHMOV 
+	  in DATA IN phase with WIDE transfer when the byte count gets odd).
+	- Handling of the IGNORE WIDE RESIDUE message.
+	  Handled from SCRIPTS as possible with some optimizations when both 
+	  a wide device and the controller are odd at the same time (SWIDE 
+	  present and IGNORE WIDE RESIDUE message on the BUS at the same time).
+	- Check against data OVERRUN/UNDERRUN condition at the end of a data 
+	  transfer, whatever a SWIDE is present (OVERRUN in DATA IN phase) 
+	  or the SODL is full (UNDERRUN in DATA out phase).
+	- Handling of the MODIFY DATA POINTER message.
+	  This one cannot be handled from SCRIPTS, but hopefully it will not
+	  happen very often. :)
+	- Large rewrite of the SCSI MESSAGE handling.
+
+Sun May 9  11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.4
+	- Support for IMMEDIATE ARBITRATION.
+	  See the README file for detailed information about this feature.
+	  Requires both a compile option and a boot option.
+	- Minor SCRIPTS optimization in reselection pattern for LUN 0.
+	- Simpler algorithm to deal with SCSI command starvation.
+	  Just use 2 tag counters in flip/flop and switch to the other 
+	  one every 3 seconds.
+	- Do some work in SCRIPTS after the SELECT instruction and prior 
+	  to testing for a PHASE. SYMBIOS say this feature is working fine. 
+	  (Btw, only problems with Toshiba 3401B had been reported).
+	- Measure the PCI clock speed and donnot attach controllers if 
+	  result is greater than 37 MHz. Since the precision of the 
+	  algorithm (from Stefan Esser) is better than 2%, this should 
+	  be fine.
+	- Fix the misdetection of SYM53C875E (was detected as a 876).
+	- Fix the misdetection of SYM53C810 not A (was detected as a 810A).
+	- Support for up to 256 TAGS per LUN (CMD_PER_LUN).
+	  Currently limited to 255 due to Linux limitation. :)
+	- Support for up to 508 active commands (CAN_QUEUE).
+	- Support for the 53C895A by Pamela Delaney <pam.delaney@lsil.com>
+	  The 53C895A contains all of the features of the 896 but has only 
+	  one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing 
+	  using dual cycle PCI data transfers.
+	- Miscellaneous minor fixes.
+	- Some additions to the README.ncr53c8xx file.
+
+Tue Apr 15  10:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.3e
+	- Support for any number of LUNs (64) (SPI2-compliant).
+	  (Btw, this may only be ever usefull under linux-2.2 ;-))
+
+Sun Apr 11  10:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.3d
+	- Add 'hostid:#id' boot option. This option allows to change the 
+	  default SCSI id the driver uses for controllers.
+	- Make SCRIPTS not use self-mastering for PCI.
+	  There were still 2 places the driver used this feature of the 
+	  53C8XX family.
+	- Move some data structures (nvram layouts and driver set-up) to 
+	  the sym53c8xx_defs.h file. So, the both drivers will share them.
+	- Set MAX LUNS to 16 (instead of 8).
+
 Sat Mar 20  21:00 1999 Gerard Roudier (groudier@club-internet.fr)
 	* version sym53c8xx-1.3b
 	- Add support for NCR PQS PDS.
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.3.19/linux/drivers/scsi/Makefile	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/Makefile	Thu Oct  7 10:17:09 1999
@@ -129,6 +129,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_SIM710),y)
+L_OBJS += sim710.o
+else
+  ifeq ($(CONFIG_SCSI_SIM710),m)
+  M_OBJS += sim710.o
+  endif
+endif
+
 ifeq ($(CONFIG_A4000T_SCSI),y)
 L_OBJS += amiga7xx.o 53c7xx.o
 else
@@ -681,6 +689,17 @@
 
 53c7xx.o : 53c7xx_d.h
 
+sim710_d.h: sim710.scr script_asm.pl
+	ln -sf sim710.scr fake7.c
+	$(CPP) -traditional -DCHIP=710 fake7.c | grep -v '^#' | perl -s script_asm.pl -ncr7x0_family
+	mv script.h sim710_d.h
+	mv scriptu.h sim710_u.h
+	rm fake7.c
+
+sim710_u.h: sim710_d.h
+
+sim710.o : sim710_d.h
+ 
 initio.o: ini9100u.c i91uscsi.c
 	$(CC) $(CFLAGS) -c ini9100u.c -o ini9100u.o
 	$(CC) $(CFLAGS) -c i91uscsi.c -o i91uscsi.o
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx
--- v2.3.19/linux/drivers/scsi/README.aic7xxx	Wed Jun  9 16:59:15 1999
+++ linux/drivers/scsi/README.aic7xxx	Thu Oct  7 12:50:23 1999
@@ -20,11 +20,13 @@
     AHA-2920C
     AHA-2930
     AHA-2930U
+    AHA-2930CU
     AHA-2930U2
     AHA-2940               
     AHA-2940W              
     AHA-2940U              
     AHA-2940UW
+    AHA-2940UW-PRO
     AHA-2940AU 
     AHA-2940U2W
     AHA-2940U2
@@ -37,6 +39,7 @@
     AHA-2950U2
     AHA-2950U2W
     AHA-2950U2B
+    AHA-29160M
     AHA-3940
     AHA-3940U
     AHA-3940W
@@ -45,6 +48,8 @@
     AHA-3940U2W
     AHA-3950U2B
     AHA-3950U2D
+    AHA-3960D
+    AHA-39160M
     AHA-3985
     AHA-3985U
     AHA-3985W
@@ -159,6 +164,12 @@
         on your controller.  This helps those people who have cards without
         a SEEPROM make sure that linux and all other operating systems think
         the same way about your hard drives.
+
+    "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to
+        give the card more hardware SCB slots.  This allows the driver to use
+	that SCB RAM.  Without this option, the driver won't touch the SCB
+	RAM because it is known to cause problems on a few cards out there
+	(such as 3985 class cards).
 	
     "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
         to use the correct IRQ type for your card.  This only applies to EISA
@@ -464,10 +475,9 @@
   FTP sites
   ------------------------------
     ftp://ftp.redhat.com/pub/aic/
-      - Primary site for Doug Ledford developed driver releases
-    ftp://ftp.dialnet.net/pub/linux/aic7xxx
-      - Temporary mirror of the redhat.com ftp site while people
-        get used to the new address
+      - Out of date.  I used to keep stuff here, but too many people
+        complained about having a hard time getting into Red Hat's ftp
+	server.  So use the web site below instead.
     ftp://ftp.pcnet.com/users/eischen/Linux/
       - Dan Eischen's driver distribution area
     ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
@@ -475,10 +485,8 @@
 
   Web sites
   ------------------------------
-    http://developer.redhat.com/aic7xxx/
-      - Primary web site maintained by Doug Ledford.  I haven't actually
-        put anything up yet....but I'm planning on it.  This information
-	is put here as an add for the vapor page :)
+    http://people.redhat.com/dledford/aic7xxx.html
+      - Primary web site maintained by Doug Ledford.
 
 Dean W. Gehnert
 deang@teleport.com
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx
--- v2.3.19/linux/drivers/scsi/README.ncr53c8xx	Mon Apr 12 09:51:04 1999
+++ linux/drivers/scsi/README.ncr53c8xx	Thu Oct  7 10:17:09 1999
@@ -1,10 +1,10 @@
-The Linux NCR53C8XX driver README file
+The Linux NCR53C8XX/SYM53C8XX drivers README file
 
 Written by Gerard Roudier <groudier@club-internet.fr>
 21 Rue Carnot
 95170 DEUIL LA BARRE - FRANCE
 
-10 March 1999
+29 May 1999
 ===============================================================================
 
 1.  Introduction
@@ -25,14 +25,39 @@
       8.6  Clear profile counters
       8.7  Set flag (no_disc)
       8.8  Set verbose level
+      8.9  Reset all logical units of a target
+      8.10 Abort all tasks of all logical units of a target
 9.  Configuration parameters
 10. Boot setup commands
       10.1 Syntax
       10.2 Available arguments
+             10.2.1  Master parity checking
+             10.2.2  Scsi parity checking
+             10.2.3  Scsi disconnections
+             10.2.4  Special features
+             10.2.5  Ultra SCSI support
+             10.2.6  Default number of tagged commands
+             10.2.7  Default synchronous period factor
+             10.2.8  Negotiate synchronous with all devices
+             10.2.9  Verbosity level
+             10.2.10 Debug mode
+             10.2.11 Burst max
+             10.2.12 LED support
+             10.2.13 Max wide
+             10.2.14 Differential mode
+             10.2.15 IRQ mode
+             10.2.16 Reverse probe
+             10.2.17 Fix up PCI configuration space
+             10.2.18 Serial NVRAM
+             10.2.19 Check SCSI BUS 
+             10.2.20 Exclude a host from being attached
+             10.2.21 Suggest a default SCSI id for hosts
+             10.2.22 Enable use of IMMEDIATE ARBITRATION
       10.3 Advised boot setup commands
       10.4 PCI configuration fix-up boot option
       10.5 Serial NVRAM support boot option
       10.6 SCSI BUS checking boot option
+      10.7 IMMEDIATE ARBITRATION boot option
 11. Some constants and flags of the ncr53c8xx.h header file
 12. Installation
 13. Architecture dependent features
@@ -43,6 +68,8 @@
       14.4 Possible data corruption during a Memory Write and Invalidate
       14.5 IRQ sharing problems
 15. SCSI problem troubleshooting
+      15.1 Problem tracking
+      15.2 Understanding hardware error reports
 16. Synchonous transfer negotiation tables
       16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers
       16.2 Synchronous timings for fast SCSI-2 53C8XX controllers
@@ -69,11 +96,12 @@
 It is now available as a bundle of 2 drivers:
 
 - ncr53c8xx generic driver that supports all the SYM53C8XX family including 
-  the ealiest 810 rev. 1 and the latest 896 2 channels LVD SCSI controller.
+  the ealiest 810 rev. 1, the latest 896 (2 channel LVD SCSI controller) and
+  the new 895A (1 channel LVD SCSI controller).
 - sym53c8xx enhanced driver (a.k.a. 896 drivers) that drops support of oldest 
   chips in order to gain advantage of new features, as LOAD/STORE intructions 
   available since the 810A and hardware phase mismatch available with the 
-  latest 896.
+  896 and the 895A.
 
 You can find technical information about the NCR 8xx family in the
 PCI-HOWTO written by Michael Will and in the SCSI-HOWTO written by
@@ -95,15 +123,17 @@
 These tools are not ALPHA but quite clean and work quite well.
 It is essential you have the 'scsiinfo' package.
 
-This short documentation only describes the features of the NCR53C8XX
-driver, configuration parameters and control commands available
-through the proc SCSI file system read / write operations.
+This short documentation describes the features of the generic and enhanced
+drivers, configuration parameters and control commands available through 
+the proc SCSI file system read / write operations.
 
 This driver has been tested OK with linux/i386, Linux/Alpha and Linux/PPC.
 
 Latest driver version and patches are available at:
 
           ftp://ftp.tux.org/pub/people/gerard-roudier
+or
+          ftp://ftp.symbios.com/mirror/ftp.tux.org/pub/tux/roudier/drivers
 
 I am not a native speaker of English and there are probably lots of
 mistakes in this README file. Any help will be welcome.
@@ -136,6 +166,7 @@
 875        Y         Y      FAST20    40 MB/s        Y             Y
 876        Y         Y      FAST20    40 MB/s        Y             Y
 895        Y         Y      FAST40    80 MB/s        Y             Y
+895A       Y         Y      FAST40    80 MB/s        Y             Y
 896        Y         Y      FAST40    80 MB/s        Y             Y
 
 
@@ -156,21 +187,25 @@
 
 3.1 Optimized SCSI SCRIPTS.
 
-The 810A, 825A, 875, 895 and newest 896 support new SCSI SCRIPTS instructions 
-named LOAD and STORE that allow to move 1 DWORD from/to an IO register to/from 
-memory much faster that the MOVE MEMORY instruction that is supported by the 
-53c7xx and 53c8xx family. The LOAD/STORE instructions support absolute and 
-DSA relative addressing modes. The SCSI SCRIPTS had been entirely rewritten 
-using LOAD/STORE instead of MOVE MEMORY instructions.
+The 810A, 825A, 875, 895, 896 and 895A support new SCSI SCRIPTS instructions 
+named LOAD and STORE that allow to move up to 1 DWORD from/to an IO register 
+to/from memory much faster that the MOVE MEMORY instruction that is supported 
+by the 53c7xx and 53c8xx family.
+The LOAD/STORE instructions support absolute and DSA relative addressing 
+modes.  The SCSI SCRIPTS had been entirely rewritten using LOAD/STORE instead 
+of MOVE MEMORY instructions.
 
 3.2 New features of the SYM53C896 (64 bit PCI dual LVD SCSI controller)
 
-The 896 allows to handle the phase mismatch context saving from SCRIPTS 
-(avoids the phase mismatch interrupt that stops the SCSI processor 
+The 896 and the 895A allows handling of the phase mismatch context from 
+SCRIPTS (avoids the phase mismatch interrupt that stops the SCSI processor 
 until the C code has saved the context of the transfer).
 Implementing this without using LOAD/STORE instructions would be painfull 
-and I did'nt even try it. This chip also supports 64 bit PCI transactions 
-and addressing. The SCRIPTS processor is not true 64 bit, but uses segment 
+and I did'nt even want to try it.
+
+The 896 chip supports 64 bit PCI transactions and addressing, while the 
+895A supports 32 bit PCI transactions and 64 bit addressing.
+The SCRIPTS processor of these chips is not true 64 bit, but uses segment 
 registers for bit 32-63. Another interesting feature is that LOAD/STORE 
 instructions that address the on-chip RAM (8k) remain internal to the chip.
 
@@ -219,9 +254,13 @@
 is currently set to 8 by default.  This value is suitable for most SCSI
 disks.  With large SCSI disks (>= 2GB, cache >= 512KB, average seek time
 <= 10 ms), using a larger value may give better performances.
-The driver supports up to 64 commands per device, but using more than 
-32 is generally not worth it, unless you are using a very large disk 
-or disk array.
+
+The sym53c8xx driver supports up to 255 commands per device, and the 
+generic ncr53c8xx driver supports up to 64, but using more than 32 is 
+generally not worth-while, unless you are using a very large disk or disk 
+array. It is noticeable that most of recent hard disks seem not to accept 
+more than 64 simultaneous commands. So, using more than 64 queued commands 
+is probably just resource wasting.
 
 If your controller does not have NVRAM or if it is managed by the SDMS 
 BIOS/SETUP, you can configure tagged queueing feature and device queue 
@@ -491,6 +530,24 @@
     The driver default verbose level is 1. This command allows to change 
     th driver verbose level after boot-up.
 
+8.9 Reset all logical units of a target
+
+    resetdev <target>
+
+    target:    target number
+    The driver will try to send a BUS DEVICE RESET message to the target.
+    (Only supported by the SYM53C8XX driver and provided for test purpose)
+
+8.10 Abort all tasks of all logical units of a target
+
+    cleardev <target>
+
+    target:    target number
+    The driver will try to send a ABORT message to all the logical units 
+    of the target.
+    (Only supported by the SYM53C8XX driver and provided for test purpose)
+
+
 9. Configuration parameters
 
 If the firmware of all your devices is perfect enough, all the
@@ -566,10 +623,11 @@
 Setup commands can be passed to the driver either at boot time or as a 
 string variable using 'insmod'.
 
-A boot setup command for the ncr53c8xx driver begins with the driver name 
-"ncr53c8xx=". The kernel syntax parser then expects an optionnal list of
-integers separated with comma followed by an optionnal list of  comma- 
-separated strings. Example of boot setup command under lilo prompt:
+A boot setup command for the ncr53c8xx (sym53c8xx) driver begins with the 
+driver name "ncr53c8xx="(sym53c8xx). The kernel syntax parser then expects 
+an optionnal list of integers separated with comma followed by an optional 
+list of  comma-separated strings. Example of boot setup command under lilo 
+prompt:
 
 lilo: linux root=/dev/hda2 ncr53c8xx=tags:4,sync:10,debug:0x200
 
@@ -582,7 +640,7 @@
 The following command will install driver module with the same options as 
 above.
 
-insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200"
+    insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200"
 
 For the moment, the integer list of arguments is discarded by the driver. 
 It will be used in the future in order to allow a per controller setup.
@@ -590,40 +648,53 @@
 Each string argument must be specified as "keyword:value". Only lower-case 
 characters and digits are allowed.
 
+In a system that contains multiple 53C8xx adapters insmod will install the 
+specified driver on each adapter. To exclude a chip use the 'excl' keyword.
+
+The sequence of commands, 
+
+    insmod sym53c8xx sym53c8xx=excl:0x1400
+    insmod ncr53c8xx
+
+installs the sym53c8xx driver on all adapters except the one at IO port 
+address 0x1400 and then installs the ncr53c8xx driver to the adapter at IO 
+port address 0x1400.
+
+
 10.2 Available arguments
 
-Master parity checking
-      mpar:y     enabled
-      mpar:n     disabled
-
-Scsi parity checking
-      spar:y     enabled
-      spar:n     disabled
-
-Scsi disconnections
-      disc:y     enabled
-      disc:n     disabled
+10.2.1  Master parity checking
+        mpar:y     enabled
+        mpar:n     disabled
+
+10.2.2  Scsi parity checking
+        spar:y     enabled
+        spar:n     disabled
+
+10.2.3  Scsi disconnections
+        disc:y     enabled
+        disc:n     disabled
  
-Special features
+10.2.4  Special features
    Only apply to 810A, 825A, 860, 875 and 895 controllers.
    Have no effect with other ones.
-      specf:y    (or 1) enabled
-      specf:n    (or 0) disabled
-      specf:3           enabled except Memory Write And Invalidate
+        specf:y    (or 1) enabled
+        specf:n    (or 0) disabled
+        specf:3           enabled except Memory Write And Invalidate
    The default driver setup is 'specf:3'. As a consequence, option 'specf:y' 
    must be specified in the boot setup command to enable Memory Write And 
    Invalidate.
 
-Ultra SCSI support
+10.2.5  Ultra SCSI support
    Only apply to 860, 875 and 895 controllers.
    Have no effect with other ones.
-      ultra:2    Ultra2 enabled
-      ultra:1    Ultra enabled
-      ultra:n    disabled
-
-Default number of tagged commands
-      tags:0     (or tags:1 ) tagged command queuing disabled
-      tags:#tags (#tags  > 1) tagged command queuing enabled
+        ultra:2    Ultra2 enabled
+        ultra:1    Ultra enabled
+        ultra:n    disabled
+
+10.2.6  Default number of tagged commands
+        tags:0     (or tags:1 ) tagged command queuing disabled
+        tags:#tags (#tags  > 1) tagged command queuing enabled
   #tags will be truncated to the max queued commands configuration parameter.
   This option also allows to specify a command queue depth for each device 
   that support tagged command queueing.
@@ -635,9 +706,9 @@
       - controller #1 target #1 logical unit #2                -> 32 commands,
       - all other logical units (all targets, all controllers) -> 10 commands.
 
-Default synchronous period factor
-      sync:255     disabled (asynchronous transfer mode)
-      sync:#factor
+10.2.7  Default synchronous period factor
+        sync:255     disabled (asynchronous transfer mode)
+        sync:#factor
   #factor = 10     Ultra-2 SCSI 40 Mega-transfers / second
   #factor = 11     Ultra-2 SCSI 33 Mega-transfers / second
   #factor < 25     Ultra   SCSI 20 Mega-transfers / second
@@ -646,19 +717,19 @@
   In all cases, the driver will use the minimum transfer period supported by 
   controllers according to NCR53C8XX chip type.
 
-Negotiate synchronous with all devices
-  (force sync nego)
-      fsn:y      enabled
-      fsn:n      disabled
-
-Verbosity level
-      verb:0     minimal
-      verb:1     normal
-      verb:2     too much
-
-Debug mode
-      debug:0	 clear debug flags
-      debug:#x   set debug flags
+10.2.8  Negotiate synchronous with all devices
+        (force sync nego)
+        fsn:y      enabled
+        fsn:n      disabled
+
+10.2.9  Verbosity level
+        verb:0     minimal
+        verb:1     normal
+        verb:2     too much
+
+10.2.10 Debug mode
+        debug:0	 clear debug flags
+        debug:#x   set debug flags
   #x is an integer value combining the following power-of-2 values:
   DEBUG_ALLOC       0x1
   DEBUG_PHASE       0x2
@@ -677,10 +748,10 @@
   You can play safely with DEBUG_NEGO. However, some of these flags may 
   generate bunches of syslog messages. 
 
-Burst max
-      burst:0    burst disabled
-      burst:255  get burst length from initial IO register settings.
-      burst:#x   burst enabled (1<<#x burst transfers max)
+10.2.11 Burst max
+        burst:0    burst disabled
+        burst:255  get burst length from initial IO register settings.
+        burst:#x   burst enabled (1<<#x burst transfers max)
   #x is an integer value which is log base 2 of the burst transfers max.
   The NCR53C875 and NCR53C825A support up to 128 burst transfers (#x = 7).
   Other chips only support up to 16 (#x = 4).
@@ -688,42 +759,42 @@
   and revision ids. By default the driver uses the maximum value supported 
   by the chip.
 
-LED support
-     led:1      enable  LED support
-     led:0      disable LED support
+10.2.12 LED support
+        led:1      enable  LED support
+        led:0      disable LED support
   Donnot enable LED support if your scsi board does not use SDMS BIOS.
   (See 'Configuration parameters')
 
-Max wide
-    wide:1      wide scsi enabled
-    wide:0      wide scsi disabled
+10.2.13 Max wide
+        wide:1      wide scsi enabled
+        wide:0      wide scsi disabled
   Some scsi boards use a 875 (ultra wide) and only supply narrow connectors.
   If you have connected a wide device with a 50 pins to 68 pins cable 
   converter, any accepted wide negotiation will break further data transfers.
   In such a case, using "wide:0" in the bootup command will be helpfull. 
 
-Differential mode
-    diff:0	never set up diff mode
-    diff:1	set up diff mode if BIOS set it
-    diff:2	always set up diff mode
-    diff:3	set diff mode if GPIO3 is not set
-
-IRQ mode
-    irqm:0	always open drain
-    irqm:1	same as initial settings (assumed BIOS settings)
-    irqm:2	always totem pole
-    irqm:0x10	driver will not use SA_SHIRQ flag when requesting irq
-    irqm:0x20	driver will not use SA_INTERRUPT flag when requesting irq
+10.2.14 Differential mode
+        diff:0	never set up diff mode
+        diff:1	set up diff mode if BIOS set it
+        diff:2	always set up diff mode
+        diff:3	set diff mode if GPIO3 is not set
+
+10.2.15 IRQ mode
+        irqm:0     always open drain
+        irqm:1     same as initial settings (assumed BIOS settings)
+        irqm:2     always totem pole
+        irqm:0x10  driver will not use SA_SHIRQ flag when requesting irq
+        irqm:0x20  driver will not use SA_INTERRUPT flag when requesting irq
 
     (Bits 0x10 and 0x20 can be combined with hardware irq mode option)
 
-Reverse probe
-    revprob:n   probe chip ids from the PCI configuration in this order:
-                810, 815, 820, 860, 875, 885, 895, 896
-    revprob:y   probe chip ids in the reverse order.
+10.2.16 Reverse probe
+        revprob:n   probe chip ids from the PCI configuration in this order:
+                    810, 815, 820, 860, 875, 885, 895, 896
+        revprob:y   probe chip ids in the reverse order.
 
-Fix up PCI configuration space
-    pcifix:<option bits>
+10.2.17 Fix up PCI configuration space
+        pcifix:<option bits>
 
     Available option bits:
         0x0:   No attempt to fix PCI configuration space registers values.
@@ -733,25 +804,52 @@
 
     Use 'pcifix:7' in order to allow the driver to fix up all PCI features.
 
-Serial NVRAM
-    nvram:n     do not look for serial NVRAM
-    nvram:y     test controllers for onboard serial NVRAM
+10.2.18 Serial NVRAM
+        nvram:n     do not look for serial NVRAM
+        nvram:y     test controllers for onboard serial NVRAM
+        (alternate binary form)
+        mvram=<bits options>
+        0x01   look for NVRAM  (equivalent to nvram=y)
+        0x02   ignore NVRAM "Synchronous negotiation" parameters for all devices
+        0x04   ignore NVRAM "Wide negotiation"  parameter for all devices
+        0x08   ignore NVRAM "Scan at boot time" parameter for all devices
+        0x80   also attach controllers set to OFF in the NVRAM (sym53c8xx only)
 
-Check SCSI BUS 
-    buschk:<option bits>
+10.2.19 Check SCSI BUS 
+        buschk:<option bits>
 
     Available option bits:
         0x0:   No check.
         0x1:   Check and donnot attach the controller on error.  
         0x2:   Check and just warn on error.
 
-Exclude hosts from being attached
-    excl=<io_address>
+10.2.20 Exclude a host from being attached
+        excl=<io_address>
 
     Prevent host at a given io address from being attached.
     For example 'ncr53c8xx=excl:0xb400,excl:0xc000' indicate to the 
     ncr53c8xx driver not to attach hosts at address 0xb400 and 0xc000.
 
+10.2.21 Suggest a default SCSI id for hosts
+        hostid:255	no id suggested.
+        hostid:#x   (0 < x < 7) x suggested for hosts SCSI id.
+
+    If a host SCSI id is available from the NVRAM, the driver will ignore 
+    any value suggested as boot option. Otherwise, if a suggested value 
+    different from 255 has been supplied, it will use it. Otherwise, it will 
+    try to deduce the value previously set in the hardware and use value 
+    7 if the hardware value is zero.
+
+10.2.22 Enable use of IMMEDIATE ARBITRATION
+        (only supported by the sym53c8xx driver. See 10.7 for more details)
+        iarb:0    donnot use this feature.
+        iarb:#x   use this feature according to bit fields as follow:
+
+    bit 0 (1) : enable IARB each time the initiator has been reselected 
+                when it arbitrated for the SCSI BUS.
+    (#x >> 4) : maximum number of successive settings of IARB if the initiator 
+                win arbitration and it has other commands to send to a device.
+
 Boot fail safe
     safe:y	load the following assumed fail safe initial setup
 
@@ -775,6 +873,7 @@
   differential support		from BIOS settings	diff:1
   irq mode			from BIOS settings	irqm:1
   SCSI BUS check		donnot attach on error	buschk:1
+  immediate arbitration		disabled		iarb:0
 
 10.3 Advised boot setup commands
 
@@ -837,7 +936,11 @@
 nvram:n     do not look for serial NVRAM
 nvram:y     test controllers for onboard serial NVRAM
 
-This option is described below (see 17. Serial NVRAM support).
+This option can also been entered as an hexadecimal value that allows 
+to control what information the driver will get from the NVRAM and what 
+information it will ignore.
+For details see '17. Serial NVRAM support'.
+
 When this option is enabled, the driver tries to detect all boards using 
 a Serial NVRAM. This memory is used to hold user set up parameters.
 
@@ -873,12 +976,17 @@
       0x02   ignore NVRAM "Synchronous negotiation" parameters for all devices
       0x04   ignore NVRAM "Wide negotiation"  parameter for all devices
       0x08   ignore NVRAM "Scan at boot time" parameter for all devices
+      0x80   also attach controllers set to OFF in the NVRAM (sym53c8xx only)
 
-My Atlas Wide only boots cleanly in 8 bits asynchronous data transfer 
-mode. However, it works flawlessly at 20 MB/second with the driver.
-Using "nvram=0x7" allows me to boot in 8 bits/async and to let the driver 
-use its setup for synchronous and wide negotiations.
-
+Option 0x80 is only supported by the sym53c8xx driver and is disabled by 
+default. Result is that, by default (option not set), the sym53c8xx driver 
+will not attach controllers set to OFF in the NVRAM.
+
+The ncr53c8xx always tries to attach all the controllers. Option 0x80 has 
+not been added to the ncr53c8xx driver, since it has been reported to 
+confuse users who use this driver since a long time. If you desire a 
+controller not to be attached by the ncr53c8xx driver at Linux boot, you 
+must use the 'excl' driver boot option.
 
 10.6 SCSI BUS checking boot option.
 
@@ -894,6 +1002,45 @@
 On the other hand, either bad cabling, broken devices, not conformant 
 devices, ... may cause a SCSI signal to be wrong when te driver reads it.
 
+10.7 IMMEDIATE ARBITRATION boot option
+
+This option is only supported by the SYM53C8XX driver (not by the NCR53C8XX).
+
+SYMBIOS 53C8XX chips are able to arbitrate for the SCSI BUS as soon as they 
+have detected an expected disconnection (BUS FREE PHASE). For this process 
+to be started, bit 1 of SCNTL1 IO register must be set when the chip is 
+connected to the SCSI BUS.
+
+When this feature has been enabled for the current connection, the chip has 
+every chance to win arbitration if only devices with lower priority are 
+competing for the SCSI BUS. By the way, when the chip is using SCSI id 7, 
+then it will for sure win the next SCSI BUS arbitration.
+
+Since, there is no way to know what devices are trying to arbitrate for the 
+BUS, using this feature can be extremally unfair. So, you are not advised 
+to enable it, or at most enable this feature for the case the chip lost 
+the previous arbitration (boot option 'iarb:1').
+
+This feature has the following advantages:
+
+a) Allow the initiator with ID 7 to win arbitration when it wants so.
+b) Overlap at least 4 micro-seconds of arbitration time with the execution 
+   of SCRIPTS that deal with the end of the current connection and that 
+   starts the next job.
+
+Hmmm... But (a) may just prevent other devices from reselecting the initiator, 
+and delay data transfers or status/completions, and (b) may just waste 
+SCSI BUS bandwidth if the SCRIPTS execution lasts more than 4 micro-seconds.
+
+The use of IARB needs the SCSI_NCR_IARB_SUPPORT option to have been defined 
+at compile time and the 'iarb' boot option to have been set to a non zero 
+value at boot time. It is not that usefull for real work, but can be used 
+to stress SCSI devices or for some applications that can gain advantage of 
+it. By the way, if you experience badnesses like 'unexpected disconnections', 
+'bad reselections', etc... when using IARB on heavy IO load, you should not 
+be surprised, because force-feeding anything and blocking its arse at the 
+same time cannot work for a long time. :-))
+
 
 11. Some constants and flags of the ncr53c8xx.h header file
 
@@ -1107,6 +1254,8 @@
 
 15. SCSI problem troubleshooting
 
+15.1 Problem tracking
+
 Most SCSI problems are due to a non conformant SCSI bus or to buggy
 devices.  If infortunately you have SCSI problems, you can check the
 following things:
@@ -1153,6 +1302,77 @@
 Once you have found the device and the feature that cause problems, just 
 disable that feature for that device.
 
+15.2 Understanding hardware error reports
+
+When the driver detects an unexpected error condition, it may display a 
+message of the following pattern.
+
+sym53c876-0:1: ERROR (0:48) (1-21-65) (f/95) @ (script 7c0:19000000).
+sym53c876-0: script cmd = 19000000
+sym53c876-0: regdump: da 10 80 95 47 0f 01 07 75 01 81 21 80 01 09 00.
+
+Some fields in such a message may help you understand the cause of the 
+problem, as follows:
+
+sym53c876-0:1: ERROR (0:48) (1-21-65) (f/95) @ (script 7c0:19000000).
+............A.........B.C....D.E..F....G.H.......I.....J...K.......
+
+Field A : target number.
+  SCSI ID of the device the controller was talking with at the moment the 
+  error occurs.
+
+Field B : DSTAT io register (DMA STATUS)
+  Bit 0x40 : MDPE Master Data Parity Error
+             Data parity error detected on the PCI BUS.
+  Bit 0x20 : BF   Bus Fault
+             PCI bus fault condition detected
+  Bit 0x01 : IID  Illegal Instruction Detected
+             Set by the chip when it detects an Illegal Instruction format 
+             on some condition that makes an instruction illegal.
+  Bit 0x80 : DFE Dma Fifo Empty
+             Pure status bit that does not indicate an error.
+  If the reported DSTAT value contains a combination of MDPE (0x40), 
+  BF (0x20), then the cause may be likely due to a PCI BUS problem.
+
+Field C : SIST io register (SCSI Interrupt Status)
+  Bit 0x08 : SGE  SCSI GROSS ERROR
+             Indicates that the chip detected a severe error condition 
+             on the SCSI BUS that prevents the SCSI protocol from functionning
+             properly.
+  Bit 0x04 : UDC  Undexpected Disconnection
+             Indicates that the device released the SCSI BUS when the chip 
+             was not expecting this to happen. A device may behave so to 
+             indicate the SCSI initiator that an error condition not reportable              using the SCSI protocol has occured.
+  Bit 0x02 : RST  SCSI BUS Reset
+             Generally SCSI targets donnot reset the SCSI BUS, although any 
+             device on the BUS can reset it at any time.
+  Bit 0x01 : PAR  Parity
+             SCSI parity error detected.
+  On a faulty SCSI BUS, any error condition among SGE (0x08), UDC (0x04) and 
+  PAR (0x01) may be detected by the chip. If your SCSI system sometimes 
+  encounters such error conditions, especially SCSI GROSS ERROR, then a SCSI 
+  BUS problem is likely the cause of these errors.
+
+For fields D,E,F,G and H, you may look into the sym53c8xx_defs.h file 
+that contains some minimal comments on IO register bits.
+Field D : SOCL  Scsi Output Control Latch
+          This register reflects the state of the SCSI control lines the 
+          chip want to drive or compare against.
+Field E : SBCL  Scsi Bus Control Lines
+          Actual value of control lines on the SCSI BUS.
+Field F : SBDL  Scsi Bus Data Lines
+          Actual value of data lines on the SCSI BUS.
+Field G : SXFER  SCSI Transfer
+          Contains the setting of the Synchronous Period for output and 
+          the current Synchronous offset (offset 0 means asynchronous).
+Field H : SCNTL3 Scsi Control Register 3
+          Contains the setting of timing values for both asynchronous and 
+          synchronous data transfers. 
+
+Understanding Fields I, J, K and dumps requires to have good knowledge of 
+SCSI standards, chip cores functionnals and internal driver data structures.
+You are not required to decode and understand them, unless you want to help 
+maintain the driver code.
 
 16. Synchonous transfer negotiation tables
 
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.3.19/linux/drivers/scsi/aic7xxx.c	Fri Sep 10 23:57:31 1999
+++ linux/drivers/scsi/aic7xxx.c	Thu Oct  7 12:51:25 1999
@@ -269,7 +269,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.19"
+#define AIC7XXX_C_VERSION  "5.1.20"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -878,13 +878,14 @@
   AHC_SG_PRELOAD       = 0x0080,
   AHC_SPIOCAP          = 0x0100,
   AHC_ULTRA3           = 0x0200,
+  AHC_NEW_AUTOTERM     = 0x0400,
   AHC_AIC7770_FE       = AHC_FENONE,
   AHC_AIC7850_FE       = AHC_SPIOCAP,
   AHC_AIC7860_FE       = AHC_ULTRA|AHC_SPIOCAP,
   AHC_AIC7870_FE       = AHC_FENONE,
   AHC_AIC7880_FE       = AHC_ULTRA,
   AHC_AIC7890_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|
-                         AHC_QUEUE_REGS|AHC_SG_PRELOAD,
+                         AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_NEW_AUTOTERM,
   AHC_AIC7895_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
   AHC_AIC7896_FE       = AHC_AIC7890_FE,
   AHC_AIC7892_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
@@ -1351,7 +1352,14 @@
  * would result in never finding any devices :)
  */
 static int aic7xxx_no_probe = 0;
-
+/*
+ * On some machines, enabling the external SCB RAM isn't reliable yet.  I
+ * haven't had time to make test patches for things like changing the
+ * timing mode on that external RAM either.  Some of those changes may
+ * fix the problem.  Until then though, we default to external SCB RAM
+ * off and give a command line option to enable it.
+ */
+static int aic7xxx_scbram = 0;
 /*
  * So that insmod can find the variable and make it point to something
  */
@@ -1450,13 +1458,12 @@
   unsigned char x;
   if(p->maddr)
   {
-    x = p->maddr[port];
+    x = readb(p->maddr + port);
   }
   else
   {
     x = inb(p->base + port);
   }
-  mb();
   return(x);
 #else
   return(inb(p->base + port));
@@ -1469,7 +1476,7 @@
 #ifdef MMAPIO
   if(p->maddr)
   {
-    p->maddr[port] = val;
+    writeb(val, p->maddr + port);
   }
   else
   {
@@ -1513,6 +1520,7 @@
     { "pci_parity", &aic7xxx_pci_parity },
     { "dump_card", &aic7xxx_dump_card },
     { "dump_sequencer", &aic7xxx_dump_sequencer },
+    { "scbram", &aic7xxx_scbram },
     { "tag_info",    NULL }
   };
 
@@ -6193,7 +6201,7 @@
         cmd->result = 0;
         scb = NULL;
       }
-      if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
+      else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
       {
         /*
          * Turn off the needsdtr, needwdtr, and needppr bits since this device
@@ -6541,6 +6549,105 @@
 }
 #endif
 
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_command_completion_intr
+ *
+ * Description:
+ *   SCSI command completion interrupt handler.
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
+{
+  struct aic7xxx_scb *scb = NULL;
+  Scsi_Cmnd *cmd;
+  unsigned char scb_index;
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
+    printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
+#endif
+    
+  /*
+   * Read the INTSTAT location after clearing the CMDINT bit.  This forces
+   * any posted PCI writes to flush to memory.  Gerard Roudier suggested
+   * this fix to the possible race of clearing the CMDINT bit but not
+   * having all command bytes flushed onto the qoutfifo.
+   */
+  aic_outb(p, CLRCMDINT, CLRINT);
+  aic_inb(p, INTSTAT);
+  /*
+   * The sequencer will continue running when it
+   * issues this interrupt. There may be >1 commands
+   * finished, so loop until we've processed them all.
+   */
+
+  while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
+  {
+    scb_index = p->qoutfifo[p->qoutfifonext];
+    p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
+    if ( scb_index >= p->scb_data->numscbs )
+      scb = NULL;
+    else
+      scb = p->scb_data->scb_array[scb_index];
+    if (scb == NULL)
+    {
+      printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
+        -1, -1, -1, scb_index);
+      continue;
+    }
+    else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+    {
+      printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
+        "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
+        (unsigned long) scb->cmd);
+      continue;
+    }
+    else if (scb->flags & SCB_QUEUED_ABORT)
+    {
+      pause_sequencer(p);
+      if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
+           (aic_inb(p, SCB_TAG) == scb->hscb->tag) )
+      {
+        unpause_sequencer(p, FALSE);
+        continue;
+      }
+      aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel,
+        scb->cmd->lun, scb->hscb->tag);
+      scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT |
+        SCB_QUEUED_ABORT);
+      unpause_sequencer(p, FALSE);
+    }
+    else if (scb->flags & SCB_ABORT)
+    {
+      /*
+       * We started to abort this, but it completed on us, let it
+       * through as successful
+       */
+      scb->flags &= ~(SCB_ABORT|SCB_RESET);
+    }
+    switch (status_byte(scb->hscb->target_status))
+    {
+      case QUEUE_FULL:
+      case BUSY:
+        scb->hscb->target_status = 0;
+        scb->cmd->result = 0;
+        aic7xxx_error(scb->cmd) = DID_OK;
+        break;
+      default:
+        cmd = scb->cmd;
+        if (scb->hscb->residual_SG_segment_count != 0)
+        {
+          aic7xxx_calculate_residual(p, scb);
+        }
+        cmd->result |= (aic7xxx_error(cmd) << 16);
+        aic7xxx_done(p, scb);
+        break;
+    }      
+  }
+}
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_isr
@@ -6600,95 +6707,7 @@
    */
   if (intstat & CMDCMPLT)
   {
-    struct aic7xxx_scb *scb = NULL;
-    Scsi_Cmnd *cmd;
-    unsigned char scb_index;
-
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-    if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
-      printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
-#endif
-    
-    /*
-     * Clear interrupt status before running the completion loop.
-     * This eliminates a race condition whereby a command could
-     * complete between the last check of qoutfifo and the
-     * CLRCMDINT statement.  This would result in us thinking the
-     * qoutfifo was empty when it wasn't, and in actuality be a lost
-     * completion interrupt.  With multiple devices or tagged queueing
-     * this could be very bad if we caught all but the last completion
-     * and no more are imediately sent.
-     */
-    aic_outb(p, CLRCMDINT, CLRINT);
-    /*
-     * The sequencer will continue running when it
-     * issues this interrupt. There may be >1 commands
-     * finished, so loop until we've processed them all.
-     */
-
-    while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
-    {
-      scb_index = p->qoutfifo[p->qoutfifonext];
-      p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
-      if ( scb_index >= p->scb_data->numscbs )
-        scb = NULL;
-      else
-        scb = p->scb_data->scb_array[scb_index];
-      if (scb == NULL)
-      {
-        printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
-          -1, -1, -1, scb_index);
-        continue;
-      }
-      else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-      {
-        printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
-          "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
-          (unsigned long) scb->cmd);
-        continue;
-      }
-      else if (scb->flags & SCB_QUEUED_ABORT)
-      {
-        pause_sequencer(p);
-        if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
-             (aic_inb(p, SCB_TAG) == scb->hscb->tag) )
-        {
-          unpause_sequencer(p, FALSE);
-          continue;
-        }
-        aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel,
-          scb->cmd->lun, scb->hscb->tag);
-        scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT |
-          SCB_QUEUED_ABORT);
-        unpause_sequencer(p, FALSE);
-      }
-      else if (scb->flags & SCB_ABORT)
-      {
-        /*
-         * We started to abort this, but it completed on us, let it
-         * through as successful
-         */
-        scb->flags &= ~(SCB_ABORT|SCB_RESET);
-      }
-      switch (status_byte(scb->hscb->target_status))
-      {
-        case QUEUE_FULL:
-        case BUSY:
-          scb->hscb->target_status = 0;
-          scb->cmd->result = 0;
-          aic7xxx_error(scb->cmd) = DID_OK;
-          break;
-        default:
-          cmd = scb->cmd;
-          if (scb->hscb->residual_SG_segment_count != 0)
-          {
-            aic7xxx_calculate_residual(p, scb);
-          }
-          cmd->result |= (aic7xxx_error(cmd) << 16);
-          aic7xxx_done(p, scb);
-          break;
-      }      
-    }
+    aic7xxx_handle_command_completion_intr(p);
   }
 
   if (intstat & BRKADRINT)
@@ -7619,9 +7638,10 @@
     aic_outb(p, SEEMS | SEECS, SEECTL);
     sxfrctl1 &= ~STPWEN;
     if ( (p->adapter_control & CFAUTOTERM) ||
-         (p->features & AHC_ULTRA2) )
+         (p->features & AHC_NEW_AUTOTERM) )
     {
-      if ( (p->adapter_control & CFAUTOTERM) && !(p->features & AHC_ULTRA2) )
+      if ( (p->adapter_control & CFAUTOTERM) &&
+          !(p->features & AHC_NEW_AUTOTERM) )
       {
         printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n",
                p->host_no);
@@ -7635,7 +7655,7 @@
       }
       /* Configure auto termination. */
 
-      if (p->features & AHC_ULTRA2)
+      if (p->features & AHC_NEW_AUTOTERM)
       {
         if (aic7xxx_override_term == -1)
           aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high,
@@ -7668,7 +7688,7 @@
       if (max_target <= 8)
         internal68_present = 0;
 
-      if ( !(p->features & AHC_ULTRA2) )
+      if ( !(p->features & AHC_NEW_AUTOTERM) )
       {
         if (max_target > 8)
         {
@@ -7698,7 +7718,7 @@
        * SE Low Term Enable = BRDDAT5 (7890)
        * LVD High Term Enable = BRDDAT4 (7890)
        */
-      if ( !(p->features & AHC_ULTRA2) &&
+      if ( !(p->features & AHC_NEW_AUTOTERM) &&
            (internal50_present && internal68_present && external_present) )
       {
         printk(KERN_INFO "(scsi%d) Illegal cable configuration!!  Only two\n",
@@ -7731,7 +7751,7 @@
              (external_present   ? 1 : 0)) <= 1) ||
            (enableSE_low != 0) )
       {
-        if (p->features & AHC_ULTRA2)
+        if (p->features & AHC_NEW_AUTOTERM)
           brddat |= BRDDAT5;
         else
           sxfrctl1 |= STPWEN;
@@ -7762,7 +7782,7 @@
     {
       if (p->adapter_control & CFSTERM)
       {
-        if (p->features & AHC_ULTRA2)
+        if (p->features & AHC_NEW_AUTOTERM)
           brddat |= BRDDAT5;
         else
           sxfrctl1 |= STPWEN;
@@ -9409,7 +9429,7 @@
        AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
        32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 18,
        32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
        AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
@@ -9539,7 +9559,7 @@
           temp_p->base = pdev->resource[0].start;
           temp_p->mbase = pdev->resource[1].start;
           current_p = list_p;
-	  while(current_p)
+	  while(current_p && temp_p)
 	  {
 	    if ( ((current_p->pci_bus == temp_p->pci_bus) &&
 	          (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
@@ -9958,7 +9978,8 @@
 #endif
               if (temp_p->features & AHC_ULTRA2)
               {
-                if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
+                if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) &&
+                     (aic7xxx_scbram) )
                 {
                   aic_outb(temp_p,
                            aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2,
@@ -9966,12 +9987,33 @@
                   temp_p->flags |= AHC_EXTERNAL_SRAM;
                   devconfig |= EXTSCBPEN;
                 }
+                else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
+                {
+                  printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n", 
+                    board_names[aic_pdevs[i].board_name_index],
+                    PCI_SLOT(temp_p->pci_device_fn),
+                    PCI_FUNC(temp_p->pci_device_fn));
+                  printk("aic7xxx: external SCB RAM detected, "
+                         "but not enabled\n");
+                }
               }
-              else if (devconfig & RAMPSM)
+              else
               {
-                devconfig &= ~SCBRAMSEL;
-                devconfig |= EXTSCBPEN;
-                temp_p->flags |= AHC_EXTERNAL_SRAM;
+                if ((devconfig & RAMPSM) && (aic7xxx_scbram))
+                {
+                  devconfig &= ~SCBRAMSEL;
+                  devconfig |= EXTSCBPEN;
+                  temp_p->flags |= AHC_EXTERNAL_SRAM;
+                }
+                else if (devconfig & RAMPSM)
+                {
+                  printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n", 
+                    board_names[aic_pdevs[i].board_name_index],
+                    PCI_SLOT(temp_p->pci_device_fn),
+                    PCI_FUNC(temp_p->pci_device_fn));
+                  printk("aic7xxx: external SCB RAM detected, "
+                         "but not enabled\n");
+                }
               }
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
               pci_write_config_dword(pdev, DEVCONFIG, devconfig);
@@ -11588,13 +11630,17 @@
     if ( aic7xxx_scb_on_qoutfifo(p, scb) )
     {
       if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
-        printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
+        printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no,
           CTL_OF_SCB(scb));
-      aic7xxx_run_done_queue(p, TRUE);
+      if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0)
+        printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no,
+          CTL_OF_SCB(scb));
+      aic7xxx_handle_command_completion_intr(p);
+      aic7xxx_done_cmds_complete(p);
       aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       DRIVER_UNLOCK
-      return(SCSI_RESET_NOT_RUNNING);
+      return(SCSI_RESET_SUCCESS);
     }
     if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.3.19/linux/drivers/scsi/hosts.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/scsi/hosts.c	Thu Oct  7 10:17:09 1999
@@ -63,6 +63,10 @@
 #include "bvme6000.h"
 #endif
 
+#ifdef CONFIG_SCSI_SIM710
+#include "sim710.h"
+#endif
+
 #ifdef CONFIG_A3000_SCSI
 #include "a3000.h"
 #endif
@@ -446,6 +450,9 @@
 #endif
 #ifdef CONFIG_BVME6000_SCSI
 	BVME6000_SCSI,
+#endif
+#ifdef CONFIG_SCSI_SIM710
+	SIM710_SCSI,
 #endif
 #ifdef CONFIG_SCSI_ADVANSYS
 	ADVANSYS,
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.3.19/linux/drivers/scsi/ncr53c8xx.c	Fri Sep 10 23:57:32 1999
+++ linux/drivers/scsi/ncr53c8xx.c	Thu Oct  7 10:17:09 1999
@@ -73,7 +73,7 @@
 */
 
 /*
-**	March 7 1999, version 3.2
+**	Sep 10 1999, version 3.2c
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -83,7 +83,7 @@
 **	    Parity checking
 **	    Etc...
 **
-**	Supported NCR chips:
+**	Supported NCR/SYMBIOS chips:
 **		53C810		(8 bits, Fast SCSI-2, no rom BIOS) 
 **		53C815		(8 bits, Fast SCSI-2, on board rom BIOS)
 **		53C820		(Wide,   Fast SCSI-2, no rom BIOS)
@@ -91,6 +91,8 @@
 **		53C860		(8 bits, Fast 20,     no rom BIOS)
 **		53C875		(Wide,   Fast 20,     on board rom BIOS)
 **		53C895		(Wide,   Fast 40,     on board rom BIOS)
+**		53C895A		(Wide,   Fast 40,     on board rom BIOS)
+**		53C896		(Wide,   Fast 40,     on board rom BIOS)
 **
 **	Other features:
 **		Memory mapped IO (linux-1.3.X and above only)
@@ -101,7 +103,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - version 3.2"
+#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - 3.2c"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
@@ -121,8 +123,10 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
 #include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#include <asm/spinlock.h>
 #endif
 #include <linux/delay.h>
 #include <linux/signal.h>
@@ -142,11 +146,14 @@
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
 #include <linux/init.h>
-#else
+#endif
+
+#ifndef	__init
+#define	__init
+#endif
 #ifndef	__initdata
 #define	__initdata
 #endif
-#endif
 
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
 #include <linux/bios32.h>
@@ -363,8 +370,9 @@
 **    We need to deal with power of 2, for alignment constraints.
 */
 #if	SCSI_NCR_MAX_TAGS > 64
-#undef	SCSI_NCR_MAX_TAGS
-#define	SCSI_NCR_MAX_TAGS (64)
+#define	MAX_TAGS (64)
+#else
+#define	MAX_TAGS SCSI_NCR_MAX_TAGS
 #endif
 
 #define NO_TAG	(255)
@@ -372,7 +380,7 @@
 /*
 **	Choose appropriate type for tag bitmap.
 */
-#if	SCSI_NCR_MAX_TAGS > 32
+#if	MAX_TAGS > 32
 typedef u_int64 tagmap_t;
 #else
 typedef u_int32 tagmap_t;
@@ -422,7 +430,17 @@
 #ifdef SCSI_NCR_CAN_QUEUE
 #define MAX_START   (SCSI_NCR_CAN_QUEUE + 4)
 #else
-#define MAX_START   (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS)
+#define MAX_START   (MAX_TARGET + 7 * MAX_TAGS)
+#endif
+
+/*
+**   We limit the max number of pending IO to 250.
+**   since we donnot want to allocate more than 1 
+**   PAGE for 'scripth'.
+*/
+#if	MAX_START > 250
+#undef	MAX_START
+#define	MAX_START 250
 #endif
 
 /*
@@ -730,34 +748,6 @@
 **	This structure is initialized from linux config options.
 **	It can be overridden at boot-up by the boot command line.
 */
-#define SCSI_NCR_MAX_EXCLUDES 8
-struct ncr_driver_setup {
-	u_char	master_parity;
-	u_char	scsi_parity;
-	u_char	disconnection;
-	u_char	special_features;
-	u_char	ultra_scsi;
-	u_char	force_sync_nego;
-	u_char	reverse_probe;
-	u_char	pci_fix_up;
-	u_char	use_nvram;
-	u_char	verbose;
-	u_char	default_tags;
-	u_short	default_sync;
-	u_short	debug;
-	u_char	burst_max;
-	u_char	led_pin;
-	u_char	max_wide;
-	u_char	settle_delay;
-	u_char	diff_support;
-	u_char	irqm;
-	u_char	bus_check;
-	u_char	optimize;
-	u_char	recovery;
-	u_int	excludes[SCSI_NCR_MAX_EXCLUDES];
-	char	tag_ctrl[100];
-};
-
 static struct ncr_driver_setup
 	driver_setup			= SCSI_NCR_DRIVER_SETUP;
 
@@ -787,108 +777,7 @@
 #define bootverbose (np->verbose)
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
-/*
-**	Symbios NvRAM data format
-*/
-#define SYMBIOS_NVRAM_SIZE 368
-#define SYMBIOS_NVRAM_ADDRESS 0x100
-
-struct Symbios_nvram {
-/* Header 6 bytes */
-	u_short start_marker;	/* 0x0000 */
-	u_short byte_count;	/* excluding header/trailer */
-	u_short checksum;
-
-/* Controller set up 20 bytes */
-	u_short	word0;		/* 0x3000 */
-	u_short	word2;		/* 0x0000 */
-	u_short	word4;		/* 0x0000 */
-	u_short	flags;
-#define SYMBIOS_SCAM_ENABLE	(1)
-#define SYMBIOS_PARITY_ENABLE	(1<<1)
-#define SYMBIOS_VERBOSE_MSGS	(1<<2)
-#define SYMBIOS_CHS_MAPPING	(1<<3)
-	u_short	flags1;
-#define SYMBIOS_SCAN_HI_LO	(1)
-	u_short	word10;		/* 0x00 */
-	u_short	flags3;		/* 0x00 */
-#define SYMBIOS_REMOVABLE_FLAGS	(3)		/* 0=none, 1=bootable, 2=all */
-	u_char	host_id;
-	u_char	byte15;		/* 0x04 */
-	u_short	word16;		/* 0x0410 */
-	u_short	word18;		/* 0x0000 */
-
-/* Boot order 14 bytes * 4 */
-	struct Symbios_host{
-		u_char	word0;		/* 0x0004:ok / 0x0000:nok */
-		u_short	device_id;	/* PCI device id */
-		u_short	vendor_id;	/* PCI vendor id */
-		u_char	byte6;		/* 0x00 */
-		u_char	device_fn;	/* PCI device/function number << 3*/
-		u_short	word8;
-		u_short	flags;
-#define	SYMBIOS_INIT_SCAN_AT_BOOT	(1)
-		u_short	io_port;	/* PCI io_port address */
-	} host[4];
-
-/* Targets 8 bytes * 16 */
-	struct Symbios_target {
-		u_short	flags;
-#define SYMBIOS_DISCONNECT_ENABLE	(1)
-#define SYMBIOS_SCAN_AT_BOOT_TIME	(1<<1)
-#define SYMBIOS_SCAN_LUNS		(1<<2)
-#define SYMBIOS_QUEUE_TAGS_ENABLED	(1<<3)
-		u_char	bus_width;	/* 0x08/0x10 */
-		u_char	sync_offset;
-		u_char	sync_period;	/* 4*period factor */
-		u_char	byte6;		/* 0x00 */
-		u_short	timeout;
-	} target[16];
-	u_char	spare_devices[19*8];
-	u_char	trailer[6];		/* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
-};
-typedef struct Symbios_nvram	Symbios_nvram;
-typedef struct Symbios_host	Symbios_host;
-typedef struct Symbios_target	Symbios_target;
-
-/*
-**	Tekram NvRAM data format.
-*/
-#define TEKRAM_NVRAM_SIZE 64
-#define TEKRAM_NVRAM_ADDRESS 0
-
-struct Tekram_nvram {
-	struct Tekram_target {
-		u_char	flags;
-#define	TEKRAM_PARITY_CHECK		(1)
-#define TEKRAM_SYNC_NEGO		(1<<1)
-#define TEKRAM_DISCONNECT_ENABLE	(1<<2)
-#define	TEKRAM_START_CMD		(1<<3)
-#define TEKRAM_TAGGED_COMMANDS		(1<<4)
-#define TEKRAM_WIDE_NEGO		(1<<5)
-		u_char	sync_index;
-		u_short	word2;
-	} target[16];
-	u_char	host_id;
-	u_char	flags;
-#define TEKRAM_MORE_THAN_2_DRIVES	(1)
-#define TEKRAM_DRIVES_SUP_1GB		(1<<1)
-#define	TEKRAM_RESET_ON_POWER_ON	(1<<2)
-#define TEKRAM_ACTIVE_NEGATION		(1<<3)
-#define TEKRAM_IMMEDIATE_SEEK		(1<<4)
-#define	TEKRAM_SCAN_LUNS		(1<<5)
-#define	TEKRAM_REMOVABLE_FLAGS		(3<<6)	/* 0: disable; 1: boot device; 2:all */
-	u_char	boot_delay_index;
-	u_char	max_tags_index;
-	u_short	flags1;
-#define TEKRAM_F2_F6_ENABLED		(1)
-	u_short	spare[29];
-};
-typedef struct Tekram_nvram	Tekram_nvram;
-typedef struct Tekram_target	Tekram_target;
-
 static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21};
-
 #endif /* SCSI_NCR_NVRAM_SUPPORT */
 
 /*
@@ -927,6 +816,7 @@
 	ncr_slot  slot;
 	ncr_chip  chip;
 	ncr_nvram *nvram;
+	u_char	  host_id;
 	int attach_done;
 } ncr_device;
 
@@ -939,7 +829,6 @@
 
 #define DEBUG_ALLOC    (0x0001)
 #define DEBUG_PHASE    (0x0002)
-#define DEBUG_POLL     (0x0004)
 #define DEBUG_QUEUE    (0x0008)
 #define DEBUG_RESULT   (0x0010)
 #define DEBUG_SCATTER  (0x0020)
@@ -948,8 +837,6 @@
 #define DEBUG_TIMING   (0x0100)
 #define DEBUG_NEGO     (0x0200)
 #define DEBUG_TAGS     (0x0400)
-#define DEBUG_FREEZE   (0x0800)
-#define DEBUG_RESTART  (0x1000)
 
 /*
 **    Enable/Disable debug messages.
@@ -1502,7 +1389,7 @@
 	*/
 	u_char		ia_tag;		/* Allocation index		*/
 	u_char		if_tag;		/* Freeing index		*/
-	u_char cb_tags[SCSI_NCR_MAX_TAGS];	/* Circular tags buffer	*/
+	u_char cb_tags[MAX_TAGS];	/* Circular tags buffer	*/
 	u_char		usetags;	/* Command queuing is active	*/
 	u_char		maxtags;	/* Max nr of tags asked by user	*/
 	u_char		numtags;	/* Current number of tags	*/
@@ -1748,7 +1635,6 @@
 	**----------------------------------------------------------------
 	*/
 	Scsi_Cmnd	*cmd;		/* SCSI command 		*/
-	u_long		tlimit;		/* Deadline for this job	*/
 	int		data_len;	/* Total data length		*/
 
 	/*----------------------------------------------------------------
@@ -3769,7 +3655,8 @@
 **==========================================================
 */
 
-static void __init ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
+static void __init 
+ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
 {
 	ncrcmd  opcode, new, old, tmp1, tmp2;
 	ncrcmd	*start, *end;
@@ -4034,7 +3921,7 @@
 	tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255;
 	tp->usrwide = tn->bus_width == 0x10 ? 1 : 0;
 	tp->usrtags =
-		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SCSI_NCR_MAX_TAGS : 0;
+		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0;
 
 	if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
 		tp->usrflag |= UF_NODISC;
@@ -4229,9 +4116,11 @@
 	/*
 	**  Get SCSI addr of host adapter (set by bios?).
 	*/
-	if (!np->myaddr) np->myaddr = INB(nc_scid) & 0x07;
-	if (!np->myaddr) np->myaddr = SCSI_NCR_MYADDR;
-
+	if (np->myaddr == 255) {
+		np->myaddr = INB(nc_scid) & 0x07;
+		if (!np->myaddr)
+			np->myaddr = SCSI_NCR_MYADDR;
+	}
 
 #endif /* SCSI_NCR_TRUST_BIOS_SETTING */
 
@@ -4241,30 +4130,53 @@
 	ncr_init_burst(np, burst_max);
 
 	/*
-	**	Set differential mode and LED support.
-	**	Ignore these features for boards known to use a 
-	**	specific GPIO wiring (Tekram only for now).
-	**	Probe initial setting of GPREG and GPCNTL for 
-	**	other ones.
-	*/
-	if (!nvram || nvram->type != SCSI_NCR_TEKRAM_NVRAM) {
+	**	Set SCSI BUS mode.
+	**
+	**	- ULTRA2 chips (895/895A/896) report the current 
+	**	  BUS mode through the STEST4 IO register.
+	**	- For previous generation chips (825/825A/875), 
+	**	  user has to tell us how to check against HVD, 
+	**	  since a 100% safe algorithm is not possible.
+	*/
+	np->scsi_mode = SMODE_SE;
+	if	(np->features & FE_ULTRA2)
+		np->scsi_mode = (np->sv_stest4 & SMODE);
+	else if	(np->features & FE_DIFF) {
 		switch(driver_setup.diff_support) {
-		case 3:
+		case 4:	/* Trust previous settings if present, then GPIO3 */
+			if (np->sv_scntl3) {
+				if (np->sv_stest2 & 0x20)
+					np->scsi_mode = SMODE_HVD;
+				break;
+			}
+		case 3:	/* SYMBIOS controllers report HVD through GPIO3 */
+			if (nvram && nvram->type != SCSI_NCR_SYMBIOS_NVRAM)
+				break;
 			if (INB(nc_gpreg) & 0x08)
+				break;
+		case 2:	/* Set HVD unconditionally */
+			np->scsi_mode = SMODE_HVD;
+		case 1:	/* Trust previous settings for HVD */
+			if (np->sv_stest2 & 0x20)
+				np->scsi_mode = SMODE_HVD;
 			break;
-		case 2:
-			np->rv_stest2	|= 0x20;
-			break;
-		case 1:
-			np->rv_stest2	|= (np->sv_stest2 & 0x20);
-			break;
-		default:
+		default:/* Don't care about HVD */	
 			break;
 		}
 	}
+	if (np->scsi_mode == SMODE_HVD)
+		np->rv_stest2 |= 0x20;
+
+	/*
+	**	Set LED support from SCRIPTS.
+	**	Ignore this feature for boards known to use a 
+	**	specific GPIO wiring and for the 895A or 896 
+	**	that drive the LED directly.
+	**	Also probe initial setting of GPIO0 as output.
+	*/
 	if ((driver_setup.led_pin ||
 	     (nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) &&
-	    !(np->sv_gpcntl & 0x01))
+	    !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
 		np->features |= FE_LED0;
 
 	/*
@@ -4314,7 +4226,7 @@
 #endif
 			tp->usrsync = driver_setup.default_sync;
 			tp->usrwide = driver_setup.max_wide;
-			tp->usrtags = SCSI_NCR_MAX_TAGS;
+			tp->usrtags = MAX_TAGS;
 			if (!driver_setup.disconnection)
 				np->target[i].usrflag = UF_NODISC;
 		}
@@ -4498,6 +4410,7 @@
 	np->clock_divn	= device->chip.nr_divisor;
 	np->maxoffs	= device->chip.offset_max;
 	np->maxburst	= device->chip.burst_max;
+	np->myaddr	= device->host_id;
 
 	np->script0  = (struct script *)
 		(((u_long) &host_data->script_data) & CACHE_LINE_MASK);
@@ -4585,6 +4498,7 @@
 	**	Fill Linux host instance structure
 	*/
 	instance->max_channel	= 0;
+	instance->this_id       = np->myaddr;
 	instance->max_id	= np->maxwide ? 16 : 8;
 	instance->max_lun	= SCSI_NCR_MAX_LUN;
 #ifndef NCR_IOMAPPED
@@ -4595,6 +4509,8 @@
 	instance->io_port	= device->slot.io_port;
 	instance->n_io_port	= 128;
 	instance->dma_channel	= 0;
+	instance->cmd_per_lun	= MAX_TAGS;
+	instance->can_queue	= (MAX_START-4);
 	instance->select_queue_depths = ncr53c8xx_select_queue_depths;
 
 	/*
@@ -4876,9 +4792,10 @@
 	**
 	**----------------------------------------------------
 	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ &&
-		np->settle_time > jiffies + cmd->timeout_per_command - HZ) {
-		np->settle_time = jiffies + cmd->timeout_per_command - HZ;
+	if (np->settle_time && cmd->timeout_per_command >= HZ) {
+		u_long tlimit = ktime_get(cmd->timeout_per_command - HZ);
+		if (ktime_dif(np->settle_time, tlimit) > 0)
+			np->settle_time = tlimit;
 	}
 
         if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
@@ -4981,7 +4898,7 @@
 		**	Force ordered tag if necessary to avoid timeouts 
 		**	and to preserve interactivity.
 		*/
-		if (lp && lp->tags_stime + (3*HZ) <= jiffies) {
+		if (lp && ktime_exp(lp->tags_stime)) {
 			if (lp->tags_smap) {
 				order = M_ORDERED_TAG;
 				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ 
@@ -4989,7 +4906,7 @@
 					printk("ordered tag forced.\n");
 				}
 			}
-			lp->tags_stime = jiffies;
+			lp->tags_stime = ktime_get(3*HZ);
 			lp->tags_smap = lp->tags_umap;
 		}
 
@@ -5210,12 +5127,6 @@
 	/*
 	**	activate this job.
 	*/
-
-	/* Compute a time limit greater than the middle-level driver one */
-	if (cmd->timeout_per_command > 0)
-		cp->tlimit	= jiffies + cmd->timeout_per_command + HZ;
-	else
-		cp->tlimit	= jiffies + 86400 * HZ;/* No timeout=24 hours */
 	cp->magic		= CCB_MAGIC;
 
 	/*
@@ -5322,7 +5233,7 @@
 	u_int32 term;
 	int retv = 0;
 
-	np->settle_time	= jiffies + settle_delay * HZ;
+	np->settle_time	= ktime_get(settle_delay * HZ);
 
 	if (bootverbose > 1)
 		printk("%s: resetting, "
@@ -5497,7 +5408,6 @@
 	**	script to abort the command.
 	*/
 
-	cp->tlimit = 0;
 	switch(cp->host_status) {
 	case HS_BUSY:
 	case HS_NEGOTIATE:
@@ -5695,7 +5605,7 @@
 #endif
 
 	if (DEBUG_FLAGS & DEBUG_TINY)
-		printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff,
+		printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp,
 			cp->host_status,cp->scsi_status);
 
 	/*
@@ -6714,7 +6624,7 @@
 
 static void ncr_timeout (ncb_p np)
 {
-	u_long	thistime = jiffies;
+	u_long	thistime = ktime_get(0);
 
 	/*
 	**	If release process in progress, let's go
@@ -6727,7 +6637,7 @@
 		return;
 	}
 
-	np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL;
+	np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
 	add_timer(&np->timer);
 
 	/*
@@ -7021,8 +6931,9 @@
 	**	We are more soft for UDC.
 	**=========================================================
 	*/
-	if (jiffies - np->regtime > 10*HZ) {
-		np->regtime = jiffies;
+
+	if (ktime_exp(np->regtime)) {
+		np->regtime = ktime_get(10*HZ);
 		for (i = 0; i<sizeof(np->regdump); i++)
 			((char*)&np->regdump)[i] = INB_OFF(i);
 		np->regdump.nc_dstat = dstat;
@@ -7138,7 +7049,7 @@
 		**	Suspend command processing for 1 second and 
 		**	reinitialize all except the chip.
 		*/
-		np->settle_time	= jiffies + HZ;
+		np->settle_time	= ktime_get(1*HZ);
 		ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
 		return 1;
 	}
@@ -8258,7 +8169,7 @@
 	if (lp) {
 		if (tag != NO_TAG) {
 			++lp->ia_tag;
-			if (lp->ia_tag == SCSI_NCR_MAX_TAGS)
+			if (lp->ia_tag == MAX_TAGS)
 				lp->ia_tag = 0;
 			lp->tags_umap |= (((tagmap_t) 1) << tag);
 		}
@@ -8306,7 +8217,7 @@
 	if (lp) {
 		if (cp->tag != NO_TAG) {
 			lp->cb_tags[lp->if_tag++] = cp->tag;
-			if (lp->if_tag == SCSI_NCR_MAX_TAGS)
+			if (lp->if_tag == MAX_TAGS)
 				lp->if_tag = 0;
 			lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag);
 			lp->tags_smap &= lp->tags_umap;
@@ -8687,10 +8598,10 @@
 		for (i = 0 ; i < 64 ; i++)
 			lp->jump_ccb[i] =
 				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
-		for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++)
+		for (i = 0 ; i < MAX_TAGS ; i++)
 			lp->cb_tags[i] = i;
-		lp->maxnxs = SCSI_NCR_MAX_TAGS;
-		lp->tags_stime = jiffies;
+		lp->maxnxs = MAX_TAGS;
+		lp->tags_stime = ktime_get(3*HZ);
 	}
 
 	/*
@@ -9208,8 +9119,7 @@
 #define	ARG_SEP	','
 #endif
 
-
-void __init ncr53c8xx_setup(char *str, int *ints)
+int __init ncr53c8xx_setup(char *str)
 {
 #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
 	char *cur = str;
@@ -9293,6 +9203,8 @@
 			if (xi < SCSI_NCR_MAX_EXCLUDES)
 				driver_setup.excludes[xi++] = val;
 		}
+		else if	(!strncmp(cur, "hostid:", 7))
+			driver_setup.host_id	= val;
 		else
 			printk("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 
@@ -9300,8 +9212,15 @@
 			++cur;
 	}
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+	return 0;
 }
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("ncr53c8xx=", ncr53c8xx_setup);
+#endif
+#endif
+
 static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
 	     uchar bus, uchar device_fn, ncr_device *device);
 
@@ -9471,7 +9390,7 @@
 
 #if	defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
 if (ncr53c8xx)
-	ncr53c8xx_setup(ncr53c8xx, (int *) 0);
+	ncr53c8xx_setup(ncr53c8xx);
 #endif
 
 	if (initverbose >= 2)
@@ -9518,6 +9437,7 @@
 #else
 			device[count].nvram = 0;
 #endif
+			device[count].host_id = driver_setup.host_id;
 			if (ncr53c8xx_pci_init(tpnt, bus, device_fn, &device[count])) {
 				device[count].nvram = 0;
 				continue;
@@ -9568,10 +9488,40 @@
 **   Return the offset immediately after the base address that has 
 **   been read. Btw, we blindly assume that the high 32 bits of 64 bit 
 **   base addresses are set to zero on 32 bit architectures.
-**   (the pci generic code now does this for us)
 **
 */
+#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
+static int __init 
+pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base)
+{
+	u_int32 tmp;
 
+	pcibios_read_config_dword(bus, device_fn, offset, &tmp);
+	*base = tmp;
+	offset += sizeof(u_int32);
+	if ((tmp & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+		pcibios_read_config_dword(bus, device_fn, offset, &tmp);
+		*base |= (((u_long)tmp) << 32);
+#endif
+		offset += sizeof(u_int32);
+	}
+	return offset;
+}
+#elif	LINUX_VERSION_CODE <= LinuxVersionCode(2,3,12)
+static int __init 
+pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+{
+	*base = pdev->base_address[index++];
+	if ((*base & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+		*base |= (((u_long)pdev->base_address[index]) << 32);
+#endif
+		++index;
+	}
+	return index;
+}
+#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) */
 static int __init 
 pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
 {
@@ -9580,6 +9530,7 @@
 		++index;
 	return ++index;
 }
+#endif
 
 /*
 **   Read and check the PCI configuration for any detected NCR 
@@ -9587,7 +9538,6 @@
 **   been detected.
 */
 
-
 static int __init ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
 			      uchar bus, uchar device_fn, ncr_device *device)
 {
@@ -9763,6 +9713,9 @@
 	 *	each and every PCI card, if they don't use Fcode?
 	 */
 
+	base = __pa(base);
+	base_2 = __pa(base_2);
+
 	if (!(command & PCI_COMMAND_MASTER)) {
 		if (initverbose >= 2)
 			printk("ncr53c8xx: setting PCI_COMMAND_MASTER bit (fixup)\n");
@@ -9791,7 +9744,7 @@
 	}
 
 	if (!latency_timer) {
-		latency_timer = 64;
+		latency_timer = 128;
 		if (initverbose >= 2)
 			printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer);
 		pcibios_write_config_byte(bus, device_fn,
@@ -9803,8 +9756,6 @@
 
 	/*
 	 * Check availability of IO space, memory space and master capability.
-	 * No need to test BARs flags since they are hardwired to the
-	 * expected value.
 	 */
 	if (command & PCI_COMMAND_IO)
 		io_port &= PCI_BASE_ADDRESS_IO_MASK;
@@ -10094,8 +10045,8 @@
 		device->queue_depth = numtags;
 		if (device->queue_depth < 2)
 			device->queue_depth = 2;
-		if (device->queue_depth > SCSI_NCR_MAX_TAGS)
-			device->queue_depth = SCSI_NCR_MAX_TAGS;
+		if (device->queue_depth > MAX_TAGS)
+			device->queue_depth = MAX_TAGS;
 
 		/*
 		**	Since the queue depth is not tunable under Linux,
@@ -10578,8 +10529,6 @@
 				uc->data |= DEBUG_ALLOC;
 			else if	((arg_len = is_keyword(ptr, len, "phase")))
 				uc->data |= DEBUG_PHASE;
-			else if	((arg_len = is_keyword(ptr, len, "poll")))
-				uc->data |= DEBUG_POLL;
 			else if	((arg_len = is_keyword(ptr, len, "queue")))
 				uc->data |= DEBUG_QUEUE;
 			else if	((arg_len = is_keyword(ptr, len, "result")))
@@ -10596,10 +10545,6 @@
 				uc->data |= DEBUG_NEGO;
 			else if	((arg_len = is_keyword(ptr, len, "tags")))
 				uc->data |= DEBUG_TAGS;
-			else if	((arg_len = is_keyword(ptr, len, "freeze")))
-				uc->data |= DEBUG_FREEZE;
-			else if	((arg_len = is_keyword(ptr, len, "restart")))
-				uc->data |= DEBUG_RESTART;
 			else
 				return -EINVAL;
 			ptr += arg_len; len -= arg_len;
@@ -10715,7 +10660,7 @@
 		                  (u_long) np->reg);
 #endif
 	copy_info(&info, "  Synchronous period factor %d, ", (int) np->minsync);
-	copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS);
+	copy_info(&info, "max commands per lun %d\n", MAX_TAGS);
 
 	if (driver_setup.debug || driver_setup.verbose > 1) {
 		copy_info(&info, "  Debug flags 0x%x, ", driver_setup.debug);
@@ -10892,8 +10837,8 @@
 	nvram_stop(np, &gpreg);
 	
 #ifdef SCSI_NCR_DEBUG_NVRAM
-printk("ncr53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
-	nvram->start_marker,
+printk("ncr53c8xx: NvRAM type=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
+	nvram->type,
 	nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
 	nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
 	nvram->byte_count, sizeof(*nvram) - 12,
@@ -10901,7 +10846,7 @@
 #endif
 
 	/* check valid NVRAM signature, verify byte count and checksum */
-	if (nvram->start_marker == 0 &&
+	if (nvram->type == 0 &&
 	    !memcmp(nvram->trailer, Symbios_trailer, 6) &&
 	    nvram->byte_count == sizeof(*nvram) - 12 &&
 	    csum == nvram->checksum)
@@ -10917,8 +10862,8 @@
 /*
  * Read Symbios NvRAM data and compute checksum.
  */
-static u_short __init nvram_read_data(ncr_slot *np, u_char *data, int len,
-				      u_char *gpreg, u_char *gpcntl)
+static u_short __init 
+nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
 {
 	int	x;
 	u_short	csum;
@@ -10947,9 +10892,8 @@
  * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
  * GPIO0 must already be set as an output
  */
-static void __init nvram_write_byte(ncr_slot *np, u_char *ack_data,
-				    u_char write_data, u_char *gpreg,
-				    u_char *gpcntl)
+static void __init 
+nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
 {
 	int x;
 	
@@ -10963,9 +10907,8 @@
  * READ a byte from the NVRAM and then send an ACK to say we have got it,
  * GPIO0 must already be set as an input
  */
-static void __init nvram_read_byte(ncr_slot *np, u_char *read_data,
-				   u_char ack_data, u_char *gpreg,
-				   u_char *gpcntl)
+static void __init 
+nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
 {
 	int x;
 	u_char read_bit;
@@ -10983,8 +10926,8 @@
  * Output an ACK to the NVRAM after reading,
  * change GPIO0 to output and when done back to an input
  */
-static void __init nvram_writeAck(ncr_slot *np, u_char write_bit,
-				  u_char *gpreg, u_char *gpcntl)
+static void __init 
+nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
 {
 	OUTB (nc_gpcntl, *gpcntl & 0xfe);
 	nvram_doBit(np, 0, write_bit, gpreg);
@@ -10995,8 +10938,8 @@
  * Input an ACK from NVRAM after writing,
  * change GPIO0 to input and when done back to an output
  */
-static void __init nvram_readAck(ncr_slot *np, u_char *read_bit,
-				 u_char *gpreg, u_char *gpcntl)
+static void __init 
+nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
 {
 	OUTB (nc_gpcntl, *gpcntl | 0x01);
 	nvram_doBit(np, read_bit, 1, gpreg);
@@ -11007,8 +10950,7 @@
  * Read or write a bit to the NVRAM,
  * read if GPIO0 input else write if GPIO0 output
  */
-static void __init nvram_doBit(ncr_slot *np, u_char *read_bit,
-			       u_char write_bit, u_char *gpreg)
+static void __init nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
 {
 	nvram_setBit(np, write_bit, gpreg, SET_BIT);
 	nvram_setBit(np, 0, gpreg, SET_CLK);
@@ -11030,8 +10972,8 @@
 /*
  * Set/clear data/clock bit in GPIO0
  */
-static void __init nvram_setBit(ncr_slot *np, u_char write_bit,
-				u_char *gpreg, int bit_mode)
+static void __init 
+nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
 {
 	UDELAY (5);
 	switch (bit_mode){
@@ -11117,8 +11059,8 @@
 /*
  * Read Tekram NvRAM data and compute checksum.
  */
-static u_short __init Tnvram_read_data(ncr_slot *np, u_short *data, int len,
-				       u_char *gpreg)
+static u_short __init 
+Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
 {
 	u_char	read_bit;
 	u_short	csum;
@@ -11143,8 +11085,7 @@
 /*
  * Send read command and address to NVRAM
  */
-static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data,
-				       u_char *read_bit, u_char *gpreg)
+static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
 {
 	int x;
 
@@ -11158,8 +11099,7 @@
 /*
  * READ a byte from the NVRAM
  */
-static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, 
-				    u_char *gpreg)
+static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
 {
 	int x;
 	u_char read_bit;
@@ -11178,8 +11118,8 @@
 /* 
  * Read bit from NVRAM
  */
-static void __init Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit,
-				   u_char *gpreg)
+static void __init 
+Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
 {
 	UDELAY (2);
 	Tnvram_Clk(np, gpreg);
@@ -11189,8 +11129,8 @@
 /*
  * Write bit to GPIO0
  */
-static void __init Tnvram_Write_Bit(ncr_slot *np, u_char write_bit,
-				    u_char *gpreg)
+static void __init 
+Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
 {
 	if (write_bit & 0x01)
 		*gpreg |= 0x02;
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.3.19/linux/drivers/scsi/scsi_ioctl.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/scsi/scsi_ioctl.c	Sat Oct  9 11:24:42 1999
@@ -176,10 +176,38 @@
 }
 
 /*
- * This interface is depreciated - users should use the scsi generics
+ * This interface is depreciated - users should use the scsi generic (sg)
  * interface instead, as this is a more flexible approach to performing
  * generic SCSI commands on a device.
+ *
+ * The structure that we are passed should look like:
+ *
+ * struct sdata {
+ *  unsigned int inlen;	     [i] Length of data to be written to device 
+ *  unsigned int outlen;     [i] Length of data to be read from device 
+ *  unsigned char cmd[x];    [i] SCSI command (6 <= x <= 12).
+ *			     [o] Data read from device starts here.
+ *			     [o] On error, sense buffer starts here.
+ *  unsigned char wdata[y];  [i] Data written to device starts here.
+ * };
+ * Notes:
+ *   -	The SCSI command length is determined by examining the 1st byte
+ *	of the given command. There is no way to override this.
+ *   -	Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha).
+ *   -	The length (x + y) must be at least OMAX_SB_LEN bytes long to
+ *	accomodate the sense buffer when an error occurs.
+ *	The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that
+ *	old code will not be surprised.
+ *   -	If a Unix error occurs (e.g. ENOMEM) then the user will receive
+ *	a negative return and the Unix error code in 'errno'. 
+ *	If the SCSI command succeeds then 0 is returned.
+ *	Positive numbers returned are the compacted SCSI error codes (4 
+ *	bytes in one int) where the lowest byte is the SCSI status.
+ *	See the drivers/scsi/scsi.h file for more information on this.
+ *
  */
+#define OMAX_SB_LEN 16   /* Old sense buffer length */
+
 int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
 {
 	unsigned long flags;
@@ -195,8 +223,6 @@
 
 	if (!sic)
 		return -EINVAL;
-
-
 	/*
 	 * Verify that we can read at least this much.
 	 */
@@ -204,23 +230,13 @@
 	if (result)
 		return result;
 
-	/*
-	 * The structure that we are passed should look like:
-	 *
-	 * struct sdata {
-	 *  unsigned int inlen;
-	 *  unsigned int outlen;
-	 *  unsigned char  cmd[];  # However many bytes are used for cmd.
-	 *  unsigned char  data[];
-	 * };
-	 */
 	get_user(inlen, &sic->inlen);
 	get_user(outlen, &sic->outlen);
 
 	/*
 	 * We do not transfer more than MAX_BUF with this interface.
 	 * If the user needs to transfer more data than this, they
-	 * should use scsi_generics instead.
+	 * should use scsi_generics (sg) instead.
 	 */
 	if (inlen > MAX_BUF)
 		return -EINVAL;
@@ -249,19 +265,16 @@
 	 */
 	cmdlen = COMMAND_SIZE(opcode);
 
-	result = verify_area(VERIFY_READ, cmd_in,
-		    cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
+	result = verify_area(VERIFY_READ, cmd_in, cmdlen + inlen);
 	if (result)
 		return result;
 
-	copy_from_user((void *) cmd, cmd_in, cmdlen);
+	copy_from_user(cmd, cmd_in, cmdlen);
 
 	/*
 	 * Obtain the data to be sent to the device (if any).
 	 */
-	copy_from_user((void *) buf,
-		       (void *) (cmd_in + cmdlen),
-		       inlen);
+	copy_from_user(buf, cmd_in + cmdlen, inlen);
 
 	/*
 	 * Set the lun field to the correct value.
@@ -311,19 +324,18 @@
 	 * If there was an error condition, pass the info back to the user. 
 	 */
 	if (SCpnt->result) {
-		result = verify_area(VERIFY_WRITE,
-				     cmd_in,
-				     sizeof(SCpnt->sense_buffer));
+		int sb_len = sizeof(SCpnt->sense_buffer);
+
+		sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len;
+		result = verify_area(VERIFY_WRITE, cmd_in, sb_len);
 		if (result)
 			return result;
-		copy_to_user((void *) cmd_in,
-			     SCpnt->sense_buffer,
-			     sizeof(SCpnt->sense_buffer));
+		copy_to_user(cmd_in, SCpnt->sense_buffer, sb_len);
 	} else {
 		result = verify_area(VERIFY_WRITE, cmd_in, outlen);
 		if (result)
 			return result;
-		copy_to_user((void *) cmd_in, buf, outlen);
+		copy_to_user(cmd_in, buf, outlen);
 	}
 	result = SCpnt->result;
 
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.3.19/linux/drivers/scsi/sg.c	Mon Jun  7 16:26:25 1999
+++ linux/drivers/scsi/sg.c	Fri Oct  8 10:06:15 1999
@@ -16,41 +16,28 @@
  *
  *  Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
  */
- static char * sg_version_str = "Version: 2.1.34 (990603)";
- static int sg_version_num = 20134; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 2.3.35 (990708)";
+ static int sg_version_num = 20335; /* 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
  *        the kernel/module needs to be built with CONFIG_SCSI_LOGGING
- *        (otherwise the macros compile to empty statements), then do
- *        something like: 'echo "scsi log all" > /proc/scsi/scsi' to log
- *        everything or 'echo "scsi log {token} #N" > /proc/scsi/scsi'
- *        where {token} is one of [error,timeout,scan,mlqueue,mlcomplete,
- *        llqueue,llcomplete,hlqueue,hlcomplete,ioctl] and #N is 0...7
- *        (with 0 meaning off). For example: 'scsi log timeout 7 > 
- *        /proc/scsi/scsi' to get all logging messages from this driver.
- *        Should use hlcomplete but it is too "noisy" (sd uses it).
- *
- *      - This driver obtains memory (heap) for the low-level driver to
- *        transfer/dma to and from. It is obtained from up to 3 sources:
- *              - obtain heap via get_free_pages()
- *              - obtain heap from the shared scsi dma pool
- *              - obtain heap from kernel directly (kmalloc) [last choice]
- *        Each open() attempts to obtain a "reserve" buffer of
- *        SG_DEF_RESERVED_SIZE bytes (or 0 bytes if opened O_RDONLY). The
- *        amount actually obtained [which could be 0 bytes] can be found from
- *        the SG_GET_RESERVED_SIZE ioctl(). This reserved buffer size can
- *        be changed by calling the SG_SET_RESERVED_SIZE ioctl(). Since this
- *        is an ambit claim, it should be followed by a SG_GET_RESERVED_SIZE
- *        ioctl() to find out how much was actually obtained.
- *        A subsequent write() to this file descriptor will use the
- *        reserved buffer unless:
- *              - it is already in use (eg during command queuing)
- *              - or the write() needs a buffer size larger than the
- *                reserved size
- *        In these cases the write() will attempt to get the required memory
- *        for the duration of this request but, if memory is low, it may
- *        fail with ENOMEM.
+ *        (otherwise the macros compile to empty statements). 
+ *        Then before running the program to be debugged enter: 
+ *          # echo "scsi log timeout 7" > /proc/scsi/scsi 
+ *        This will send copious output to the console and the log which
+ *        is usually /var/log/messages. To turn off debugging enter:
+ *          # echo "scsi log timeout 0" > /proc/scsi/scsi 
+ *        The 'timeout' token was chosen because it is relatively unused.
+ *        The token 'hlcomplete' should be used but that triggers too
+ *        much output from the sd device driver. To dump the current
+ *        state of the SCSI mid level data structures enter:
+ *          # echo "scsi dump 1" > /proc/scsi/scsi 
+ *        To dump the state of sg's data structures get the 'sg_debug'
+ *        program from the utilities and enter:
+ *          # sg_debug /dev/sga 
+ *        or any valid sg device name. The state of _all_ sg devices
+ *        will be sent to the console and the log.
  *
  *      - The 'alt_address' field in the scatter_list structure and the
  *        related 'mem_src' indicate the source of the heap allocation.
@@ -146,7 +133,8 @@
 {
     struct sg_fd * nextfp; /* NULL when last opened fd on this device */
     struct sg_device * parentdp;     /* owning device */
-    wait_queue_head_t read_wait;   /* queue read until command done */
+    wait_queue_head_t read_wait;     /* queue read until command done */
+    wait_queue_head_t write_wait;    /* write waits on pending read */
     int timeout;                     /* defaults to SG_DEFAULT_TIMEOUT */
     Sg_scatter_hold reserve;  /* buffer held for this file descriptor */
     unsigned save_scat_len;   /* original length of trunc. scat. element */
@@ -160,7 +148,7 @@
     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
     char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */
     char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */
-} Sg_fd; /* 1208 bytes long on i386 */
+} Sg_fd; /* 1212 bytes long on i386 */
 
 typedef struct sg_device /* holds the state of each scsi generic device */
 {
@@ -212,7 +200,6 @@
 static const int size_sg_header = sizeof(struct sg_header);
 
 
-
 static int sg_open(struct inode * inode, struct file * filp)
 {
     int dev = MINOR(inode->i_rdev);
@@ -360,6 +347,8 @@
         count = (srp->header.result == 0) ? 0 : -EIO;
         sg_finish_rem_req(srp, NULL, 0);
     }
+    if (! sfp->cmd_q)
+        wake_up_interruptible(&sfp->write_wait);
     return count;
 }
 
@@ -391,10 +380,21 @@
     if (count < (size_sg_header + 6))
         return -EIO;   /* The minimum scsi command length is 6 bytes. */ 
 
-    srp = sg_add_request(sfp);
-    if (! srp) {
-        SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full, domain error\n"));
-        return -EDOM;
+    if (! (srp = sg_add_request(sfp))) {
+        if (sfp->cmd_q) {
+            SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n"));
+            return -EDOM;
+        }
+        else { /* old semantics: wait for pending read() to finish */
+            if (filp->f_flags & O_NONBLOCK)
+                return -EAGAIN;
+            k = 0;
+            __wait_event_interruptible(sfp->write_wait, 
+                                   (srp = sg_add_request(sfp)),
+                                   k);
+            if (k)
+                return k; /* -ERESTARTSYS because signal hit process */
+        }
     }
     __copy_from_user(&srp->header, buf, size_sg_header); 
     buf += size_sg_header;
@@ -404,7 +404,7 @@
         if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
             SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
             sfp->next_cmd_len = 0;
-            return -EDOM;
+            return -EIO;
         }
         cmd_size = sfp->next_cmd_len;
         sfp->next_cmd_len = 0; /* reset so only this write() effected */
@@ -490,7 +490,12 @@
     switch(cmd_in)
     {
     case SG_SET_TIMEOUT:
-        return get_user(sfp->timeout, (int *)arg);
+        result =  get_user(val, (int *)arg);
+        if (result) return result;
+        if (val < 0)
+            return -EIO;
+        sfp->timeout = val;
+        return 0;
     case SG_GET_TIMEOUT:  /* N.B. User receives timeout as return value */
         return sfp->timeout; /* strange ..., for backward compatibility */
     case SG_SET_FORCE_LOW_DMA:
@@ -519,9 +524,12 @@
             __put_user((int)sdp->device->id, &sg_idp->scsi_id);
             __put_user((int)sdp->device->lun, &sg_idp->lun);
             __put_user((int)sdp->device->type, &sg_idp->scsi_type);
+            __put_user((short)sdp->device->host->cmd_per_lun, 
+                       &sg_idp->h_cmd_per_lun);
+            __put_user((short)sdp->device->queue_depth, 
+                       &sg_idp->d_queue_depth);
             __put_user(0, &sg_idp->unused1);
             __put_user(0, &sg_idp->unused2);
-            __put_user(0, &sg_idp->unused3);
             return 0;
         }
     case SG_SET_FORCE_PACK_ID:
@@ -605,6 +613,13 @@
         return put_user(sg_version_num, (int *)arg);
     case SG_EMULATED_HOST:
         return put_user(sdp->device->host->hostt->emulated, (int *)arg);
+    case SG_SCSI_RESET:
+        if (! scsi_block_when_processing_errors(sdp->device))
+            return -EBUSY;
+        result = get_user(val, (int *)arg);
+        if (result) return result;
+        /* Don't do anything till scsi mod level visibility */
+        return 0;
     case SCSI_IOCTL_SEND_COMMAND:
         /* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
            user already has read/write access to the generic device and so
@@ -686,6 +701,9 @@
     Sg_fd * sfp;
     Sg_request * srp = NULL;
     int closed = 0;
+    static const int min_sb_len = 
+                SG_MAX_SENSE > sizeof(SCpnt->sense_buffer) ? 
+                        sizeof(SCpnt->sense_buffer) : SG_MAX_SENSE;
 
     if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) {
         SCSI_LOG_TIMEOUT(1, printk("sg__done: bad args dev=%d\n", dev));
@@ -727,8 +745,7 @@
 
     SCSI_LOG_TIMEOUT(4, printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n", 
                 dev, (int)status_byte(SCpnt->result), (int)SCpnt->result));
-    memcpy(srp->header.sense_buffer, SCpnt->sense_buffer,
-           sizeof(SCpnt->sense_buffer));
+    memcpy(srp->header.sense_buffer, SCpnt->sense_buffer, min_sb_len);
     switch (host_byte(SCpnt->result)) 
     { /* This setup of 'result' is for backward compatibility and is best
          ignored by the user who should use target, host + driver status */
@@ -1491,13 +1508,15 @@
         return sdp->headfp;
     }
     sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0);
-    if (!sfp)
-	return NULL;
-
-    memset(sfp, 0, sizeof(Sg_fd));
-    sfp->my_mem_src = SG_HEAP_KMAL;
-
-    init_waitqueue_head(&sfp->read_wait);    
+    if (sfp) {
+        memset(sfp, 0, sizeof(Sg_fd));
+        sfp->my_mem_src = SG_HEAP_KMAL;
+        init_waitqueue_head(&sfp->read_wait);
+        init_waitqueue_head(&sfp->write_wait);
+    }
+    else
+        return NULL;
+        
     sfp->timeout = SG_DEFAULT_TIMEOUT;
     sfp->force_packid = SG_DEF_FORCE_PACK_ID;
     sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/sim710.c linux/drivers/scsi/sim710.c
--- v2.3.19/linux/drivers/scsi/sim710.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/sim710.c	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,1605 @@
+/*
+ * sim710.c - Copyright (C) 1999 Richard Hirst <richard@sleepie.demon.co.uk>
+ *
+ *----------------------------------------------------------------------------
+ *  This 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.
+ *----------------------------------------------------------------------------
+ *
+ * MCA card detection code by Trent McNair.
+ *
+ * Various bits of code in this driver have been copied from 53c7,8xx,c,
+ * which is coyright Drew Eckhardt.  The scripts for the SCSI chip are
+ * compiled with the script compiler written by Drew.
+ *
+ * This is a simple driver for the NCR53c710.  More complex drivers
+ * for this chip (e.g. 53c7xx.c) require that the scsi chip be able to
+ * do DMA block moves between memory and on-chip registers, which can
+ * be a problem if those registers are in the I/O address space.  There
+ * can also be problems on hardware where the registers are memory
+ * mapped, if the design is such that memory-to-memory transfers initiated
+ * by the scsi chip cannot access the chip registers.
+ *
+ * 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.  It was initially written for the Tadpole
+ * TP34V VME board which is 68030 based.
+ *
+ * The driver supports boot-time parameters similar to
+ *	sim710=addr:0x9000,irq:15
+ * and insmod parameters similar to
+ *	sim710="addr:0x9000 irq:15"
+ *
+ * The complete list of options are:
+ *
+ * addr:0x9000		Specifies the base I/O port (or address) of the 53C710.
+ * irq:15		Specifies the IRQ number used by the 53c710.
+ * debug:0xffff		Generates lots of debug output.
+ * ignore:0x0a		Makes the driver ignore SCSI IDs 0 and 2.
+ * nodisc:0x70		Prevents disconnects from IDs 6, 5 and 4.
+ * noneg:0x10		Prevents SDTR negotiation on ID 4.
+ *
+ * Current limitations:
+ *
+ * o  Async only
+ * o  Severely lacking in error recovery
+ * o  Auto detection of IRQs and chip addresses only on MCA architectures
+ *
+ */
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
+#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#include <asm/spinlock.h>
+#endif
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/byteorder.h>
+#include <linux/blk.h>
+
+#ifdef CONFIG_TP34V_SCSI
+
+#include <asm/tp34vhw.h>
+#define MEM_MAPPED
+
+#elif defined(CONFIG_MCA)
+
+#define IO_MAPPED
+
+/*
+ * For each known microchannel card using the 53c710 we need a list
+ * of possible IRQ and IO settings, as well as their corresponding
+ * bit assignment in pos[].  This might get cumbersome if there
+ * are more than a few cards (I only know of 2 at this point).
+ */
+
+#define MCA_53C710_IDS { 0x01bb, 0x01ba, 0x004f }
+
+/* CARD ID 01BB and 01BA use the same pos values */
+
+#define MCA_01BB_IO_PORTS { 0x0000, 0x0000, 0x0800, 0x0C00, 0x1000, 0x1400, \
+			    0x1800, 0x1C00, 0x2000, 0x2400, 0x2800, \
+			    0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, \
+			    0x4000, 0x4400, 0x4800, 0x4C00, 0x5000  }
+
+#define MCA_01BB_IRQS { 3, 5, 11, 14 }
+
+/* CARD ID 004f */
+
+#define MCA_004F_IO_PORTS { 0x0000, 0x0200, 0x0300, 0x0400, 0x0500,  0x0600 }
+
+#define MCA_004F_IRQS { 5, 9, 14 }
+
+#else
+
+/* Assume an Intel platform */
+
+#define IO_MAPPED
+
+#endif
+
+#include "scsi.h"
+#include "hosts.h"
+#include "sim710.h"
+
+#include<linux/stat.h>
+
+#define DEBUG
+#undef DEBUG_LIMIT_INTS		/* Define to 10 to hang driver after 10 ints */
+
+/* Debug options available via the "debug:0x1234" parameter		*/
+
+#define DEB_NONE	0x0000	/* Nothing				*/
+#define DEB_HALT	0x0001	/* Detailed trace of chip halt funtion	*/
+#define DEB_REGS	0x0002	/* All chip register read/writes	*/
+#define DEB_SYNC	0x0004	/* Sync/async negotiation		*/
+#define DEB_PMM		0x0008	/* Phase mis-match handling		*/
+#define DEB_INTS	0x0010	/* General interrupt trace		*/
+#define DEB_TOUT	0x0020	/* Selection timeouts			*/
+#define DEB_RESUME	0x0040	/* Resume addresses for the script	*/
+#define DEB_CMND	0x0080	/* Commands and status returned		*/
+#define DEB_FIXUP	0x0100	/* Fixup of scsi addresses		*/
+#define DEB_DISC	0x0200	/* Disconnect/reselect handling		*/
+
+#define DEB_ANY		0xffff	/* Any and all debug options		*/
+
+#ifdef DEBUG
+#define DEB(m,x) if (sim710_debug & m) x
+int sim710_debug = 0;
+#else
+#define DEB(m,x)
+#endif
+
+/* Redefine scsi_done to force renegotiation of (a)sync transfers
+ * following any failed command.
+ */
+
+#define SCSI_DONE(cmd)	{ \
+	DEB(DEB_CMND, printk("scsi%d: Complete %08x\n", \
+		host->host_no, cmd->result)); \
+	if (cmd->result) \
+	    hostdata->negotiate |= (1 << cmd->target); \
+	cmd->scsi_done(cmd); \
+    }
+
+#ifndef offsetof
+#define offsetof(t, m)      ((size_t) (&((t *)0)->m))
+#endif
+
+
+struct proc_dir_entry proc_scsi_sim710 = {
+    PROC_SCSI_SIM710, 6, "sim710",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+#define STATE_INITIALISED	0
+#define STATE_HALTED		1
+#define STATE_IDLE		2
+#define STATE_BUSY		3
+#define STATE_DISABLED		4
+
+#define MAXBOARDS 2	/* Increase this and the sizes of the
+			   arrays below, if you need more.. */
+
+#ifdef MODULE
+
+char *sim710;		/* command line passed by insmod */
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("Simple NCR53C710 driver");
+MODULE_PARM(sim710, "s");
+
+#endif
+
+static int sim710_errors = 0;	/* Count of error interrupts */
+static int sim710_intrs = 0;	/* Count of all interrupts */
+static int ignore_ids = 0;	/* Accept all SCSI IDs */
+static int opt_nodisc = 0;	/* Allow disconnect on all IDs */
+static int opt_noneg = 0;	/* Allow SDTR negotiation on all IDs */
+
+#ifdef CONFIG_TP34V_SCSI
+
+/* Special hardwired case for Tadpole TP34V at the moment, otherwise
+ * boot parameters 'sim710=addr:0x8000,irq:15' (for example) must be given.
+ */
+
+static int no_of_boards = 2;
+
+static unsigned int bases[MAXBOARDS] = {
+	TP34V_SCSI0_BASE, TP34V_SCSI1_BASE
+};
+static unsigned int irq_vectors[MAXBOARDS] = {
+	TP34V_SCSI0_VECTOR, TP34V_SCSI1_VECTOR
+};
+static unsigned int irq_index[MAXBOARDS] = {
+	TP34V_SCSI0_IRQ_INDEX, TP34V_SCSI1_IRQ_INDEX
+};
+
+#else
+
+/* All other cases use boot/module params, or auto-detect */
+
+static int no_of_boards = 0;
+
+static unsigned int bases[MAXBOARDS] = {
+	0
+};
+static unsigned int irq_vectors[MAXBOARDS] = {
+	0
+};
+
+#endif
+
+/* The SCSI Script!!! */
+
+#include "sim710_d.h"
+
+/* Now define offsets in the DSA, as (A_dsa_xxx/4) */
+
+#define DSA_SELECT	(A_dsa_select/4)
+#define DSA_MSGOUT	(A_dsa_msgout/4)
+#define DSA_CMND	(A_dsa_cmnd/4)
+#define DSA_STATUS	(A_dsa_status/4)
+#define DSA_MSGIN	(A_dsa_msgin/4)
+#define DSA_DATAIN	(A_dsa_datain/4)
+#define DSA_DATAOUT	(A_dsa_dataout/4)
+#define DSA_SIZE	(A_dsa_size/4)
+
+#define MAX_SG		128	/* Scatter/Gather elements */
+
+
+#define MAX_MSGOUT	8
+#define MAX_MSGIN	8
+#define MAX_CMND	12
+#define MAX_STATUS	1
+
+struct sim710_hostdata{
+    int state;
+    Scsi_Cmnd * issue_queue;
+    Scsi_Cmnd * running;
+    int chip;
+    u8 negotiate;
+    u8 reselected_identify;
+    u8 msgin_buf[MAX_MSGIN];
+
+    struct sim710_target {
+	Scsi_Cmnd *cur_cmd;
+	u32 resume_offset;
+	u32 data_in_jump;
+	u32 data_out_jump;
+	u32 dsa[DSA_SIZE];		/* SCSI Script DSA area */
+	u8  dsa_msgout[MAX_MSGOUT];
+	u8  dsa_msgin[MAX_MSGIN];
+	u8  dsa_cdb[MAX_CMND];
+	u8  dsa_status[MAX_STATUS];
+    } target[8];
+
+    u32 script[sizeof(SCRIPT)/4] __attribute__ ((aligned (4)));
+};
+
+
+/* Template to request asynchronous transfers */
+
+static const unsigned char async_message[] = {
+    EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 0, 0 /* asynchronous */};
+
+
+static void sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
+static void do_sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
+static __inline__ void run_process_issue_queue(struct sim710_hostdata *);
+static void process_issue_queue (struct sim710_hostdata *, unsigned long flags);
+static int full_reset(struct Scsi_Host * host);
+
+/*
+ * Function: void sim710_setup(char *str, int *ints)
+ */
+
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
+void
+sim710_setup(char *str, int *ints)
+{
+    char *cur = str;
+    char *pc, *pv;
+    int val;
+    int base;
+    int c;
+
+    no_of_boards = 0;
+    while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+	char *pe;
+
+	val = 0;
+	pv = pc;
+	c = *++pv;
+
+	if (c == 'n')
+	    val = 0;
+	else if	(c == 'y')
+	    val = 1;
+	else {
+	    base = 0;
+	    val = (int) simple_strtoul(pv, &pe, base);
+	}
+	if (!strncmp(cur, "addr:", 5)) {
+	    bases[0] = val;
+	    no_of_boards = 1;
+	}
+	else if	(!strncmp(cur, "irq:", 4))
+	    irq_vectors[0] = val;
+	else if	(!strncmp(cur, "ignore:", 7))
+	    ignore_ids = val;
+	else if	(!strncmp(cur, "nodisc:", 7))
+	    opt_nodisc = val;
+	else if	(!strncmp(cur, "noneg:", 6))
+	    opt_noneg = val;
+	else if	(!strncmp(cur, "disabled:", 5)) {
+	    no_of_boards = -1;
+	    return;
+	}
+#ifdef DEBUG
+	else if (!strncmp(cur, "debug:", 6)) {
+	    sim710_debug = val;
+	}
+#endif
+	else
+	    printk("sim710_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
+
+	if ((cur = strchr(cur, ARG_SEP)) != NULL)
+	    ++cur;
+    }
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("sim710=", sim710_setup);
+#endif
+#endif
+
+/*
+ * Function: static const char *sbcl_to_phase (int sbcl)
+ */
+
+static const char *
+sbcl_to_phase (int sbcl) {
+    switch (sbcl & SBCL_PHASE_MASK) {
+    case SBCL_PHASE_DATAIN:
+	return "DATAIN";
+    case SBCL_PHASE_DATAOUT:
+	return "DATAOUT";
+    case SBCL_PHASE_MSGIN:
+	return "MSGIN";
+    case SBCL_PHASE_MSGOUT:
+	return "MSGOUT";
+    case SBCL_PHASE_CMDOUT:
+	return "CMDOUT";
+    case SBCL_PHASE_STATIN:
+	return "STATUSIN";
+    default:
+	return "unknown";
+    }
+}
+
+
+/*
+ * Function: static void disable (struct Scsi_Host *host)
+ */
+
+static void
+disable (struct Scsi_Host *host)
+{
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+	host->hostdata[0];
+
+    hostdata->state = STATE_DISABLED;
+    printk (KERN_ALERT "scsi%d : disabled.  Unload and reload\n",
+		            host->host_no);
+}
+
+
+/*
+ * Function : static int ncr_halt (struct Scsi_Host *host)
+ *
+ * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
+ *
+ * Inputs : host - SCSI chip to halt
+ *
+ * Returns : 0 on success
+ */
+
+static int
+ncr_halt (struct Scsi_Host *host)
+{
+    unsigned long flags;
+    unsigned char istat, tmp;
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+	host->hostdata[0];
+    int stage;
+
+    save_flags(flags);
+    cli();
+    /* Stage 0 : eat all interrupts
+       Stage 1 : set ABORT
+       Stage 2 : eat all but abort interrupts
+       Stage 3 : eat all interrupts
+     */
+    for (stage = 0;;) {
+	if (stage == 1) {
+	    DEB(DEB_HALT, printk("ncr_halt: writing ISTAT_ABRT\n"));
+	    NCR_write8(ISTAT_REG, ISTAT_ABRT);
+	    ++stage;
+	}
+	istat = NCR_read8 (ISTAT_REG);
+	if (istat & ISTAT_SIP) {
+	    DEB(DEB_HALT, printk("ncr_halt: got ISTAT_SIP, istat=%02x\n", istat));
+	    tmp = NCR_read8(SSTAT0_REG);
+	    DEB(DEB_HALT, printk("ncr_halt: got SSTAT0_REG=%02x\n", tmp));
+	} else if (istat & ISTAT_DIP) {
+	    DEB(DEB_HALT, printk("ncr_halt: got ISTAT_DIP, istat=%02x\n", istat));
+	    tmp = NCR_read8(DSTAT_REG);
+	    DEB(DEB_HALT, printk("ncr_halt: got DSTAT_REG=%02x\n", tmp));
+	    if (stage == 2) {
+		if (tmp & DSTAT_ABRT) {
+	    	    DEB(DEB_HALT, printk("ncr_halt: got DSTAT_ABRT, clearing istat\n"));
+		    NCR_write8(ISTAT_REG, 0);
+		    ++stage;
+		} else {
+		    printk(KERN_ALERT "scsi%d : could not halt NCR chip\n",
+			host->host_no);
+		    disable (host);
+	    	}
+    	    }
+	}
+	if (!(istat & (ISTAT_SIP|ISTAT_DIP))) {
+	    if (stage == 0)
+	    	++stage;
+	    else if (stage == 3)
+		break;
+	}
+    }
+    hostdata->state = STATE_HALTED;
+    restore_flags(flags);
+    return 0;
+}
+
+/*
+ * Function : static void sim710_soft_reset (struct Scsi_Host *host)
+ *
+ * Purpose :  perform a soft reset of the NCR53c7xx chip
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ * Preconditions : sim710_init must have been called for this
+ *      host.
+ *
+ */
+
+static void
+sim710_soft_reset (struct Scsi_Host *host)
+{
+    unsigned long flags;
+#ifdef CONFIG_TP34V_SCSI
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+	host->hostdata[0];
+#endif
+
+    save_flags(flags);
+    cli();
+#ifdef CONFIG_TP34V_SCSI
+    tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x80;
+#endif
+    /*
+     * Do a soft reset of the chip so that everything is
+     * reinitialized to the power-on state.
+     *
+     * Basically follow the procedure outlined in the NCR53c700
+     * data manual under Chapter Six, How to Use, Steps Necessary to
+     * Start SCRIPTS, with the exception of actually starting the
+     * script and setting up the synchronous transfer gunk.
+     */
+
+    /* XXX Should we reset the scsi bus here? */
+
+    NCR_write8(SCNTL1_REG, SCNTL1_RST);		/* Reset the bus */
+    udelay(50);
+    NCR_write8(SCNTL1_REG, 0);
+
+    udelay(500);
+
+    NCR_write8(ISTAT_REG, ISTAT_10_SRST);	/* Reset the chip */
+    udelay(50);
+    NCR_write8(ISTAT_REG, 0);
+
+    mdelay(1000);				/* Let devices recover */
+
+    NCR_write8(DCNTL_REG, DCNTL_10_COM | DCNTL_700_CF_3);
+    NCR_write8(CTEST7_REG, CTEST7_10_CDIS|CTEST7_STD);
+    NCR_write8(DMODE_REG, DMODE_10_BL_8 | DMODE_10_FC2);
+    NCR_write8(SCID_REG, 1 << host->this_id);
+    NCR_write8(SBCL_REG, 0);
+    NCR_write8(SXFER_REG, 0);
+    NCR_write8(SCNTL1_REG, SCNTL1_ESR_700);
+    NCR_write8(SCNTL0_REG, SCNTL0_EPC | SCNTL0_EPG_700 | SCNTL0_ARB1 |
+		SCNTL0_ARB2);
+
+    NCR_write8(DIEN_REG, DIEN_700_BF |
+		DIEN_ABRT | DIEN_SSI | DIEN_SIR | DIEN_700_OPC);
+
+    NCR_write8(SIEN_REG_700,
+	    SIEN_PAR | SIEN_700_STO | SIEN_RST | SIEN_UDC | SIEN_SGE | SIEN_MA);
+
+
+#ifdef CONFIG_TP34V_SCSI
+    tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x30 | TP34V_SCSI0n1_IPL;
+#endif
+
+    restore_flags(flags);
+}
+
+
+/*
+ * Function : static void sim710_driver_init (struct Scsi_Host *host)
+ *
+ * Purpose : Initialize internal structures, as required on startup, or
+ *	after a SCSI bus reset.
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ */
+
+static void
+sim710_driver_init (struct Scsi_Host *host)
+{
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+	host->hostdata[0];
+    int i;
+
+    hostdata->running = NULL;
+    memcpy (hostdata->script, SCRIPT, sizeof(SCRIPT));
+    for (i = 0; i < PATCHES; i++)
+	hostdata->script[LABELPATCHES[i]] += virt_to_bus(hostdata->script);
+    patch_abs_32 (hostdata->script, 0, reselected_identify, 
+    	virt_to_bus((void *)&(hostdata->reselected_identify)));
+    patch_abs_32 (hostdata->script, 0, msgin_buf, 
+    	virt_to_bus((void *)&(hostdata->msgin_buf[0])));
+    hostdata->state = STATE_INITIALISED;
+    hostdata->negotiate = 0xff;
+}
+
+
+/* Handle incoming Synchronous data transfer request.  If our negotiate
+ * flag is set then this is a response to our request, otherwise it is
+ * spurious request from the target.  Don't really expect target initiated
+ * SDTRs, because we always negotiate on the first command.  Could still
+ * get them though..
+ * The chip is currently paused with ACK asserted o the last byte of the
+ * SDTR.
+ * resa is the resume address if the message is in response to our outgoing
+ * SDTR.  Only possible on initial identify.
+ * resb is the resume address if the message exchange is initiated by the
+ * target.
+ */
+
+static u32
+handle_sdtr (struct Scsi_Host * host, Scsi_Cmnd * cmd, u32 resa, u32 resb)
+{
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];
+    struct sim710_target *targdata = hostdata->target + cmd->target;
+    u32 resume_offset;
+
+    if (resa && hostdata->negotiate & (1 << cmd->target)) {
+	DEB(DEB_SYNC, printk("scsi%d: Response to host SDTR = %02x %02x\n",
+		host->host_no, hostdata->msgin_buf[3], hostdata->msgin_buf[4]));
+	/* We always issue an SDTR with the identify, so we must issue
+	 * the CDB next.
+	 */
+	resume_offset = resa;
+	hostdata->negotiate &= ~(1 << cmd->target);
+    }
+    else {
+	DEB(DEB_SYNC, printk("scsi%d: Target initiated SDTR = %02x %02x\n",
+		host->host_no, hostdata->msgin_buf[3], hostdata->msgin_buf[4]));
+	memcpy(targdata->dsa_msgout, async_message, sizeof(async_message));
+	targdata->dsa[DSA_MSGOUT] = sizeof(async_message);
+	/* I guess the target could do this anytime; we have to send our
+	 * response, and then continue (sending the CDB if not already done).
+	 */
+	resume_offset = resb;
+    }
+    return resume_offset;
+}
+
+
+/*
+ * Function : static int datapath_residual (Scsi_Host *host)
+ *
+ * Purpose : return residual data count of what's in the chip.
+ *
+ * Inputs : host - SCSI host
+ */
+
+static int
+datapath_residual (struct Scsi_Host *host) {
+    int count, synchronous, sstat;
+    unsigned int ddir;
+
+    count = ((NCR_read8 (DFIFO_REG) & DFIFO_10_BO_MASK) -
+	(NCR_read32 (DBC_REG) & DFIFO_10_BO_MASK)) & DFIFO_10_BO_MASK;
+    synchronous = NCR_read8 (SXFER_REG) & SXFER_MO_MASK;
+    ddir = NCR_read8 (CTEST0_REG_700) & CTEST0_700_DDIR;
+
+    if (ddir) {
+    /* Receive */
+	if (synchronous) 
+	    count += (NCR_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
+	else
+	    if (NCR_read8 (SSTAT1_REG) & SSTAT1_ILF)
+		++count;
+    } else {
+    /* Send */
+	sstat = NCR_read8 (SSTAT1_REG);
+	if (sstat & SSTAT1_OLF)
+	    ++count;
+	if (synchronous && (sstat & SSTAT1_ORF))
+	    ++count;
+    }
+    return count;
+}
+
+
+static u32
+handle_idd (struct Scsi_Host * host, Scsi_Cmnd * cmd)
+{
+    struct sim710_hostdata *hostdata =
+		(struct sim710_hostdata *)host->hostdata[0];
+    struct sim710_target *targdata = hostdata->target + cmd->target;
+    u32 resume_offset = 0, index;
+
+    index = (u32)((u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script);
+
+    switch (index) {
+    case Ent_wait_disc_complete/4 + 2:
+	cmd->result = targdata->dsa_status[0];
+        SCSI_DONE(cmd);
+	targdata->cur_cmd = NULL;
+	resume_offset = Ent_reselect;
+	break;
+    case Ent_wait_disc2/4 + 2:
+	/* Disconnect after command - just wait for a reselect */
+	targdata->resume_offset = Ent_resume_msgin2a;
+	resume_offset = Ent_reselect;
+	break;
+    case Ent_wait_disc3/4 + 2:
+	/* Disconnect after the data phase */
+	targdata->resume_offset = Ent_resume_msgin3a;
+	resume_offset = Ent_reselect;
+	break;
+    case Ent_wait_disc1/4 + 2:
+	/* Disconnect before command - not expected */
+	targdata->resume_offset = Ent_resume_msgin1a;
+	resume_offset = Ent_reselect;
+	break;
+    default:
+	printk("scsi%d: Unexpected Illegal Instruction, script[%04x]\n",
+		host->host_no, index);
+	sim710_errors++;
+	/* resume_offset is zero, which will cause host reset */
+    }
+    return resume_offset;
+}
+
+
+/* Handle a phase mismatch.
+ */
+
+static u32
+handle_phase_mismatch (struct Scsi_Host * host, Scsi_Cmnd * cmd)
+{
+    struct sim710_hostdata *hostdata =
+		(struct sim710_hostdata *)host->hostdata[0];
+    struct sim710_target *targdata = hostdata->target + cmd->target;
+    u32 resume_offset = 0, index;
+    unsigned char sbcl;
+
+    sbcl = NCR_read8(SBCL_REG) & SBCL_PHASE_MASK;
+    index = (u32)((u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script);
+
+    DEB(DEB_PMM, printk("scsi%d: Phase mismatch, phase %s (%x) at script[0x%x]\n",
+	host->host_no, sbcl_to_phase(sbcl), sbcl, index));
+    DEB(DEB_PMM, print_command(cmd->cmnd));
+
+    if (index == Ent_done_ident/4) {
+	/* Sending initial message out - probably rejecting our sync
+	 * negotiation request.
+	 */
+	NCR_write8(SOCL_REG, 0);	/* Negate ATN */
+	if (sbcl == SBCL_PHASE_MSGIN)
+	    resume_offset = Ent_resume_rej_ident;
+	else if (sbcl == SBCL_PHASE_CMDOUT) {
+	    /* Some old devices (SQ555) switch to cmdout after the first
+	     * byte of an identify message, regardless of whether we
+	     * have more bytes to send!
+	     */
+	    printk("scsi%d: Unexpected switch to CMDOUT during IDENTIFY\n",
+		host->host_no);
+	    resume_offset = Ent_resume_cmd;
+	}
+	else {
+	    printk("scsi%d: Unexpected phase change to %s on initial msgout\n",
+		host->host_no, sbcl_to_phase(sbcl));
+	    /* resume_offset is zero, which will cause a host reset */
+	}
+	hostdata->negotiate &= ~(1 << cmd->target);
+    }
+    else if (index > Ent_patch_input_data/4 &&
+		index < Ent_patch_output_data/4) {
+	/* DataIn transfer phase */
+	u32 sg_id, oaddr, olen, naddr, nlen;
+	int residual;
+
+	sg_id = (index - Ent_patch_input_data/4 - 4) / 2;
+	targdata->data_in_jump = hostdata->script[Ent_patch_input_data/4+1] =
+		virt_to_bus(hostdata->script + Ent_patch_input_data/4 + sg_id * 2 + 2);
+	olen  = targdata->dsa[DSA_DATAIN + sg_id * 2];
+	oaddr = targdata->dsa[DSA_DATAIN + sg_id * 2 + 1];
+	residual = datapath_residual (host);
+	if (residual)
+	    printk("scsi%d: Residual count %d on DataIn - NOT expected!!!",
+		host->host_no, residual);
+	naddr = NCR_read32(DNAD_REG) - residual;
+	nlen  = (NCR_read32(DBC_REG) & 0x00ffffff) + residual;
+	DEB(DEB_PMM, printk("scsi%d: DIN sg %d, old %08x/%08x, new %08x/%08x (%d)\n",
+		host->host_no, sg_id, oaddr, olen, naddr, nlen, residual));
+	if (oaddr+olen != naddr+nlen) {
+	    printk("scsi%d: PMM DIN counts error: 0x%x + 0x%x != 0x%x + 0x%x",
+		host->host_no, oaddr, olen, naddr, nlen);
+	}
+	else {
+	    targdata->dsa[DSA_DATAIN + sg_id * 2]     = nlen;
+	    targdata->dsa[DSA_DATAIN + sg_id * 2 + 1] = naddr;
+	    resume_offset = Ent_resume_pmm;
+	}
+    }
+    else if (index > Ent_patch_output_data/4 &&
+		index <= Ent_end_data_trans/4) {
+	/* Dataout transfer phase */
+	u32 sg_id, oaddr, olen, naddr, nlen;
+	int residual;
+
+	sg_id = (index - Ent_patch_output_data/4 - 4) / 2;
+	targdata->data_out_jump = hostdata->script[Ent_patch_output_data/4+1] =
+		virt_to_bus(hostdata->script + Ent_patch_output_data/4 + sg_id * 2 + 2);
+	olen  = targdata->dsa[DSA_DATAOUT + sg_id * 2];
+	oaddr = targdata->dsa[DSA_DATAOUT + sg_id * 2 + 1];
+	residual = datapath_residual (host);
+	naddr = NCR_read32(DNAD_REG) - residual;
+	nlen  = (NCR_read32(DBC_REG) & 0x00ffffff) + residual;
+	DEB(DEB_PMM, printk("scsi%d: DOUT sg %d, old %08x/%08x, new %08x/%08x (%d)\n",
+		host->host_no, sg_id, oaddr, olen, naddr, nlen, residual));
+	if (oaddr+olen != naddr+nlen) {
+	    printk("scsi%d: PMM DOUT counts error: 0x%x + 0x%x != 0x%x + 0x%x",
+		host->host_no, oaddr, olen, naddr, nlen);
+	}
+	else {
+	    targdata->dsa[DSA_DATAOUT + sg_id * 2]     = nlen;
+	    targdata->dsa[DSA_DATAOUT + sg_id * 2 + 1] = naddr;
+	    resume_offset = Ent_resume_pmm;
+	}
+    }
+    else {
+	printk("scsi%d: Unexpected phase change to %s at index 0x%x\n",
+		host->host_no, sbcl_to_phase(sbcl), index);
+	/* resume_offset is zero, which will cause a host reset */
+    }
+    /* Flush DMA FIFO */
+    NCR_write8 (CTEST8_REG, CTEST8_10_CLF);
+    while (NCR_read8 (CTEST8_REG) & CTEST8_10_CLF);
+
+    return resume_offset;
+}
+
+
+static u32
+handle_script_int(struct Scsi_Host * host, Scsi_Cmnd * cmd)
+{
+    struct sim710_hostdata *hostdata =
+		(struct sim710_hostdata *)host->hostdata[0];
+    struct sim710_target *targdata = hostdata->target + cmd->target;
+    u32 dsps, resume_offset = 0;
+    unsigned char sbcl;
+
+    dsps = NCR_read32(DSPS_REG);
+
+    switch (dsps) {
+    case A_int_cmd_complete:
+	cmd->result = targdata->dsa_status[0];
+        SCSI_DONE(cmd);
+	targdata->cur_cmd = NULL;
+	resume_offset = Ent_reselect;
+	break;
+    case A_int_msg_sdtr1:
+	resume_offset = handle_sdtr(host, cmd,
+		Ent_resume_msgin1a, Ent_resume_msgin1b);
+	break;
+    case A_int_msg_sdtr2:
+	resume_offset = handle_sdtr(host, cmd, 0, Ent_resume_msgin2b);
+	break;
+    case A_int_msg_sdtr3:
+	resume_offset = handle_sdtr(host, cmd, 0, Ent_resume_msgin3b);
+	break;
+    case A_int_disc1:
+	/* Disconnect before command - not expected */
+	targdata->resume_offset = Ent_resume_msgin1a;
+	resume_offset = Ent_reselect;
+	break;
+    case A_int_disc2:
+	/* Disconnect after command - just wait for a reselect */
+	targdata->resume_offset = Ent_resume_msgin2a;
+	resume_offset = Ent_reselect;
+	break;
+    case A_int_disc3:
+	/* Disconnect after the data phase */
+	targdata->resume_offset = Ent_resume_msgin3a;
+	resume_offset = Ent_reselect;
+	break;
+    case A_int_reselected:
+	hostdata->script[Ent_patch_output_data/4+1] = targdata->data_out_jump;
+	hostdata->script[Ent_patch_input_data/4+1] = targdata->data_in_jump;
+	NCR_write32(DSA_REG, virt_to_bus(targdata->dsa));
+	resume_offset = targdata->resume_offset;
+	break;
+    case A_int_data_bad_phase:
+	sbcl = NCR_read8(SBCL_REG) & SBCL_PHASE_MASK;
+	printk("scsi%d: int_data_bad_phase, phase %s (%x)\n",
+		host->host_no, sbcl_to_phase(sbcl), sbcl);
+	break;
+    case A_int_bad_extmsg1a:
+    case A_int_bad_extmsg1b:
+    case A_int_bad_extmsg2a:
+    case A_int_bad_extmsg2b:
+    case A_int_bad_extmsg3a:
+    case A_int_bad_extmsg3b:
+    case A_int_bad_msg1:
+    case A_int_bad_msg2:
+    case A_int_bad_msg3:
+    case A_int_cmd_bad_phase:
+    case A_int_no_msgout1:
+    case A_int_no_msgout2:
+    case A_int_no_msgout3:
+    case A_int_not_cmd_complete:
+    case A_int_sel_no_ident:
+    case A_int_sel_not_cmd:
+    case A_int_status_not_msgin:
+    case A_int_resel_not_msgin:
+    case A_int_selected:
+    case A_int_not_rej:
+    default:
+	sbcl = NCR_read8(SBCL_REG) & SBCL_PHASE_MASK;
+	printk("scsi%d: Unimplemented script interrupt: %08x, phase %s\n",
+		host->host_no, dsps, sbcl_to_phase(sbcl));
+	sim710_errors++;
+	/* resume_offset is zero, which will cause a host reset */
+    }
+    return resume_offset;
+}
+
+
+/* A quick wrapper for sim710_intr_handle to grab the spin lock */
+
+static void
+do_sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    sim710_intr_handle(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+
+/* A "high" level interrupt handler */
+
+static void
+sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned int flags;
+    struct Scsi_Host * host = (struct Scsi_Host *)dev_id;
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];
+    Scsi_Cmnd * cmd;
+    unsigned char istat, dstat;
+    unsigned char sstat0;
+    u32 dsps, resume_offset = 0;
+
+    save_flags(flags);
+    cli();
+    sim710_intrs++;
+    while ((istat = NCR_read8(ISTAT_REG)) & (ISTAT_SIP|ISTAT_DIP)) {
+	dsps = NCR_read32(DSPS_REG);
+	hostdata->state = STATE_HALTED;
+	sstat0 = dstat = 0;
+	if (istat & ISTAT_SIP) {
+	    sstat0 = NCR_read8(SSTAT0_REG);
+	}
+	if (istat & ISTAT_DIP) {
+	    udelay(10);		/* Some comment somewhere about 10cycles
+				 * between accesses to sstat0 and dstat ??? */
+	    dstat = NCR_read8(DSTAT_REG);
+	}
+	DEB(DEB_INTS, printk("scsi%d: Int %d, istat %02x, sstat0 %02x "
+		"dstat %02x, dsp [%04x], scratch %02x\n",
+	    host->host_no, sim710_intrs, istat, sstat0, dstat,
+	    (u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script,
+	    NCR_read32(SCRATCH_REG)));
+	if ((dstat & DSTAT_SIR) && dsps == A_int_reselected) {
+	    /* Reselected.  Identify the target from LCRC_REG, and
+	     * update current command.  If we were trying to select
+	     * a device, then that command needs to go back on the
+	     * issue_queue for later.
+	     */
+	    unsigned char lcrc = NCR_read8(LCRC_REG_10);
+	    int id = 0;
+
+	    if (!(lcrc & 0x7f)) {
+		printk("scsi%d: Reselected with LCRC = %02x\n",
+			host->host_no, lcrc);
+		cmd = NULL;
+	    }
+	    else {
+		while (!(lcrc & 1)) {
+		    id++;
+		    lcrc >>= 1;
+		}
+		DEB(DEB_DISC, printk("scsi%d: Reselected by ID %d\n",
+			host->host_no, id));
+		if (hostdata->running) {
+		    /* Clear SIGP */
+		    (void)NCR_read8(CTEST2_REG_700);
+
+		    DEB(DEB_DISC, printk("scsi%d: Select of %d interrupted "
+				"by reselect from %d (%p)\n",
+				host->host_no, hostdata->running->target,
+				id, hostdata->target[id].cur_cmd));
+		    cmd = hostdata->running;
+		    hostdata->target[cmd->target].cur_cmd = NULL;
+		    cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
+		    hostdata->issue_queue = cmd;
+		}
+		cmd = hostdata->running = hostdata->target[id].cur_cmd;
+	    }
+	}
+	else
+	    cmd = hostdata->running;
+
+	if (!cmd) {
+	    printk("scsi%d: No active command!\n", host->host_no);
+	    printk("scsi%d: Int %d, istat %02x, sstat0 %02x "
+		"dstat %02x, dsp [%04x], scratch %02x, dsps %08x\n",
+		host->host_no, sim710_intrs, istat, sstat0, dstat,
+		(u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script,
+		NCR_read32(SCRATCH_REG), dsps);
+	    /* resume_offset is zero, which will cause a host reset */
+	}
+	else if (sstat0 & SSTAT0_700_STO) {
+	    DEB(DEB_TOUT, printk("scsi%d: Selection timeout\n", host->host_no));
+	    cmd->result = DID_NO_CONNECT << 16;
+	    SCSI_DONE(cmd);
+	    hostdata->target[cmd->target].cur_cmd = NULL;
+	    resume_offset = Ent_reselect;
+	}
+	else if (dstat & DSTAT_SIR)
+	    resume_offset = handle_script_int(host, cmd);
+	else if (sstat0 & SSTAT0_MA) {
+	    resume_offset = handle_phase_mismatch(host, cmd);
+	}
+	else if (sstat0 & (SSTAT0_MA|SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) {
+	    printk("scsi%d: Serious error, sstat0 = %02x\n", host->host_no,
+			    sstat0);
+	    sim710_errors++;
+	    /* resume_offset is zero, which will cause a host reset */
+	}
+	else if (dstat & (DSTAT_BF|DSTAT_ABRT|DSTAT_SSI|DSTAT_WTD)) {
+	    printk("scsi%d: Serious error, dstat = %02x\n", host->host_no,
+			    dstat);
+	    sim710_errors++;
+	    /* resume_offset is zero, which will cause a host reset */
+	}
+	else if (dstat & DSTAT_IID) {
+	    /* This can be due to a quick reselect while doing a WAIT
+	     * DISCONNECT.
+	     */
+	    resume_offset = handle_idd(host, cmd);
+	}
+	else {
+	    sim710_errors++;
+	    printk("scsi%d: Spurious interrupt!\n", host->host_no);
+	    /* resume_offset is zero, which will cause a host reset */
+	}
+    }
+
+    if (resume_offset) {
+	if (resume_offset == Ent_reselect) {
+	    hostdata->running = NULL;
+	    hostdata->state = STATE_IDLE;
+	}
+	else
+	    hostdata->state = STATE_BUSY;
+	DEB(DEB_RESUME, printk("scsi%d: Resuming at script[0x%x]\n",
+		host->host_no, resume_offset/4));
+#ifdef DEBUG_LIMIT_INTS
+	if (sim710_intrs < DEBUG_LIMIT_INTS)
+#endif
+	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+resume_offset/4));
+	if (resume_offset == Ent_reselect)
+	    run_process_issue_queue(hostdata);
+    }
+    else {
+	printk("scsi%d: Failed to handle interrupt.  Failing commands "
+		"and resetting SCSI bus and chip\n", host->host_no);
+	mdelay(4000);		/* Give chance to read screen!! */
+	full_reset(host);
+    }
+
+    restore_flags(flags);
+}
+
+
+static void
+run_command (struct sim710_hostdata *hostdata, Scsi_Cmnd *cmd)
+{
+    struct Scsi_Host *host = cmd->host;
+    struct sim710_target *targdata = hostdata->target + cmd->target;
+    int i, datain, dataout, sg_start;
+    u32 *dip, *dop, dsa;
+
+    DEB(DEB_CMND, printk("scsi%d: id%d starting ", host->host_no,
+		cmd->target));
+    DEB(DEB_CMND, print_command(cmd->cmnd));
+
+    switch (cmd->cmnd[0]) {
+    case INQUIRY:
+    case MODE_SENSE:
+    case READ_6:
+    case READ_10:
+    case READ_CAPACITY:
+    case REQUEST_SENSE:
+    case READ_BLOCK_LIMITS:
+    case READ_TOC:
+        datain = 1;
+	dataout = 0;
+        break;
+    case MODE_SELECT:
+    case WRITE_6:
+    case WRITE_10:
+        datain = 0;
+        dataout = 1;
+        break;
+    case TEST_UNIT_READY:
+    case ALLOW_MEDIUM_REMOVAL:
+    case START_STOP:
+        datain = dataout = 0;
+        break;
+    default:
+        datain = dataout = 1;
+    }
+
+    memcpy(targdata->dsa_cdb, cmd->cmnd, MAX_CMND);
+
+    targdata->dsa_msgout[0] =
+		IDENTIFY((opt_nodisc & (1<<cmd->target)) ? 0 : 1 ,0);
+    if (hostdata->negotiate & (1 << cmd->target)) {
+	if (opt_noneg & (1 << cmd->target)) {
+	    hostdata->negotiate ^= (1 << cmd->target);
+	    targdata->dsa[DSA_MSGOUT] = 1;
+	}
+	else {
+	    DEB(DEB_SYNC, printk("scsi%d: Negotiating async transfers "
+		"for ID %d\n",
+		host->host_no, cmd->target));
+	    memcpy(targdata->dsa_msgout+1, async_message, sizeof(async_message));
+	    targdata->dsa[DSA_MSGOUT] = sizeof(async_message) + 1;
+	}
+    }
+    else
+	targdata->dsa[DSA_MSGOUT] = 1;
+
+    targdata->dsa_msgin[0] = 0xff;
+    targdata->dsa_status[0] = 0xff;
+
+    targdata->dsa[DSA_SELECT]		= (1 << cmd->target) << 16;
+    targdata->dsa[DSA_MSGOUT+1]		= virt_to_bus(targdata->dsa_msgout);
+    targdata->dsa[DSA_CMND]		= cmd->cmd_len;
+    targdata->dsa[DSA_CMND+1]		= virt_to_bus(targdata->dsa_cdb);
+    targdata->dsa[DSA_STATUS]		= 1;
+    targdata->dsa[DSA_STATUS+1]		= virt_to_bus(targdata->dsa_status);
+    targdata->dsa[DSA_MSGIN]		= 1;
+    targdata->dsa[DSA_MSGIN+1]		= virt_to_bus(targdata->dsa_msgin);
+
+    sg_start = (MAX_SG - (cmd->use_sg ? cmd->use_sg : 1)) * 2;
+    dip = targdata->dsa + DSA_DATAIN + sg_start;
+    dop = targdata->dsa + DSA_DATAOUT + sg_start;
+
+    for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; i++) {
+	u32 vbuf = cmd->use_sg ?
+		(u32)(((struct scatterlist *)cmd->buffer)[i].address) :
+		(u32)(cmd->request_buffer);
+	u32 bbuf = virt_to_bus((void *)vbuf);
+	u32 cnt = cmd->use_sg ?
+		((struct scatterlist *)cmd->buffer)[i].length :
+		cmd->request_bufflen;
+
+	if (datain) {
+#ifdef CONFIG_TP34V_SCSI
+	    cache_clear(virt_to_phys((void *)vbuf), cnt);
+#endif
+	    *dip++	= cnt;
+	    *dip++	= bbuf;
+	}
+	if (dataout) {
+#ifdef CONFIG_TP34V_SCSI
+	    cache_push(virt_to_phys((void *)vbuf), cnt);
+#endif
+	    *dop++	= cnt;
+	    *dop++	= bbuf;
+	}
+    }
+    targdata->data_out_jump = hostdata->script[Ent_patch_output_data/4+1] =
+	virt_to_bus(hostdata->script + Ent_patch_output_data/4 + sg_start + 2);
+    targdata->data_in_jump = hostdata->script[Ent_patch_input_data/4+1] =
+	virt_to_bus(hostdata->script + Ent_patch_input_data/4 + sg_start + 2);
+
+    for (i = 0, dsa = virt_to_bus(targdata->dsa); i < 4; i++) {
+	u32 v = hostdata->script[Ent_patch_new_dsa/4 + i * 2];
+
+	v &= ~0x0000ff00;
+	v |= (dsa & 0xff) << 8;
+	hostdata->script[Ent_patch_new_dsa/4 + i * 2] = v;
+	dsa >>= 8;
+    }
+    hostdata->running = targdata->cur_cmd = cmd;
+    hostdata->state = STATE_BUSY;
+
+    NCR_write8(ISTAT_REG, ISTAT_10_SIGP);
+}
+
+
+static volatile int process_issue_queue_running = 0;
+ 
+static __inline__ void 
+run_process_issue_queue(struct sim710_hostdata *hostdata)
+{
+    unsigned long flags;
+    save_flags (flags);
+    cli();
+    if (!process_issue_queue_running) {
+	process_issue_queue_running = 1;
+	process_issue_queue(hostdata, flags);
+	/*
+	 * process_issue_queue_running is cleared in process_issue_queue
+	 * once it can't do more work, and process_issue_queue exits with
+	 * interrupts disabled.
+	 */
+    }
+    restore_flags (flags);
+}
+
+
+/*
+ * Function : process_issue_queue (hostdata, flags)
+ *
+ * Purpose : Start next command for any idle target.
+ * 
+ * NOTE : process_issue_queue exits with interrupts *disabled*, so the 
+ *	caller must reenable them if it desires.
+ * 
+ * NOTE : process_issue_queue should be called from both 
+ *	sim710_queue_command() and from the interrupt handler 
+ *	after command completion.
+ */
+
+static void 
+process_issue_queue (struct sim710_hostdata *hostdata, unsigned long flags)
+{
+    Scsi_Cmnd *tmp, *prev;
+    int done;
+
+    /*
+     * We run (with interrupts disabled) until we're sure that none of 
+     * the host adapters have anything that can be done, at which point 
+     * we set process_issue_queue_running to 0 and exit.
+     *
+     * Interrupts are enabled before doing various other internal 
+     * instructions, after we've decided that we need to run through
+     * the loop again.
+     *
+     */
+
+    do {
+	cli(); /* Freeze request queues */
+	done = 1;
+	if (hostdata->issue_queue) {
+	    if (hostdata->state == STATE_DISABLED) {
+		tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+		hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
+		tmp->result = (DID_BAD_TARGET << 16);
+		tmp->scsi_done (tmp);
+		done = 0;
+	    }
+	    else if (hostdata->state == STATE_IDLE) {
+		for (tmp = hostdata->issue_queue, prev = NULL; tmp;
+				prev = tmp, tmp = (Scsi_Cmnd *) tmp->SCp.ptr) {
+		    if (hostdata->target[tmp->target].cur_cmd == NULL) {
+			if (prev)
+			    prev->SCp.ptr = tmp->SCp.ptr;
+			else
+			    hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
+			tmp->SCp.ptr = NULL;
+			run_command (hostdata, tmp);
+			done = 0;
+		    } /* if target/lun is not busy */
+		} /* scan issue queue for work */
+	    } /* host is idle */
+	} /* if hostdata->issue_queue */
+	if (!done)
+	    restore_flags (flags);
+    } while (!done);
+    process_issue_queue_running = 0;
+}
+
+
+int
+sim710_queuecommand(Scsi_Cmnd * cmd, void (*done)(Scsi_Cmnd *))
+{
+    struct Scsi_Host *host = cmd->host;
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];
+    Scsi_Cmnd *tmp;
+    unsigned long flags;
+
+    if (cmd->lun) {
+	/* Silently ignore luns other than zero! */
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	return 0;
+    }
+
+    DEB(DEB_CMND, printk("scsi%d: id%d queuing ", host->host_no,
+		cmd->target));
+    DEB(DEB_CMND, print_command(cmd->cmnd));
+
+    cmd->scsi_done = done;
+    cmd->host_scribble = NULL;
+    cmd->SCp.ptr = NULL;
+    cmd->SCp.buffer = NULL;
+
+    save_flags(flags);
+    cli();
+
+    if (ignore_ids & (1 << cmd->target)) {
+	printk("scsi%d: ignoring target %d\n", host->host_no, cmd->target);
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	restore_flags (flags);
+	return 0;
+    }
+#ifdef DEBUG_LIMIT_INTS
+    if (sim710_intrs > DEBUG_LIMIT_INTS) {
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	restore_flags (flags);
+	return 0;
+    }
+#endif
+    if (cmd->use_sg > MAX_SG)
+	panic ("cmd->use_sg = %d\n", cmd->use_sg);
+
+    if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+        cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
+        hostdata->issue_queue = cmd;
+    } else {
+        for (tmp = hostdata->issue_queue; tmp->SCp.ptr;
+                tmp = (Scsi_Cmnd *) tmp->SCp.ptr);
+        tmp->SCp.ptr = (unsigned char *) cmd;
+    }
+    restore_flags (flags);
+    run_process_issue_queue(hostdata);
+    return 0;
+}
+
+
+int
+sim710_detect(Scsi_Host_Template * tpnt)
+{
+    unsigned char irq_vector;
+    unsigned char scsi_id;
+    unsigned int base_addr;
+    struct Scsi_Host * host = NULL;
+    struct sim710_hostdata *hostdata;
+    int chips = 0;
+    int indx;
+    int revision;
+    int order, size;
+
+#ifdef MODULE
+    if (sim710)
+	sim710_setup(sim710, (int *)0);
+#endif
+
+    if (no_of_boards < 0) {
+	printk("sim710: NCR53C710 driver disabled\n");
+	return 0;
+    }
+
+#ifdef CONFIG_MCA
+    /* If board details have been specified via boot/module parameters,
+     * then don't bother probing.
+     */
+    if (no_of_boards == 0) {
+	int slot;
+	int pos[3];
+	int mca_53c710_ids[] = MCA_53C710_IDS;
+	int *id_to_check = mca_53c710_ids;
+	static int io_004f_by_pos[] = MCA_004F_IO_PORTS;
+	static int irq_004f_by_pos[] = MCA_004F_IRQS;
+	static int io_01bb_by_pos[] = MCA_01BB_IO_PORTS;
+	static int irq_01bb_by_pos[] = MCA_01BB_IRQS;
+
+	while ( *id_to_check && no_of_boards < MAXBOARDS) {
+	    if (!MCA_bus)
+		return 0;
+
+	    if ((slot = mca_find_adapter(*id_to_check, 0)) != MCA_NOTFOUND) {
+
+		pos[0] = mca_read_stored_pos(slot, 2);
+		pos[1] = mca_read_stored_pos(slot, 3);
+		pos[2] = mca_read_stored_pos(slot, 4);
+
+		/*
+		 * 01BB & 01BA port base by bits 7,6,5,4,3,2 in pos[2]
+		 *
+		 *    000000  <disabled>   001010  0x2800
+		 *    000001  <invalid>    001011  0x2C00
+		 *    000010  0x0800       001100  0x3000
+		 *    000011  0x0C00       001101  0x3400
+		 *    000100  0x1000       001110  0x3800
+		 *    000101  0x1400       001111  0x3C00
+		 *    000110  0x1800       010000  0x4000
+		 *    000111  0x1C00       010001  0x4400
+		 *    001000  0x2000       010010  0x4800
+		 *    001001  0x2400       010011  0x4C00
+		 *                         010100  0x5000
+		 *
+		 * 00F4 port base by bits 3,2,1 in pos[0]
+		 *
+		 *    000  <disabled>      001    0x200
+		 *    010  0x300           011    0x400
+		 *    100  0x500           101    0x600
+		 *
+		 * 01BB & 01BA IRQ is specified in pos[0] bits 7 and 6:
+		 *
+		 *    00   3               10   11
+		 *    01   5               11   14
+		 *
+		 * 00F4 IRQ specified by bits 6,5,4 in pos[0]
+		 *
+		 *    100   5              101    9
+		 *    110   14
+		 */
+
+		if ( *id_to_check == 0x01bb || *id_to_check == 0x01ba ) {
+		    bases[no_of_boards] = io_01bb_by_pos[(pos[2] & 0xFC) >> 2];
+		    irq_vectors[no_of_boards] =
+				irq_01bb_by_pos[((pos[0] & 0xC0) >> 6)];
+		    if (bases[no_of_boards] == 0x0000)
+			printk("sim710: NCR53C710 Adapter ID 0x01bb is disabled.\n");
+		    else {
+			no_of_boards++;
+			if ( *id_to_check == 0x01bb )
+			    mca_set_adapter_name( slot,
+				    "NCR 3360/3430 SCSI SubSystem" );
+			else
+			    mca_set_adapter_name(slot,
+				    "NCR Dual SIOP SCSI Host Adapter Board");
+		    }
+		}
+		else if ( *id_to_check == 0x004f ) {
+		    bases[no_of_boards] = io_004f_by_pos[((pos[0] & 0x0E) >> 1)];
+		    irq_vectors[no_of_boards] =
+				irq_004f_by_pos[((pos[0] & 0x70) >> 4) - 4];
+		    if (bases[no_of_boards] == 0x0000)
+			printk("sim710: NCR53C710 Adapter ID 0x004f is disabled.\n");
+		    else {
+			no_of_boards++;
+			mca_set_adapter_name(slot,
+				"NCR 53c710 SCSI Host Adapter Board");
+		    }
+		}
+	    }
+	    id_to_check++;
+	}
+    }
+#endif
+
+    if (!no_of_boards) {
+       printk("sim710: No NCR53C710 adapter found.\n");
+       return 0;
+    }
+
+    size = sizeof(struct sim710_hostdata);
+    order = 0;
+    while (size > (PAGE_SIZE << order))
+	order++;
+    size = PAGE_SIZE << order;
+
+    DEB(DEB_ANY, printk("sim710: hostdata %d bytes, size %d, order %d\n",
+	sizeof(struct sim710_hostdata), size, order));
+
+    tpnt->proc_dir = &proc_scsi_sim710;
+
+    for(indx = 0; indx < no_of_boards; indx++) {
+	host = scsi_register(tpnt, 4);
+	host->hostdata[0] = __get_free_pages(GFP_ATOMIC, order);
+	if (host->hostdata[0] == 0)
+	    panic ("sim710: Couldn't get hostdata memory");
+	hostdata = (struct sim710_hostdata *)host->hostdata[0];
+	memset(hostdata, 0, size);
+#ifdef CONFIG_TP34V_SCSI
+	cache_push(virt_to_phys(hostdata), size);
+	cache_clear(virt_to_phys(hostdata), size);
+	kernel_set_cachemode((void *)hostdata,size,IOMAP_NOCACHE_SER);
+#endif
+	scsi_id = 7;
+	base_addr = bases[indx];
+	irq_vector = irq_vectors[indx];
+	printk("sim710: Configuring Sim710 (SCSI-ID %d) at %x, IRQ %d\n",
+	    		scsi_id, base_addr, irq_vector);
+	DEB(DEB_ANY, printk("sim710: hostdata = %p (%d bytes), dsa0 = %p\n",
+			hostdata, sizeof(struct sim710_hostdata),
+			 hostdata->target[0].dsa));
+	hostdata->chip = indx;
+	host->irq = irq_vector;
+	host->this_id = scsi_id;
+	host->unique_id = base_addr;
+	host->base = (char *)base_addr;
+
+	ncr_halt(host);
+
+	revision = (NCR_read8(CTEST8_REG) & 0xF0) >> 4;
+	printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
+
+	sim710_soft_reset(host);
+
+	sim710_driver_init(host);
+
+#ifdef CONFIG_TP34V_SCSI
+	if (request_irq(irq_vector,do_sim710_intr_handle, 0, "sim710", host))
+#else
+	if (request_irq(irq_vector,do_sim710_intr_handle, SA_INTERRUPT, "sim710", host))
+#endif
+	{
+	    printk("scsi%d : IRQ%d not free, detaching\n",
+	    		host->host_no, host->irq);
+
+	    scsi_unregister (host);
+	}
+	else {
+#ifdef IO_MAPPED
+	    request_region((u32)host->base, 64, "sim710");
+#endif
+	    chips++;
+	}
+	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_reselect/4));
+	hostdata->state = STATE_IDLE;
+    }
+    return chips;
+}
+
+int
+sim710_abort(Scsi_Cmnd * cmd)
+{
+    struct Scsi_Host * host = cmd->host;
+
+    printk("scsi%d: Unable to abort command for target %d\n",
+	   host->host_no, cmd->target);
+    return FAILED;
+}
+
+/*
+ * This is a device reset.  Need to select and send a Bus Device Reset msg.
+ */
+
+int
+sim710_dev_reset(Scsi_Cmnd * SCpnt)
+{
+    struct Scsi_Host * host = SCpnt->host;
+
+    printk("scsi%d: Unable to send Bus Device Reset for target %d\n",
+	   host->host_no, SCpnt->target);
+    return FAILED;
+}
+
+/*
+ * This is bus reset.  We need to reset the bus and fail any active commands.
+ */
+
+int
+sim710_bus_reset(Scsi_Cmnd * SCpnt)
+{
+    struct Scsi_Host * host = SCpnt->host;
+
+    printk("scsi%d: Unable to do SCSI bus reset\n", host->host_no);
+    return FAILED;
+}
+
+static int
+full_reset(struct Scsi_Host * host)
+{
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+	    host->hostdata[0];
+    int target;
+    Scsi_Cmnd *cmd;
+
+    ncr_halt(host);
+    printk("scsi%d: dsp = %08x (script[0x%04x]), scratch = %08x\n",
+	host->host_no, NCR_read32(DSP_REG),
+	((u32)bus_to_virt(NCR_read32(DSP_REG)) - (u32)hostdata->script)/4,
+	NCR_read32(SCRATCH_REG));
+
+    for (target = 0; target < 7; target++) {
+	if ((cmd = hostdata->target[target].cur_cmd)) {
+	    printk("scsi%d: Failing command for ID%d\n",
+			host->host_no, target);
+	    cmd->result = DID_RESET << 16;
+	    cmd->scsi_done(cmd);
+	    hostdata->target[target].cur_cmd = NULL;
+	}
+    }
+
+    sim710_soft_reset(host);
+    sim710_driver_init(host);
+
+    NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_reselect/4));
+    hostdata->state = STATE_IDLE;
+
+    run_process_issue_queue(hostdata);
+
+    return SUCCESS;
+}
+
+/*
+ * This is host reset.  We need to reset the chip and the bus.
+ */
+
+int
+sim710_host_reset(Scsi_Cmnd * SCpnt)
+{
+    struct Scsi_Host * host = SCpnt->host;
+
+    printk("scsi%d: >>>>>>>>>>>> Host reset <<<<<<<<<<<<\n", host->host_no);
+
+    return full_reset(host);
+}
+
+#ifdef MODULE
+
+int
+sim710_release(struct Scsi_Host *host)
+{
+    free_irq(host->irq, host);
+#ifdef IO_MAPPED
+    release_region((u32)host->base, 64);
+#endif
+    return 1;
+}
+
+Scsi_Host_Template driver_template = SIM710_SCSI;
+
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/sim710.h linux/drivers/scsi/sim710.h
--- v2.3.19/linux/drivers/scsi/sim710.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/sim710.h	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,845 @@
+#ifndef _SIM710_H
+#define _SIM710_H
+
+/*
+ * sim710.h - Copyright (C) 1999 Richard Hirst
+ */
+
+#include <linux/types.h>
+
+int sim710_detect(Scsi_Host_Template *);
+int sim710_command(Scsi_Cmnd *);
+int sim710_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int sim710_abort(Scsi_Cmnd * SCpnt);
+int sim710_bus_reset(Scsi_Cmnd * SCpnt);
+int sim710_dev_reset(Scsi_Cmnd * SCpnt);
+int sim710_host_reset(Scsi_Cmnd * SCpnt);
+int sim710_biosparam(Disk *, kdev_t, int*);
+#ifdef MODULE
+int sim710_release(struct Scsi_Host *);
+#else
+#define sim710_release	NULL
+#endif
+
+#if defined(HOSTS_C) || defined(MODULE)
+#include <scsi/scsicam.h>
+
+extern struct proc_dir_entry proc_scsi_sim710;
+
+#define SIM710_SCSI { proc_dir:			&proc_scsi_sim710,	\
+		      name:			"Simple 53c710", 	\
+		      detect:			sim710_detect,		\
+		      release:			sim710_release,		\
+		      queuecommand:		sim710_queuecommand,	\
+		      eh_abort_handler:		sim710_abort,		\
+		      eh_device_reset_handler:	sim710_dev_reset,	\
+		      eh_bus_reset_handler:	sim710_bus_reset,	\
+		      eh_host_reset_handler:	sim710_host_reset,	\
+		      bios_param:		scsicam_bios_param,	\
+		      can_queue:		8,		 	\
+		      this_id:			7, 			\
+		      sg_tablesize:		128,		 	\
+		      cmd_per_lun:		1,		 	\
+		      use_clustering:		DISABLE_CLUSTERING,	\
+		      use_new_eh_code:		1}
+
+#endif
+
+#ifndef HOSTS_C
+
+#ifdef __BIG_ENDIAN
+#define	bE	3	/* 0 for little endian, 3 for big endian */
+#else
+#define bE	0
+#endif
+
+/* SCSI control 0 rw, default = 0xc0 */
+#define SCNTL0_REG 		(0x00^bE)
+#define SCNTL0_ARB1		0x80	/* 0 0 = simple arbitration */
+#define SCNTL0_ARB2		0x40	/* 1 1 = full arbitration */
+#define SCNTL0_STRT		0x20	/* Start Sequence */
+#define SCNTL0_WATN		0x10	/* Select with ATN */
+#define SCNTL0_EPC		0x08	/* Enable parity checking */
+/* Bit 2 is reserved on 800 series chips */
+#define SCNTL0_EPG_700		0x04	/* Enable parity generation */
+#define SCNTL0_AAP		0x02	/*  ATN/ on parity error */
+#define SCNTL0_TRG		0x01	/* Target mode */
+
+/* SCSI control 1 rw, default = 0x00 */
+
+#define SCNTL1_REG 		(0x01^bE)
+#define SCNTL1_EXC		0x80	/* Extra Clock Cycle of Data setup */
+#define SCNTL1_ADB		0x40	/*  contents of SODL on bus */
+#define SCNTL1_ESR_700		0x20	/* Enable SIOP response to selection
+					   and reselection */
+#define SCNTL1_CON		0x10	/* Connected */
+#define SCNTL1_RST		0x08	/* SCSI RST/ */
+#define SCNTL1_AESP		0x04	/* Force bad parity */
+#define SCNTL1_SND_700		0x02	/* Start SCSI send */
+#define SCNTL1_IARB_800		0x02	/* Immediate Arbitration, start
+					   arbitration immediately after
+					   busfree is detected */
+#define SCNTL1_RCV_700		0x01	/* Start SCSI receive */
+#define SCNTL1_SST_800		0x01	/* Start SCSI transfer */
+
+/* SCSI control 2 rw, */
+
+#define SCNTL2_REG_800		(0x02^bE)
+#define SCNTL2_800_SDU		0x80	/* SCSI disconnect unexpected */
+
+/* SCSI control 3 rw */
+
+#define SCNTL3_REG_800 		(0x03^bE)
+#define SCNTL3_800_SCF_SHIFT	4
+#define SCNTL3_800_SCF_MASK	0x70
+#define SCNTL3_800_SCF2		0x40	/* Synchronous divisor */
+#define SCNTL3_800_SCF1		0x20	/* 0x00 = SCLK/3 */
+#define SCNTL3_800_SCF0		0x10	/* 0x10 = SCLK/1 */
+					/* 0x20 = SCLK/1.5
+					   0x30 = SCLK/2
+					   0x40 = SCLK/3 */
+
+#define SCNTL3_800_CCF_SHIFT	0
+#define SCNTL3_800_CCF_MASK	0x07
+#define SCNTL3_800_CCF2		0x04	/* 0x00 50.01 to 66 */
+#define SCNTL3_800_CCF1		0x02	/* 0x01 16.67 to 25 */
+#define SCNTL3_800_CCF0		0x01	/* 0x02	25.01 - 37.5
+					   0x03	37.51 - 50
+					   0x04 50.01 - 66 */
+
+/*
+ * SCSI destination ID rw - the appropriate bit is set for the selected
+ * target ID.  This is written by the SCSI SCRIPTS processor.
+ * default = 0x00
+ */
+#define SDID_REG_700  		(0x02^bE)
+#define SDID_REG_800  		(0x06^bE)
+
+#define GP_REG_800		(0x07^bE) /* General purpose IO */
+#define GP_800_IO1		0x02
+#define GP_800_IO2		0x01
+
+/* SCSI interrupt enable rw, default = 0x00 */
+#define SIEN_REG_700		(0x03^bE)
+#define SIEN0_REG_800		(0x40^bE)
+#define SIEN_MA			0x80	/* Phase mismatch (ini) or ATN (tgt) */
+#define SIEN_FC			0x40	/* Function complete */
+#define SIEN_700_STO		0x20	/* Selection or reselection timeout */
+#define SIEN_800_SEL		0x20	/* Selected */
+#define SIEN_700_SEL		0x10	/* Selected or reselected */
+#define SIEN_800_RESEL		0x10	/* Reselected */
+#define SIEN_SGE		0x08	/* SCSI gross error */
+#define SIEN_UDC		0x04	/* Unexpected disconnect */
+#define SIEN_RST		0x02	/* SCSI RST/ received */
+#define SIEN_PAR		0x01	/* Parity error */
+
+/*
+ * SCSI chip ID rw
+ * NCR53c700 :
+ * 	When arbitrating, the highest bit is used, when reselection or selection
+ * 	occurs, the chip responds to all IDs for which a bit is set.
+ * 	default = 0x00
+ */
+#define SCID_REG		(0x04^bE)
+/* Bit 7 is reserved on 800 series chips */
+#define SCID_800_RRE		0x40	/* Enable response to reselection */
+#define SCID_800_SRE		0x20	/* Enable response to selection */
+/* Bits four and three are reserved on 800 series chips */
+#define SCID_800_ENC_MASK	0x07	/* Encoded SCSI ID */
+
+/* SCSI transfer rw, default = 0x00 */
+#define SXFER_REG		(0x05^bE)
+#define SXFER_DHP		0x80	/* Disable halt on parity */
+
+#define SXFER_TP2		0x40	/* Transfer period msb */
+#define SXFER_TP1		0x20
+#define SXFER_TP0		0x10	/* lsb */
+#define SXFER_TP_MASK		0x70
+/* FIXME : SXFER_TP_SHIFT == 5 is right for '8xx chips */
+#define SXFER_TP_SHIFT		5
+#define SXFER_TP_4		0x00	/* Divisors */
+#define SXFER_TP_5		0x10<<1
+#define SXFER_TP_6		0x20<<1
+#define SXFER_TP_7		0x30<<1
+#define SXFER_TP_8		0x40<<1
+#define SXFER_TP_9		0x50<<1
+#define SXFER_TP_10		0x60<<1
+#define SXFER_TP_11		0x70<<1
+
+#define SXFER_MO3		0x08	/* Max offset msb */
+#define SXFER_MO2		0x04
+#define SXFER_MO1		0x02
+#define SXFER_MO0		0x01	/* lsb */
+#define SXFER_MO_MASK		0x0f
+#define SXFER_MO_SHIFT		0
+
+/*
+ * SCSI output data latch rw
+ * The contents of this register are driven onto the SCSI bus when
+ * the Assert Data Bus bit of the SCNTL1 register is set and
+ * the CD, IO, and MSG bits of the SOCL register match the SCSI phase
+ */
+#define SODL_REG_700		(0x06^bE)
+#define SODL_REG_800		(0x54^bE)
+
+
+/*
+ * SCSI output control latch rw, default = 0
+ * Note that when the chip is being manually programmed as an initiator,
+ * the MSG, CD, and IO bits must be set correctly for the phase the target
+ * is driving the bus in.  Otherwise no data transfer will occur due to
+ * phase mismatch.
+ */
+
+#define SOCL_REG		(0x07^bE)
+#define SOCL_REQ		0x80	/*  REQ */
+#define SOCL_ACK		0x40	/*  ACK */
+#define SOCL_BSY		0x20	/*  BSY */
+#define SOCL_SEL		0x10	/*  SEL */
+#define SOCL_ATN		0x08	/*  ATN */
+#define SOCL_MSG		0x04	/*  MSG */
+#define SOCL_CD			0x02	/*  C/D */
+#define SOCL_IO			0x01	/*  I/O */
+
+/*
+ * SCSI first byte received latch ro
+ * This register contains the first byte received during a block MOVE
+ * SCSI SCRIPTS instruction, including
+ *
+ * Initiator mode	Target mode
+ * Message in		Command
+ * Status		Message out
+ * Data in		Data out
+ *
+ * It also contains the selecting or reselecting device's ID and our
+ * ID.
+ *
+ * Note that this is the register the various IF conditionals can
+ * operate on.
+ */
+#define SFBR_REG		(0x08^bE)
+
+/*
+ * SCSI input data latch ro
+ * In initiator mode, data is latched into this register on the rising
+ * edge of REQ/. In target mode, data is latched on the rising edge of
+ * ACK/
+ */
+#define SIDL_REG_700		(0x09^bE)
+#define SIDL_REG_800		(0x50^bE)
+
+/*
+ * SCSI bus data lines ro
+ * This register reflects the instantaneous status of the SCSI data
+ * lines.  Note that SCNTL0 must be set to disable parity checking,
+ * otherwise reading this register will latch new parity.
+ */
+#define SBDL_REG_700		(0x0a^bE)
+#define SBDL_REG_800		(0x58^bE)
+
+#define SSID_REG_800		(0x0a^bE)
+#define SSID_800_VAL		0x80	/* Exactly two bits asserted at sel */
+#define SSID_800_ENCID_MASK	0x07	/* Device which performed operation */
+
+
+
+/*
+ * SCSI bus control lines rw,
+ * instantaneous readout of control lines
+ */
+#define SBCL_REG		(0x0b^bE)
+#define SBCL_REQ		0x80	/*  REQ ro */
+#define SBCL_ACK		0x40	/*  ACK ro */
+#define SBCL_BSY		0x20	/*  BSY ro */
+#define SBCL_SEL		0x10	/*  SEL ro */
+#define SBCL_ATN		0x08	/*  ATN ro */
+#define SBCL_MSG		0x04	/*  MSG ro */
+#define SBCL_CD			0x02	/*  C/D ro */
+#define SBCL_IO			0x01	/*  I/O ro */
+#define SBCL_PHASE_CMDOUT	SBCL_CD
+#define SBCL_PHASE_DATAIN	SBCL_IO
+#define SBCL_PHASE_DATAOUT	0
+#define SBCL_PHASE_MSGIN	(SBCL_CD|SBCL_IO|SBCL_MSG)
+#define SBCL_PHASE_MSGOUT	(SBCL_CD|SBCL_MSG)
+#define SBCL_PHASE_STATIN	(SBCL_CD|SBCL_IO)
+#define SBCL_PHASE_MASK		(SBCL_CD|SBCL_IO|SBCL_MSG)
+/*
+ * Synchronous SCSI Clock Control bits
+ * 0 - set by DCNTL
+ * 1 - SCLK / 1.0
+ * 2 - SCLK / 1.5
+ * 3 - SCLK / 2.0
+ */
+#define SBCL_SSCF1		0x02	/* wo, -66 only */
+#define SBCL_SSCF0		0x01	/* wo, -66 only */
+#define SBCL_SSCF_MASK		0x03
+
+/*
+ * XXX note : when reading the DSTAT and STAT registers to clear interrupts,
+ * insure that 10 clocks elapse between the two
+ */
+/* DMA status ro */
+#define DSTAT_REG		(0x0c^bE)
+#define DSTAT_DFE		0x80	/* DMA FIFO empty */
+#define DSTAT_800_MDPE		0x40	/* Master Data Parity Error */
+#define DSTAT_BF		0x20	/* Bus Fault */
+#define DSTAT_ABRT		0x10	/* Aborted - set on error */
+#define DSTAT_SSI		0x08	/* SCRIPTS single step interrupt */
+#define DSTAT_SIR		0x04	/* SCRIPTS interrupt received -
+					   set when INT instruction is
+					   executed */
+#define DSTAT_WTD		0x02	/* Watchdog timeout detected */
+#define DSTAT_OPC		0x01	/* Illegal instruction */
+#define DSTAT_IID		0x01	/* Same thing, different name */
+
+
+#define SSTAT0_REG		(0x0d^bE)	/* SCSI status 0 ro */
+#define SIST0_REG_800		(0x42^bE)	/* SCSI status 0 ro */
+#define SSTAT0_MA		0x80	/* ini : phase mismatch,
+					 * tgt : ATN/ asserted
+					 */
+#define SSTAT0_CMP		0x40	/* function complete */
+#define SSTAT0_700_STO		0x20	/* Selection or reselection timeout */
+#define SSTAT0_800_SEL		0x20	/* Selected */
+#define SSTAT0_700_SEL		0x10	/* Selected or reselected */
+#define SIST0_800_RSL		0x10	/* Reselected */
+#define SSTAT0_SGE		0x08	/* SCSI gross error */
+#define SSTAT0_UDC		0x04	/* Unexpected disconnect */
+#define SSTAT0_RST		0x02	/* SCSI RST/ received */
+#define SSTAT0_PAR		0x01	/* Parity error */
+
+#define SSTAT1_REG		(0x0e^bE)	/* SCSI status 1 ro */
+#define SSTAT1_ILF		0x80	/* SIDL full */
+#define SSTAT1_ORF		0x40	/* SODR full */
+#define SSTAT1_OLF		0x20	/* SODL full */
+#define SSTAT1_AIP		0x10	/* Arbitration in progress */
+#define SSTAT1_LOA		0x08	/* Lost arbitration */
+#define SSTAT1_WOA		0x04	/* Won arbitration */
+#define SSTAT1_RST		0x02	/* Instant readout of RST/ */
+#define SSTAT1_SDP		0x01	/* Instant readout of SDP/ */
+
+#define SSTAT2_REG		(0x0f^bE)	/* SCSI status 2 ro */
+#define SSTAT2_FF3		0x80 	/* number of bytes in synchronous */
+#define SSTAT2_FF2		0x40	/* data FIFO */
+#define SSTAT2_FF1		0x20
+#define SSTAT2_FF0		0x10
+#define SSTAT2_FF_MASK		0xf0
+#define SSTAT2_FF_SHIFT		4
+
+/*
+ * Latched signals, latched on the leading edge of REQ/ for initiators,
+ * ACK/ for targets.
+ */
+#define SSTAT2_SDP		0x08	/* SDP */
+#define SSTAT2_MSG		0x04	/* MSG */
+#define SSTAT2_CD		0x02	/* C/D */
+#define SSTAT2_IO		0x01	/* I/O */
+#define SSTAT2_PHASE_CMDOUT	SSTAT2_CD
+#define SSTAT2_PHASE_DATAIN	SSTAT2_IO
+#define SSTAT2_PHASE_DATAOUT	0
+#define SSTAT2_PHASE_MSGIN	(SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+#define SSTAT2_PHASE_MSGOUT	(SSTAT2_CD|SSTAT2_MSG)
+#define SSTAT2_PHASE_STATIN	(SSTAT2_CD|SSTAT2_IO)
+#define SSTAT2_PHASE_MASK	(SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+
+
+#define DSA_REG			0x10	/* DATA structure address */
+
+#define CTEST0_REG_700		(0x14^bE)	/* Chip test 0 ro */
+#define CTEST0_REG_800		(0x18^bE)	/* Chip test 0 ro */
+/* 0x80 - 0x04 are reserved */
+#define CTEST0_700_RTRG		0x02	/* Real target mode */
+#define CTEST0_700_DDIR		0x01	/* Data direction, 1 =
+					 * SCSI bus to host, 0  =
+					 * host to SCSI.
+					 */
+
+#define CTEST1_REG_700		(0x15^bE)	/* Chip test 1 ro */
+#define CTEST1_REG_800		(0x19^bE)	/* Chip test 1 ro */
+#define CTEST1_FMT3		0x80	/* Identify which byte lanes are empty */
+#define CTEST1_FMT2		0x40 	/* in the DMA FIFO */
+#define CTEST1_FMT1		0x20
+#define CTEST1_FMT0		0x10
+
+#define CTEST1_FFL3		0x08	/* Identify which bytes lanes are full */
+#define CTEST1_FFL2		0x04	/* in the DMA FIFO */
+#define CTEST1_FFL1		0x02
+#define CTEST1_FFL0		0x01
+
+#define CTEST2_REG_700		(0x16^bE)	/* Chip test 2 ro */
+#define CTEST2_REG_800		(0x1a^bE)	/* Chip test 2 ro */
+
+#define CTEST2_800_DDIR		0x80	/* 1 = SCSI->host */
+#define CTEST2_800_SIGP		0x40	/* A copy of SIGP in ISTAT.
+					   Reading this register clears */
+#define CTEST2_800_CIO		0x20	/* Configured as IO */.
+#define CTEST2_800_CM		0x10	/* Configured as memory */
+
+/* 0x80 - 0x40 are reserved on 700 series chips */
+#define CTEST2_700_SOFF		0x20	/* SCSI Offset Compare,
+					 * As an initiator, this bit is
+					 * one when the synchronous offset
+					 * is zero, as a target this bit
+					 * is one when the synchronous
+					 * offset is at the maximum
+					 * defined in SXFER
+					 */
+#define CTEST2_700_SFP		0x10	/* SCSI FIFO parity bit,
+					 * reading CTEST3 unloads a byte
+					 * from the FIFO and sets this
+					 */
+#define CTEST2_700_DFP		0x08	/* DMA FIFO parity bit,
+					 * reading CTEST6 unloads a byte
+					 * from the FIFO and sets this
+					 */
+#define CTEST2_TEOP		0x04	/* SCSI true end of process,
+					 * indicates a totally finished
+					 * transfer
+					 */
+#define CTEST2_DREQ		0x02	/* Data request signal */
+/* 0x01 is reserved on 700 series chips */
+#define CTEST2_800_DACK		0x01
+
+/*
+ * Chip test 3 ro
+ * Unloads the bottom byte of the eight deep SCSI synchronous FIFO,
+ * check SSTAT2 FIFO full bits to determine size.  Note that a GROSS
+ * error results if a read is attempted on this register.  Also note
+ * that 16 and 32 bit reads of this register will cause corruption.
+ */
+#define CTEST3_REG_700		(0x17^bE)
+/*  Chip test 3 rw */
+#define CTEST3_REG_800		(0x1b^bE)
+#define CTEST3_800_V3		0x80	/* Chip revision */
+#define CTEST3_800_V2		0x40
+#define CTEST3_800_V1		0x20
+#define CTEST3_800_V0		0x10
+#define CTEST3_800_FLF		0x08	/* Flush DMA FIFO */
+#define CTEST3_800_CLF		0x04	/* Clear DMA FIFO */
+#define CTEST3_800_FM		0x02	/* Fetch mode pin */
+/* bit 0 is reserved on 800 series chips */
+
+#define CTEST4_REG_400		(0x18^bE)	/* Chip test 4 rw */
+#define CTEST4_REG_800		(0x21^bE)	/* Chip test 4 rw */
+/* 0x80 is reserved on 700 series chips */
+#define CTEST4_800_BDIS		0x80	/* Burst mode disable */
+#define CTEST4_ZMOD		0x40	/* High impedance mode */
+#define CTEST4_SZM		0x20	/* SCSI bus high impedance */
+#define CTEST4_700_SLBE		0x10	/* SCSI loopback enabled */
+#define CTEST4_800_SRTM		0x10	/* Shadow Register Test Mode */
+#define CTEST4_700_SFWR		0x08	/* SCSI FIFO write enable,
+					 * redirects writes from SODL
+					 * to the SCSI FIFO.
+					 */
+#define CTEST4_800_MPEE		0x08	/* Enable parity checking
+					   during master cycles on PCI
+					   bus */
+
+/*
+ * These bits send the contents of the CTEST6 register to the appropriate
+ * byte lane of the 32 bit DMA FIFO.  Normal operation is zero, otherwise
+ * the high bit means the low two bits select the byte lane.
+ */
+#define CTEST4_FBL2		0x04
+#define CTEST4_FBL1		0x02
+#define CTEST4_FBL0		0x01
+#define CTEST4_FBL_MASK		0x07
+#define CTEST4_FBL_0		0x04	/* Select DMA FIFO byte lane 0 */
+#define CTEST4_FBL_1		0x05	/* Select DMA FIFO byte lane 1 */
+#define CTEST4_FBL_2		0x06	/* Select DMA FIFO byte lane 2 */
+#define CTEST4_FBL_3		0x07	/* Select DMA FIFO byte lane 3 */
+#define CTEST4_800_SAVE		(CTEST4_800_BDIS)
+
+
+#define CTEST5_REG_700		(0x19^bE)	/* Chip test 5 rw */
+#define CTEST5_REG_800		(0x22^bE)	/* Chip test 5 rw */
+/*
+ * Clock Address Incrementor.  When set, it increments the
+ * DNAD register to the next bus size boundary.  It automatically
+ * resets itself when the operation is complete.
+ */
+#define CTEST5_ADCK		0x80
+/*
+ * Clock Byte Counter.  When set, it decrements the DBC register to
+ * the next bus size boundary.
+ */
+#define CTEST5_BBCK		0x40
+/*
+ * Reset SCSI Offset.  Setting this bit to 1 clears the current offset
+ * pointer in the SCSI synchronous offset counter (SSTAT).  This bit
+ * is set to 1 if a SCSI Gross Error Condition occurs.  The offset should
+ * be cleared when a synchronous transfer fails.  When written, it is
+ * automatically cleared after the SCSI synchronous offset counter is
+ * reset.
+ */
+/* Bit 5 is reserved on 800 series chips */
+#define CTEST5_700_ROFF		0x20
+/*
+ * Master Control for Set or Reset pulses. When 1, causes the low
+ * four bits of register to set when set, 0 causes the low bits to
+ * clear when set.
+ */
+#define CTEST5_MASR 		0x10
+#define CTEST5_DDIR		0x08	/* DMA direction */
+/*
+ * Bits 2-0 are reserved on 800 series chips
+ */
+#define CTEST5_700_EOP		0x04	/* End of process */
+#define CTEST5_700_DREQ		0x02	/* Data request */
+#define CTEST5_700_DACK		0x01	/* Data acknowledge */
+
+/*
+ * Chip test 6 rw - writing to this register writes to the byte
+ * lane in the DMA FIFO as determined by the FBL bits in the CTEST4
+ * register.
+ */
+#define CTEST6_REG_700		(0x1a^bE)
+#define CTEST6_REG_800		(0x23^bE)
+
+#define CTEST7_REG		(0x1b^bE)	/* Chip test 7 rw */
+#define CTEST7_10_CDIS		0x80	/* Cache burst disable */
+#define CTEST7_10_SC1		0x40	/* Snoop control bits */
+#define CTEST7_10_SC0		0x20
+#define CTEST7_10_SC_MASK	0x60
+#define CTEST7_STD		0x10	/* Selection timeout disable */
+#define CTEST7_DFP		0x08	/* DMA FIFO parity bit for CTEST6 */
+#define CTEST7_EVP		0x04	/* 1 = host bus even parity, 0 = odd */
+#define CTEST7_10_TT1		0x02	/* Transfer type */
+#define CTEST7_DIFF		0x01	/* Differential mode */
+
+#define CTEST7_SAVE ( CTEST7_EVP | CTEST7_DIFF )
+
+
+#define TEMP_REG		0x1c	/* through 0x1f Temporary stack rw */
+
+#define DFIFO_REG		(0x20^bE)	/* DMA FIFO rw */
+/*
+ * 0x80 is reserved on the NCR53c710, the CLF and FLF bits have been
+ * moved into the CTEST8 register.
+ */
+#define DFIFO_BO6		0x40
+#define DFIFO_BO5		0x20
+#define DFIFO_BO4		0x10
+#define DFIFO_BO3		0x08
+#define DFIFO_BO2		0x04
+#define DFIFO_BO1		0x02
+#define DFIFO_BO0		0x01
+#define DFIFO_10_BO_MASK	0x7f	/* 7 bit counter */
+
+/*
+ * Interrupt status rw
+ * Note that this is the only register which can be read while SCSI
+ * SCRIPTS are being executed.
+ */
+#define ISTAT_REG_700		(0x21^bE)
+#define ISTAT_REG_800		(0x14^bE)
+#define ISTAT_ABRT		0x80	/* Software abort, write
+					 *1 to abort, wait for interrupt. */
+#define ISTAT_10_SRST		0x40	/* software reset */
+#define ISTAT_10_SIGP		0x20	/* signal script */
+#define ISTAT_CON		0x08	/* 1 when connected */
+#define ISTAT_800_INTF		0x04	/* Interrupt on the fly */
+#define ISTAT_700_PRE		0x04	/* Pointer register empty.
+					 * Set to 1 when DSPS and DSP
+					 * registers are empty in pipeline
+					 * mode, always set otherwise.
+					 */
+#define ISTAT_SIP		0x02	/* SCSI interrupt pending from
+					 * SCSI portion of SIOP see
+					 * SSTAT0
+					 */
+#define ISTAT_DIP		0x01	/* DMA interrupt pending
+					 * see DSTAT
+					 */
+
+#define CTEST8_REG		(0x22^bE)	/* Chip test 8 rw */
+#define CTEST8_10_V3		0x80	/* Chip revision */
+#define CTEST8_10_V2		0x40
+#define CTEST8_10_V1		0x20
+#define CTEST8_10_V0		0x10
+#define CTEST8_10_V_MASK	0xf0
+#define CTEST8_10_FLF		0x08	/* Flush FIFOs */
+#define CTEST8_10_CLF		0x04	/* Clear FIFOs */
+#define CTEST8_10_FM		0x02	/* Fetch pin mode */
+#define CTEST8_10_SM		0x01	/* Snoop pin mode */
+
+
+#define LCRC_REG_10		(0x23^bE)
+
+/*
+ * 0x24 through 0x27 are the DMA byte counter register.  Instructions
+ * write their high 8 bits into the DCMD register, the low 24 bits into
+ * the DBC register.
+ *
+ * Function is dependent on the command type being executed.
+ */
+
+
+#define DBC_REG			0x24
+/*
+ * For Block Move Instructions, DBC is a 24 bit quantity representing
+ *     the number of bytes to transfer.
+ * For Transfer Control Instructions, DBC is bit fielded as follows :
+ */
+/* Bits 20 - 23 should be clear */
+#define DBC_TCI_TRUE		(1 << 19) 	/* Jump when true */
+#define DBC_TCI_COMPARE_DATA	(1 << 18)	/* Compare data */
+#define DBC_TCI_COMPARE_PHASE	(1 << 17)	/* Compare phase with DCMD field */
+#define DBC_TCI_WAIT_FOR_VALID	(1 << 16)	/* Wait for REQ */
+/* Bits 8 - 15 are reserved on some implementations ? */
+#define DBC_TCI_MASK_MASK	0xff00 		/* Mask for data compare */
+#define DBC_TCI_MASK_SHIFT	8
+#define DBC_TCI_DATA_MASK	0xff		/* Data to be compared */
+#define DBC_TCI_DATA_SHIFT	0
+
+#define DBC_RWRI_IMMEDIATE_MASK	0xff00		/* Immediate data */
+#define DBC_RWRI_IMMEDIATE_SHIFT 8		/* Amount to shift */
+#define DBC_RWRI_ADDRESS_MASK	0x3f0000	/* Register address */
+#define DBC_RWRI_ADDRESS_SHIFT 	16
+
+
+/*
+ * DMA command r/w
+ */
+#define DCMD_REG		(0x27^bE)
+#define DCMD_TYPE_MASK		0xc0	/* Masks off type */
+#define DCMD_TYPE_BMI		0x00	/* Indicates a Block Move instruction */
+#define DCMD_BMI_IO		0x01	/* I/O, CD, and MSG bits selecting   */
+#define DCMD_BMI_CD		0x02	/* the phase for the block MOVE      */
+#define DCMD_BMI_MSG		0x04	/* instruction 			     */
+
+#define DCMD_BMI_OP_MASK	0x18	/* mask for opcode */
+#define DCMD_BMI_OP_MOVE_T	0x00	/* MOVE */
+#define DCMD_BMI_OP_MOVE_I	0x08	/* MOVE Initiator */
+
+#define DCMD_BMI_INDIRECT	0x20	/*  Indirect addressing */
+
+#define DCMD_TYPE_TCI		0x80	/* Indicates a Transfer Control
+					   instruction */
+#define DCMD_TCI_IO		0x01	/* I/O, CD, and MSG bits selecting   */
+#define DCMD_TCI_CD		0x02	/* the phase for the block MOVE      */
+#define DCMD_TCI_MSG		0x04	/* instruction 			     */
+#define DCMD_TCI_OP_MASK	0x38	/* mask for opcode */
+#define DCMD_TCI_OP_JUMP	0x00	/* JUMP */
+#define DCMD_TCI_OP_CALL	0x08	/* CALL */
+#define DCMD_TCI_OP_RETURN	0x10	/* RETURN */
+#define DCMD_TCI_OP_INT		0x18	/* INT */
+
+#define DCMD_TYPE_RWRI		0x40	/* Indicates I/O or register Read/Write
+					   instruction */
+#define DCMD_RWRI_OPC_MASK	0x38	/* Opcode mask */
+#define DCMD_RWRI_OPC_WRITE	0x28	/* Write SFBR to register */
+#define DCMD_RWRI_OPC_READ	0x30	/* Read register to SFBR */
+#define DCMD_RWRI_OPC_MODIFY	0x38	/* Modify in place */
+
+#define DCMD_RWRI_OP_MASK	0x07
+#define DCMD_RWRI_OP_MOVE	0x00
+#define DCMD_RWRI_OP_SHL	0x01
+#define DCMD_RWRI_OP_OR		0x02
+#define DCMD_RWRI_OP_XOR	0x03
+#define DCMD_RWRI_OP_AND	0x04
+#define DCMD_RWRI_OP_SHR	0x05
+#define DCMD_RWRI_OP_ADD	0x06
+#define DCMD_RWRI_OP_ADDC	0x07
+
+#define DCMD_TYPE_MMI		0xc0	/* Indicates a Memory Move instruction
+					   (three words) */
+
+
+#define DNAD_REG		0x28	/* through 0x2b DMA next address for
+					   data */
+#define DSP_REG			0x2c	/* through 0x2f DMA SCRIPTS pointer rw */
+#define DSPS_REG		0x30	/* through 0x33 DMA SCRIPTS pointer
+					   save rw */
+#define DMODE_BL1		0x80	/* Burst length bits */
+#define DMODE_BL0		0x40
+#define DMODE_BL_MASK		0xc0
+/* Burst lengths (800) */
+#define DMODE_BL_2	0x00	/* 2 transfer */
+#define DMODE_BL_4	0x40	/* 4 transfers */
+#define DMODE_BL_8	0x80	/* 8 transfers */
+#define DMODE_BL_16	0xc0	/* 16 transfers */
+
+#define DMODE_10_BL_1	0x00	/* 1 transfer */
+#define DMODE_10_BL_2	0x40	/* 2 transfers */
+#define DMODE_10_BL_4	0x80	/* 4 transfers */
+#define DMODE_10_BL_8	0xc0	/* 8 transfers */
+#define DMODE_10_FC2	0x20	/* Driven to FC2 pin */
+#define DMODE_10_FC1	0x10	/* Driven to FC1 pin */
+#define DMODE_710_PD	0x08	/* Program/data on FC0 pin */
+#define DMODE_710_UO	0x02	/* User prog. output */
+
+#define DMODE_MAN		0x01	/* Manual start mode,
+					 * requires a 1 to be written
+					 * to the start DMA bit in the DCNTL
+					 * register to run scripts
+					 */
+
+/* NCR53c800 series only */
+#define SCRATCHA_REG_800	0x34	/* through 0x37 Scratch A rw */
+/* NCR53c710 only */
+#define SCRATCHB_REG_10		0x34	/* through 0x37 scratch rw */
+
+#define DMODE_REG	    	(0x38^bE)	/* DMA mode rw, NCR53c710 and newer */
+#define DMODE_800_SIOM		0x20	/* Source IO = 1 */
+#define DMODE_800_DIOM		0x10	/* Destination IO = 1 */
+#define DMODE_800_ERL		0x08	/* Enable Read Line */
+
+#define DIEN_REG		(0x39^bE)	/* DMA interrupt enable rw */
+/* 0x80, 0x40, and 0x20 are reserved on 700-series chips */
+#define DIEN_800_MDPE		0x40	/* Master data parity error */
+#define DIEN_800_BF		0x20	/* BUS fault */
+#define DIEN_700_BF		0x20	/* BUS fault */
+#define DIEN_ABRT		0x10	/* Enable aborted interrupt */
+#define DIEN_SSI		0x08	/* Enable single step interrupt */
+#define DIEN_SIR		0x04	/* Enable SCRIPTS INT command
+					 * interrupt
+					 */
+#define DIEN_700_WTD		0x02	/* Enable watchdog timeout interrupt */
+#define DIEN_700_OPC		0x01	/* Enable illegal instruction
+					 * interrupt
+					 */
+#define DIEN_800_IID		0x01	/*  Same meaning, different name */
+
+/*
+ * DMA watchdog timer rw
+ * set in 16 CLK input periods.
+ */
+#define DWT_REG			(0x3a^bE)
+
+/* DMA control rw */
+#define DCNTL_REG		(0x3b^bE)
+#define DCNTL_700_CF1		0x80	/* Clock divisor bits */
+#define DCNTL_700_CF0		0x40
+#define DCNTL_700_CF_MASK	0xc0
+/* Clock divisors 			   Divisor SCLK range (MHZ) */
+#define DCNTL_700_CF_2		0x00    /* 2.0	   37.51-50.00 */
+#define DCNTL_700_CF_1_5	0x40	/* 1.5	   25.01-37.50 */
+#define DCNTL_700_CF_1		0x80	/* 1.0     16.67-25.00 */
+#define DCNTL_700_CF_3		0xc0	/* 3.0	   50.01-66.67 (53c700-66) */
+
+#define DCNTL_700_S16		0x20	/* Load scripts 16 bits at a time */
+#define DCNTL_SSM		0x10	/* Single step mode */
+#define DCNTL_700_LLM		0x08	/* Low level mode, can only be set
+					 * after selection */
+#define DCNTL_800_IRQM		0x08	/* Totem pole IRQ pin */
+#define DCNTL_STD		0x04	/* Start DMA / SCRIPTS */
+/* 0x02 is reserved */
+#define DCNTL_10_COM		0x01	/* 700 software compatibility mode */
+#define DCNTL_10_EA		0x20	/* Enable Ack - needed for MVME16x */
+
+#define SCRATCHB_REG_800	0x5c	/* through 0x5f scratch b rw */
+/* NCR53c710 only */
+#define ADDER_REG_10		0x3c	/* Adder, NCR53c710 only */
+
+#define SIEN1_REG_800		(0x41^bE)
+#define SIEN1_800_STO		0x04	/* selection/reselection timeout */
+#define SIEN1_800_GEN		0x02	/* general purpose timer */
+#define SIEN1_800_HTH		0x01	/* handshake to handshake */
+
+#define SIST1_REG_800		(0x43^bE)
+#define SIST1_800_STO		0x04	/* selection/reselection timeout */
+#define SIST1_800_GEN		0x02	/* general purpose timer */
+#define SIST1_800_HTH		0x01	/* handshake to handshake */
+
+#define SLPAR_REG_800		(0x44^bE)	/* Parity */
+
+#define MACNTL_REG_800		(0x46^bE)	/* Memory access control */
+#define MACNTL_800_TYP3		0x80
+#define MACNTL_800_TYP2		0x40
+#define MACNTL_800_TYP1		0x20
+#define MACNTL_800_TYP0		0x10
+#define MACNTL_800_DWR		0x08
+#define MACNTL_800_DRD		0x04
+#define MACNTL_800_PSCPT	0x02
+#define MACNTL_800_SCPTS	0x01
+
+#define GPCNTL_REG_800		(0x47^bE)	/* General Purpose Pin Control */
+
+/* Timeouts are expressed such that 0=off, 1=100us, doubling after that */
+#define STIME0_REG_800		(0x48^bE)	/* SCSI Timer Register 0 */
+#define STIME0_800_HTH_MASK	0xf0	/* Handshake to Handshake timeout */
+#define STIME0_800_HTH_SHIFT	4
+#define STIME0_800_SEL_MASK	0x0f	/* Selection timeout */
+#define STIME0_800_SEL_SHIFT	0
+
+#define STIME1_REG_800		(0x49^bE)
+#define STIME1_800_GEN_MASK	0x0f	/* General purpose timer */
+
+#define RESPID_REG_800		(0x4a^bE)	/* Response ID, bit fielded.  8
+					   bits on narrow chips, 16 on WIDE */
+
+#define STEST0_REG_800		(0x4c^bE)
+#define STEST0_800_SLT		0x08	/* Selection response logic test */
+#define STEST0_800_ART		0x04	/* Arbitration priority encoder test */
+#define STEST0_800_SOZ		0x02	/* Synchronous offset zero */
+#define STEST0_800_SOM		0x01	/* Synchronous offset maximum */
+
+#define STEST1_REG_800		(0x4d^bE)
+#define STEST1_800_SCLK		0x80	/* Disable SCSI clock */
+
+#define STEST2_REG_800		(0x4e^bE)
+#define STEST2_800_SCE		0x80	/* Enable SOCL/SODL */
+#define STEST2_800_ROF		0x40	/* Reset SCSI sync offset */
+#define STEST2_800_SLB		0x10	/* Enable SCSI loopback mode */
+#define STEST2_800_SZM		0x08	/* SCSI high impedance mode */
+#define STEST2_800_EXT		0x02	/* Extend REQ/ACK filter 30 to 60ns */
+#define STEST2_800_LOW		0x01	/* SCSI low level mode */
+
+#define STEST3_REG_800		(0x4f^bE)
+#define STEST3_800_TE		0x80	/* Enable active negation */
+#define STEST3_800_STR		0x40	/* SCSI FIFO test read */
+#define STEST3_800_HSC		0x20	/* Halt SCSI clock */
+#define STEST3_800_DSI		0x10	/* Disable single initiator response */
+#define STEST3_800_TTM		0x04	/* Time test mode */
+#define STEST3_800_CSF		0x02	/* Clear SCSI FIFO */
+#define STEST3_800_STW		0x01	/* SCSI FIFO test write */
+
+#define ISTAT_REG	ISTAT_REG_700
+#define SCRATCH_REG	SCRATCHB_REG_10
+
+#ifdef MEM_MAPPED
+#define NCR_read8(address) 					\
+	(unsigned int)readb((u32)(host->base) + ((u32)(address)))
+
+#define NCR_read32(address) 					\
+	(unsigned int) readl((u32)(host->base) + (u32)(address))
+
+#define NCR_write8(address,value) 				\
+	{ DEB(DEB_REGS, printk("NCR: %02x => %08x\n", (u32)(value), ((u32)(host->base) + (u32)(address)))); \
+	*(volatile unsigned char *)					\
+		((u32)(host->base) + (u32)(address)) = (value); }
+
+#define NCR_write32(address,value) 				\
+	{ DEB(DEB_REGS, printk("NCR: %08x => %08x\n", (u32)(value), ((u32)(host->base) + (u32)(address)))); \
+	*(volatile unsigned long *)					\
+		((u32)(host->base) + (u32)(address)) = (value); }
+#else
+#define NCR_read8(address) 					\
+	inb((u32)(host->base) + (address))
+
+#define NCR_read32(address) 					\
+	inl((u32)(host->base) + (address))
+
+#define NCR_write8(address,value) 				\
+	{ DEB(DEB_REGS, printk("NCR: %02x => %08x\n", (u32)(value), ((u32)(host->base) + (u32)(address)))); \
+	outb((value), (u32)(host->base) + (u32)(address)); }
+
+#define NCR_write32(address,value) 				\
+	{ DEB(DEB_REGS, printk("NCR: %08x => %08x\n", (u32)(value), ((u32)(host->base) + (u32)(address)))); \
+	outl((value), (u32)(host->base) + (u32)(address)); }
+#endif
+
+/* Patch arbitrary 32 bit words in the script */
+#define patch_abs_32(script, offset, symbol, value)			\
+    	for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof 		\
+    	    (u32)); ++i) {					\
+	    (script)[A_##symbol##_used[i] - (offset)] += (value);	\
+	      DEB(DEB_FIXUP, printk("scsi%d: %s reference %d at 0x%x in %s is now 0x%x\n",\
+		host->host_no, #symbol, i, A_##symbol##_used[i] - 	\
+		(int)(offset), #script, (script)[A_##symbol##_used[i] -	\
+		(offset)]));						\
+    	}
+
+#endif
+#endif
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/sim710.scr linux/drivers/scsi/sim710.scr
--- v2.3.19/linux/drivers/scsi/sim710.scr	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/sim710.scr	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,554 @@
+/*
+ * sim710.scr - Copyright (C) 1999 Richard Hirst
+ */
+
+/* Offsets from DSA, allow 128 elements of scatter/gather */
+
+ABSOLUTE dsa_select  = 0
+ABSOLUTE dsa_msgout  = 8
+ABSOLUTE dsa_cmnd    = 16
+ABSOLUTE dsa_status  = 24
+ABSOLUTE dsa_msgin   = 32
+ABSOLUTE dsa_datain  = 40	/* 8 * 128 = 1024 bytes */
+ABSOLUTE dsa_dataout = 1064	/* 8 * 128 = 1024 bytes */
+ABSOLUTE dsa_size     = 2088
+
+ABSOLUTE reselected_identify = 0
+ABSOLUTE msgin_buf = 0
+
+/* Interrupt values passed back to driver */
+
+ABSOLUTE int_bad_extmsg1a	= 0xab930000
+ABSOLUTE int_bad_extmsg1b	= 0xab930001
+ABSOLUTE int_bad_extmsg2a	= 0xab930002
+ABSOLUTE int_bad_extmsg2b	= 0xab930003
+ABSOLUTE int_bad_extmsg3a	= 0xab930004
+ABSOLUTE int_bad_extmsg3b	= 0xab930005
+ABSOLUTE int_bad_msg1		= 0xab930006
+ABSOLUTE int_bad_msg2		= 0xab930007
+ABSOLUTE int_bad_msg3		= 0xab930008
+ABSOLUTE int_cmd_bad_phase	= 0xab930009
+ABSOLUTE int_cmd_complete	= 0xab93000a
+ABSOLUTE int_data_bad_phase	= 0xab93000b
+ABSOLUTE int_msg_sdtr1		= 0xab93000c
+ABSOLUTE int_msg_sdtr2		= 0xab93000d
+ABSOLUTE int_msg_sdtr3		= 0xab93000e
+ABSOLUTE int_no_msgout1		= 0xab93000f
+ABSOLUTE int_no_msgout2		= 0xab930010
+ABSOLUTE int_no_msgout3		= 0xab930011
+ABSOLUTE int_not_cmd_complete	= 0xab930012
+ABSOLUTE int_sel_no_ident	= 0xab930013
+ABSOLUTE int_sel_not_cmd	= 0xab930014
+ABSOLUTE int_status_not_msgin	= 0xab930015
+ABSOLUTE int_resel_not_msgin	= 0xab930016
+ABSOLUTE int_reselected		= 0xab930017
+ABSOLUTE int_selected		= 0xab930018
+ABSOLUTE int_disc1		= 0xab930019
+ABSOLUTE int_disc2		= 0xab93001a
+ABSOLUTE int_disc3		= 0xab93001b
+ABSOLUTE int_not_rej		= 0xab93001c
+
+
+/* Bit field settings used to record status in SCRATCH */
+
+ABSOLUTE had_select	= 0x01
+ABSOLUTE had_msgout	= 0x02
+ABSOLUTE had_cmdout	= 0x04
+ABSOLUTE had_datain	= 0x08
+ABSOLUTE had_dataout	= 0x10
+ABSOLUTE had_status	= 0x20
+ABSOLUTE had_msgin	= 0x40
+ABSOLUTE had_extmsg	= 0x80
+
+
+/* These scripts are heavily based on the examples in the NCR 53C710
+ * Programmer's Guide (Preliminary).
+ */
+
+ENTRY do_select
+do_select:
+	CLEAR TARGET
+	MOVE SCRATCH0 & 0 TO SCRATCH0
+	; Enable selection timer
+	MOVE CTEST7 & 0xef TO CTEST7
+	SELECT ATN FROM dsa_select, reselect
+	JUMP get_status, WHEN STATUS
+	; Disable selection timer
+	MOVE CTEST7 | 0x10 TO CTEST7
+	MOVE SCRATCH0 | had_select TO SCRATCH0
+	INT int_sel_no_ident, IF NOT MSG_OUT
+	MOVE SCRATCH0 | had_msgout TO SCRATCH0
+	MOVE FROM dsa_msgout, when MSG_OUT
+ENTRY done_ident
+done_ident:
+	JUMP get_status, IF STATUS
+redo_msgin1:
+	JUMP get_msgin1, WHEN MSG_IN
+	INT int_sel_not_cmd, IF NOT CMD
+ENTRY resume_cmd
+resume_cmd:
+	MOVE SCRATCH0 | had_cmdout TO SCRATCH0
+	MOVE FROM dsa_cmnd, WHEN CMD
+ENTRY resume_pmm
+resume_pmm:
+redo_msgin2:
+	JUMP get_msgin2, WHEN MSG_IN
+	JUMP get_status, IF STATUS
+	JUMP input_data, IF DATA_IN
+	JUMP output_data, IF DATA_OUT
+	INT int_cmd_bad_phase
+
+get_status:
+	; Disable selection timer
+	MOVE CTEST7 | 0x10 TO CTEST7
+	MOVE FROM dsa_status, WHEN STATUS
+	INT int_status_not_msgin, WHEN NOT MSG_IN
+	MOVE FROM dsa_msgin, WHEN MSG_IN
+	INT int_not_cmd_complete, IF NOT 0x00
+	CLEAR ACK
+ENTRY wait_disc_complete
+wait_disc_complete:
+	WAIT DISCONNECT
+	INT int_cmd_complete
+
+input_data:
+	MOVE SCRATCH0 | had_datain TO SCRATCH0
+ENTRY patch_input_data
+patch_input_data:
+	JUMP 0
+	MOVE FROM dsa_datain+0x0000, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0008, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0010, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0018, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0020, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0028, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0030, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0038, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0040, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0048, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0050, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0058, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0060, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0068, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0070, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0078, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0080, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0088, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0090, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0098, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00a0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00a8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00b0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00b8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00c0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00c8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00d0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00d8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00e0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00e8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00f0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x00f8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0100, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0108, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0110, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0118, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0120, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0128, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0130, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0138, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0140, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0148, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0150, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0158, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0160, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0168, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0170, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0178, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0180, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0188, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0190, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0198, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01a0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01a8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01b0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01b8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01c0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01c8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01d0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01d8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01e0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01e8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01f0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x01f8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0200, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0208, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0210, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0218, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0220, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0228, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0230, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0238, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0240, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0248, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0250, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0258, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0260, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0268, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0270, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0278, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0280, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0288, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0290, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0298, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02a0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02a8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02b0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02b8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02c0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02c8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02d0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02d8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02e0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02e8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02f0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x02f8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0300, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0308, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0310, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0318, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0320, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0328, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0330, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0338, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0340, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0348, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0350, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0358, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0360, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0368, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0370, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0378, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0380, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0388, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0390, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x0398, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03a0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03a8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03b0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03b8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03c0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03c8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03d0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03d8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03e0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03e8, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03f0, WHEN DATA_IN
+	MOVE FROM dsa_datain+0x03f8, WHEN DATA_IN
+	JUMP end_data_trans
+
+output_data:
+	MOVE SCRATCH0 | had_dataout TO SCRATCH0
+ENTRY patch_output_data
+patch_output_data:
+	JUMP 0
+	MOVE FROM dsa_dataout+0x0000, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0008, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0010, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0018, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0020, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0028, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0030, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0038, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0040, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0048, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0050, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0058, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0060, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0068, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0070, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0078, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0080, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0088, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0090, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0098, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00a0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00a8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00b0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00b8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00c0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00c8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00d0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00d8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00e0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00e8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00f0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x00f8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0100, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0108, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0110, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0118, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0120, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0128, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0130, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0138, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0140, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0148, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0150, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0158, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0160, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0168, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0170, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0178, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0180, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0188, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0190, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0198, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01a0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01a8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01b0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01b8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01c0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01c8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01d0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01d8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01e0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01e8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01f0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x01f8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0200, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0208, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0210, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0218, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0220, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0228, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0230, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0238, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0240, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0248, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0250, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0258, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0260, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0268, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0270, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0278, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0280, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0288, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0290, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0298, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02a0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02a8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02b0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02b8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02c0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02c8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02d0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02d8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02e0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02e8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02f0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x02f8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0300, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0308, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0310, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0318, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0320, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0328, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0330, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0338, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0340, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0348, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0350, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0358, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0360, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0368, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0370, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0378, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0380, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0388, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0390, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x0398, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03a0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03a8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03b0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03b8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03c0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03c8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03d0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03d8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03e0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03e8, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03f0, WHEN DATA_OUT
+	MOVE FROM dsa_dataout+0x03f8, WHEN DATA_OUT
+ENTRY end_data_trans
+end_data_trans:
+redo_msgin3:
+	JUMP get_status, WHEN STATUS
+	JUMP get_msgin3, WHEN MSG_IN
+	INT int_data_bad_phase
+
+get_msgin1:
+	MOVE SCRATCH0 | had_msgin TO SCRATCH0
+	MOVE 1, msgin_buf, WHEN MSG_IN
+	JUMP ext_msg1, IF 0x01		; Extended Message
+	JUMP ignore_msg1, IF 0x02	; Save Data Pointers
+	JUMP ignore_msg1, IF 0x03	; Save Restore Pointers
+	JUMP disc1, IF 0x04		; Disconnect
+	INT int_bad_msg1
+ignore_msg1:
+	CLEAR ACK
+	JUMP redo_msgin1
+ext_msg1:
+	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+	CLEAR ACK
+	MOVE 1, msgin_buf + 1, WHEN MSG_IN
+	JUMP ext_msg1a, IF 0x03
+	INT int_bad_extmsg1a
+ext_msg1a:
+	CLEAR ACK
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+	JUMP ext_msg1b, IF 0x01		; Must be SDTR
+	INT int_bad_extmsg1b
+ext_msg1b:
+	CLEAR ACK
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+	INT int_msg_sdtr1
+disc1:
+	CLEAR ACK
+ENTRY wait_disc1
+wait_disc1:
+	WAIT DISCONNECT
+	INT int_disc1
+ENTRY resume_msgin1a
+resume_msgin1a:
+	CLEAR ACK
+	JUMP redo_msgin1
+ENTRY resume_msgin1b
+resume_msgin1b:
+	SET ATN
+	CLEAR ACK
+	INT int_no_msgout1, WHEN NOT MSG_OUT
+	MOVE SCRATCH0 | had_msgout TO SCRATCH0
+	MOVE FROM dsa_msgout, when MSG_OUT
+	JUMP redo_msgin1
+
+get_msgin2:
+	MOVE SCRATCH0 | had_msgin TO SCRATCH0
+	MOVE 1, msgin_buf, WHEN MSG_IN
+	JUMP ext_msg2, IF 0x01		; Extended Message
+	JUMP ignore_msg2, IF 0x02	; Save Data Pointers
+	JUMP ignore_msg2, IF 0x03	; Save Restore Pointers
+	JUMP disc2, IF 0x04		; Disconnect
+	INT int_bad_msg2
+ignore_msg2:
+	CLEAR ACK
+	JUMP redo_msgin2
+ext_msg2:
+	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+	CLEAR ACK
+	MOVE 1, msgin_buf + 1, WHEN MSG_IN
+	JUMP ext_msg2a, IF 0x03
+	INT int_bad_extmsg2a
+ext_msg2a:
+	CLEAR ACK
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+	JUMP ext_msg2b, IF 0x01		; Must be SDTR
+	INT int_bad_extmsg2b
+ext_msg2b:
+	CLEAR ACK
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+	INT int_msg_sdtr2
+disc2:
+	CLEAR ACK
+ENTRY wait_disc2
+wait_disc2:
+	WAIT DISCONNECT
+	INT int_disc2
+ENTRY resume_msgin2a
+resume_msgin2a:
+	CLEAR ACK
+	JUMP redo_msgin2
+ENTRY resume_msgin2b
+resume_msgin2b:
+	SET ATN
+	CLEAR ACK
+	INT int_no_msgout2, WHEN NOT MSG_OUT
+	MOVE SCRATCH0 | had_msgout TO SCRATCH0
+	MOVE FROM dsa_msgout, when MSG_OUT
+	JUMP redo_msgin2
+
+get_msgin3:
+	MOVE SCRATCH0 | had_msgin TO SCRATCH0
+	MOVE 1, msgin_buf, WHEN MSG_IN
+	JUMP ext_msg3, IF 0x01		; Extended Message
+	JUMP ignore_msg3, IF 0x02	; Save Data Pointers
+	JUMP ignore_msg3, IF 0x03	; Save Restore Pointers
+	JUMP disc3, IF 0x04		; Disconnect
+	INT int_bad_msg3
+ignore_msg3:
+	CLEAR ACK
+	JUMP redo_msgin3
+ext_msg3:
+	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+	CLEAR ACK
+	MOVE 1, msgin_buf + 1, WHEN MSG_IN
+	JUMP ext_msg3a, IF 0x03
+	INT int_bad_extmsg3a
+ext_msg3a:
+	CLEAR ACK
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+	JUMP ext_msg3b, IF 0x01		; Must be SDTR
+	INT int_bad_extmsg3b
+ext_msg3b:
+	CLEAR ACK
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+	INT int_msg_sdtr3
+disc3:
+	CLEAR ACK
+ENTRY wait_disc3
+wait_disc3:
+	WAIT DISCONNECT
+	INT int_disc3
+ENTRY resume_msgin3a
+resume_msgin3a:
+	CLEAR ACK
+	JUMP redo_msgin3
+ENTRY resume_msgin3b
+resume_msgin3b:
+	SET ATN
+	CLEAR ACK
+	INT int_no_msgout3, WHEN NOT MSG_OUT
+	MOVE SCRATCH0 | had_msgout TO SCRATCH0
+	MOVE FROM dsa_msgout, when MSG_OUT
+	JUMP redo_msgin3
+
+ENTRY resume_rej_ident
+resume_rej_ident:
+	CLEAR ATN
+	MOVE 1, msgin_buf, WHEN MSG_IN
+	INT int_not_rej, IF NOT 0x07		; Reject
+	CLEAR ACK
+	JUMP done_ident
+
+ENTRY reselect
+reselect:
+	; Disable selection timer
+	MOVE CTEST7 | 0x10 TO CTEST7
+	WAIT RESELECT resel_err
+	INT int_resel_not_msgin, WHEN NOT MSG_IN
+	MOVE 1, reselected_identify, WHEN MSG_IN
+	INT int_reselected
+resel_err:
+	MOVE CTEST2 & 0x40 TO SFBR
+	JUMP selected, IF 0x00
+	MOVE SFBR & 0 TO SFBR
+ENTRY patch_new_dsa
+patch_new_dsa:
+	MOVE SFBR | 0x11 TO DSA0
+	MOVE SFBR | 0x22 TO DSA1
+	MOVE SFBR | 0x33 TO DSA2
+	MOVE SFBR | 0x44 TO DSA3
+	JUMP do_select
+
+selected:
+	INT int_selected
+
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/sim710_d.h linux/drivers/scsi/sim710_d.h
--- v2.3.19/linux/drivers/scsi/sim710_d.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/sim710_d.h	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,2360 @@
+u32 SCRIPT[] = {
+/*
+
+
+
+
+
+
+ABSOLUTE dsa_select  = 0
+ABSOLUTE dsa_msgout  = 8
+ABSOLUTE dsa_cmnd    = 16
+ABSOLUTE dsa_status  = 24
+ABSOLUTE dsa_msgin   = 32
+ABSOLUTE dsa_datain  = 40	
+ABSOLUTE dsa_dataout = 1064	
+ABSOLUTE dsa_size     = 2088
+
+ABSOLUTE reselected_identify = 0
+ABSOLUTE msgin_buf = 0
+
+
+
+ABSOLUTE int_bad_extmsg1a	= 0xab930000
+ABSOLUTE int_bad_extmsg1b	= 0xab930001
+ABSOLUTE int_bad_extmsg2a	= 0xab930002
+ABSOLUTE int_bad_extmsg2b	= 0xab930003
+ABSOLUTE int_bad_extmsg3a	= 0xab930004
+ABSOLUTE int_bad_extmsg3b	= 0xab930005
+ABSOLUTE int_bad_msg1		= 0xab930006
+ABSOLUTE int_bad_msg2		= 0xab930007
+ABSOLUTE int_bad_msg3		= 0xab930008
+ABSOLUTE int_cmd_bad_phase	= 0xab930009
+ABSOLUTE int_cmd_complete	= 0xab93000a
+ABSOLUTE int_data_bad_phase	= 0xab93000b
+ABSOLUTE int_msg_sdtr1		= 0xab93000c
+ABSOLUTE int_msg_sdtr2		= 0xab93000d
+ABSOLUTE int_msg_sdtr3		= 0xab93000e
+ABSOLUTE int_no_msgout1		= 0xab93000f
+ABSOLUTE int_no_msgout2		= 0xab930010
+ABSOLUTE int_no_msgout3		= 0xab930011
+ABSOLUTE int_not_cmd_complete	= 0xab930012
+ABSOLUTE int_sel_no_ident	= 0xab930013
+ABSOLUTE int_sel_not_cmd	= 0xab930014
+ABSOLUTE int_status_not_msgin	= 0xab930015
+ABSOLUTE int_resel_not_msgin	= 0xab930016
+ABSOLUTE int_reselected		= 0xab930017
+ABSOLUTE int_selected		= 0xab930018
+ABSOLUTE int_disc1		= 0xab930019
+ABSOLUTE int_disc2		= 0xab93001a
+ABSOLUTE int_disc3		= 0xab93001b
+ABSOLUTE int_not_rej		= 0xab93001c
+
+
+
+
+ABSOLUTE had_select	= 0x01
+ABSOLUTE had_msgout	= 0x02
+ABSOLUTE had_cmdout	= 0x04
+ABSOLUTE had_datain	= 0x08
+ABSOLUTE had_dataout	= 0x10
+ABSOLUTE had_status	= 0x20
+ABSOLUTE had_msgin	= 0x40
+ABSOLUTE had_extmsg	= 0x80
+
+
+
+
+
+
+ENTRY do_select
+do_select:
+	CLEAR TARGET
+
+at 0x00000000 : */	0x60000200,0x00000000,
+/*
+	MOVE SCRATCH0 & 0 TO SCRATCH0
+
+at 0x00000002 : */	0x7c340000,0x00000000,
+/*
+	; Enable selection timer
+	MOVE CTEST7 & 0xef TO CTEST7
+
+at 0x00000004 : */	0x7c1bef00,0x00000000,
+/*
+	SELECT ATN FROM dsa_select, reselect
+
+at 0x00000006 : */	0x43000000,0x00000c48,
+/*
+	JUMP get_status, WHEN STATUS
+
+at 0x00000008 : */	0x830b0000,0x000000a0,
+/*
+	; Disable selection timer
+	MOVE CTEST7 | 0x10 TO CTEST7
+
+at 0x0000000a : */	0x7a1b1000,0x00000000,
+/*
+	MOVE SCRATCH0 | had_select TO SCRATCH0
+
+at 0x0000000c : */	0x7a340100,0x00000000,
+/*
+	INT int_sel_no_ident, IF NOT MSG_OUT
+
+at 0x0000000e : */	0x9e020000,0xab930013,
+/*
+	MOVE SCRATCH0 | had_msgout TO SCRATCH0
+
+at 0x00000010 : */	0x7a340200,0x00000000,
+/*
+	MOVE FROM dsa_msgout, when MSG_OUT
+
+at 0x00000012 : */	0x1e000000,0x00000008,
+/*
+ENTRY done_ident
+done_ident:
+	JUMP get_status, IF STATUS
+
+at 0x00000014 : */	0x830a0000,0x000000a0,
+/*
+redo_msgin1:
+	JUMP get_msgin1, WHEN MSG_IN
+
+at 0x00000016 : */	0x870b0000,0x00000920,
+/*
+	INT int_sel_not_cmd, IF NOT CMD
+
+at 0x00000018 : */	0x9a020000,0xab930014,
+/*
+ENTRY resume_cmd
+resume_cmd:
+	MOVE SCRATCH0 | had_cmdout TO SCRATCH0
+
+at 0x0000001a : */	0x7a340400,0x00000000,
+/*
+	MOVE FROM dsa_cmnd, WHEN CMD
+
+at 0x0000001c : */	0x1a000000,0x00000010,
+/*
+ENTRY resume_pmm
+resume_pmm:
+redo_msgin2:
+	JUMP get_msgin2, WHEN MSG_IN
+
+at 0x0000001e : */	0x870b0000,0x00000a20,
+/*
+	JUMP get_status, IF STATUS
+
+at 0x00000020 : */	0x830a0000,0x000000a0,
+/*
+	JUMP input_data, IF DATA_IN
+
+at 0x00000022 : */	0x810a0000,0x000000e0,
+/*
+	JUMP output_data, IF DATA_OUT
+
+at 0x00000024 : */	0x800a0000,0x000004f8,
+/*
+	INT int_cmd_bad_phase
+
+at 0x00000026 : */	0x98080000,0xab930009,
+/*
+
+get_status:
+	; Disable selection timer
+	MOVE CTEST7 | 0x10 TO CTEST7
+
+at 0x00000028 : */	0x7a1b1000,0x00000000,
+/*
+	MOVE FROM dsa_status, WHEN STATUS
+
+at 0x0000002a : */	0x1b000000,0x00000018,
+/*
+	INT int_status_not_msgin, WHEN NOT MSG_IN
+
+at 0x0000002c : */	0x9f030000,0xab930015,
+/*
+	MOVE FROM dsa_msgin, WHEN MSG_IN
+
+at 0x0000002e : */	0x1f000000,0x00000020,
+/*
+	INT int_not_cmd_complete, IF NOT 0x00
+
+at 0x00000030 : */	0x98040000,0xab930012,
+/*
+	CLEAR ACK
+
+at 0x00000032 : */	0x60000040,0x00000000,
+/*
+ENTRY wait_disc_complete
+wait_disc_complete:
+	WAIT DISCONNECT
+
+at 0x00000034 : */	0x48000000,0x00000000,
+/*
+	INT int_cmd_complete
+
+at 0x00000036 : */	0x98080000,0xab93000a,
+/*
+
+input_data:
+	MOVE SCRATCH0 | had_datain TO SCRATCH0
+
+at 0x00000038 : */	0x7a340800,0x00000000,
+/*
+ENTRY patch_input_data
+patch_input_data:
+	JUMP 0
+
+at 0x0000003a : */	0x80080000,0x00000000,
+/*
+	MOVE FROM dsa_datain+0x0000, WHEN DATA_IN
+
+at 0x0000003c : */	0x19000000,0x00000028,
+/*
+	MOVE FROM dsa_datain+0x0008, WHEN DATA_IN
+
+at 0x0000003e : */	0x19000000,0x00000030,
+/*
+	MOVE FROM dsa_datain+0x0010, WHEN DATA_IN
+
+at 0x00000040 : */	0x19000000,0x00000038,
+/*
+	MOVE FROM dsa_datain+0x0018, WHEN DATA_IN
+
+at 0x00000042 : */	0x19000000,0x00000040,
+/*
+	MOVE FROM dsa_datain+0x0020, WHEN DATA_IN
+
+at 0x00000044 : */	0x19000000,0x00000048,
+/*
+	MOVE FROM dsa_datain+0x0028, WHEN DATA_IN
+
+at 0x00000046 : */	0x19000000,0x00000050,
+/*
+	MOVE FROM dsa_datain+0x0030, WHEN DATA_IN
+
+at 0x00000048 : */	0x19000000,0x00000058,
+/*
+	MOVE FROM dsa_datain+0x0038, WHEN DATA_IN
+
+at 0x0000004a : */	0x19000000,0x00000060,
+/*
+	MOVE FROM dsa_datain+0x0040, WHEN DATA_IN
+
+at 0x0000004c : */	0x19000000,0x00000068,
+/*
+	MOVE FROM dsa_datain+0x0048, WHEN DATA_IN
+
+at 0x0000004e : */	0x19000000,0x00000070,
+/*
+	MOVE FROM dsa_datain+0x0050, WHEN DATA_IN
+
+at 0x00000050 : */	0x19000000,0x00000078,
+/*
+	MOVE FROM dsa_datain+0x0058, WHEN DATA_IN
+
+at 0x00000052 : */	0x19000000,0x00000080,
+/*
+	MOVE FROM dsa_datain+0x0060, WHEN DATA_IN
+
+at 0x00000054 : */	0x19000000,0x00000088,
+/*
+	MOVE FROM dsa_datain+0x0068, WHEN DATA_IN
+
+at 0x00000056 : */	0x19000000,0x00000090,
+/*
+	MOVE FROM dsa_datain+0x0070, WHEN DATA_IN
+
+at 0x00000058 : */	0x19000000,0x00000098,
+/*
+	MOVE FROM dsa_datain+0x0078, WHEN DATA_IN
+
+at 0x0000005a : */	0x19000000,0x000000a0,
+/*
+	MOVE FROM dsa_datain+0x0080, WHEN DATA_IN
+
+at 0x0000005c : */	0x19000000,0x000000a8,
+/*
+	MOVE FROM dsa_datain+0x0088, WHEN DATA_IN
+
+at 0x0000005e : */	0x19000000,0x000000b0,
+/*
+	MOVE FROM dsa_datain+0x0090, WHEN DATA_IN
+
+at 0x00000060 : */	0x19000000,0x000000b8,
+/*
+	MOVE FROM dsa_datain+0x0098, WHEN DATA_IN
+
+at 0x00000062 : */	0x19000000,0x000000c0,
+/*
+	MOVE FROM dsa_datain+0x00a0, WHEN DATA_IN
+
+at 0x00000064 : */	0x19000000,0x000000c8,
+/*
+	MOVE FROM dsa_datain+0x00a8, WHEN DATA_IN
+
+at 0x00000066 : */	0x19000000,0x000000d0,
+/*
+	MOVE FROM dsa_datain+0x00b0, WHEN DATA_IN
+
+at 0x00000068 : */	0x19000000,0x000000d8,
+/*
+	MOVE FROM dsa_datain+0x00b8, WHEN DATA_IN
+
+at 0x0000006a : */	0x19000000,0x000000e0,
+/*
+	MOVE FROM dsa_datain+0x00c0, WHEN DATA_IN
+
+at 0x0000006c : */	0x19000000,0x000000e8,
+/*
+	MOVE FROM dsa_datain+0x00c8, WHEN DATA_IN
+
+at 0x0000006e : */	0x19000000,0x000000f0,
+/*
+	MOVE FROM dsa_datain+0x00d0, WHEN DATA_IN
+
+at 0x00000070 : */	0x19000000,0x000000f8,
+/*
+	MOVE FROM dsa_datain+0x00d8, WHEN DATA_IN
+
+at 0x00000072 : */	0x19000000,0x00000100,
+/*
+	MOVE FROM dsa_datain+0x00e0, WHEN DATA_IN
+
+at 0x00000074 : */	0x19000000,0x00000108,
+/*
+	MOVE FROM dsa_datain+0x00e8, WHEN DATA_IN
+
+at 0x00000076 : */	0x19000000,0x00000110,
+/*
+	MOVE FROM dsa_datain+0x00f0, WHEN DATA_IN
+
+at 0x00000078 : */	0x19000000,0x00000118,
+/*
+	MOVE FROM dsa_datain+0x00f8, WHEN DATA_IN
+
+at 0x0000007a : */	0x19000000,0x00000120,
+/*
+	MOVE FROM dsa_datain+0x0100, WHEN DATA_IN
+
+at 0x0000007c : */	0x19000000,0x00000128,
+/*
+	MOVE FROM dsa_datain+0x0108, WHEN DATA_IN
+
+at 0x0000007e : */	0x19000000,0x00000130,
+/*
+	MOVE FROM dsa_datain+0x0110, WHEN DATA_IN
+
+at 0x00000080 : */	0x19000000,0x00000138,
+/*
+	MOVE FROM dsa_datain+0x0118, WHEN DATA_IN
+
+at 0x00000082 : */	0x19000000,0x00000140,
+/*
+	MOVE FROM dsa_datain+0x0120, WHEN DATA_IN
+
+at 0x00000084 : */	0x19000000,0x00000148,
+/*
+	MOVE FROM dsa_datain+0x0128, WHEN DATA_IN
+
+at 0x00000086 : */	0x19000000,0x00000150,
+/*
+	MOVE FROM dsa_datain+0x0130, WHEN DATA_IN
+
+at 0x00000088 : */	0x19000000,0x00000158,
+/*
+	MOVE FROM dsa_datain+0x0138, WHEN DATA_IN
+
+at 0x0000008a : */	0x19000000,0x00000160,
+/*
+	MOVE FROM dsa_datain+0x0140, WHEN DATA_IN
+
+at 0x0000008c : */	0x19000000,0x00000168,
+/*
+	MOVE FROM dsa_datain+0x0148, WHEN DATA_IN
+
+at 0x0000008e : */	0x19000000,0x00000170,
+/*
+	MOVE FROM dsa_datain+0x0150, WHEN DATA_IN
+
+at 0x00000090 : */	0x19000000,0x00000178,
+/*
+	MOVE FROM dsa_datain+0x0158, WHEN DATA_IN
+
+at 0x00000092 : */	0x19000000,0x00000180,
+/*
+	MOVE FROM dsa_datain+0x0160, WHEN DATA_IN
+
+at 0x00000094 : */	0x19000000,0x00000188,
+/*
+	MOVE FROM dsa_datain+0x0168, WHEN DATA_IN
+
+at 0x00000096 : */	0x19000000,0x00000190,
+/*
+	MOVE FROM dsa_datain+0x0170, WHEN DATA_IN
+
+at 0x00000098 : */	0x19000000,0x00000198,
+/*
+	MOVE FROM dsa_datain+0x0178, WHEN DATA_IN
+
+at 0x0000009a : */	0x19000000,0x000001a0,
+/*
+	MOVE FROM dsa_datain+0x0180, WHEN DATA_IN
+
+at 0x0000009c : */	0x19000000,0x000001a8,
+/*
+	MOVE FROM dsa_datain+0x0188, WHEN DATA_IN
+
+at 0x0000009e : */	0x19000000,0x000001b0,
+/*
+	MOVE FROM dsa_datain+0x0190, WHEN DATA_IN
+
+at 0x000000a0 : */	0x19000000,0x000001b8,
+/*
+	MOVE FROM dsa_datain+0x0198, WHEN DATA_IN
+
+at 0x000000a2 : */	0x19000000,0x000001c0,
+/*
+	MOVE FROM dsa_datain+0x01a0, WHEN DATA_IN
+
+at 0x000000a4 : */	0x19000000,0x000001c8,
+/*
+	MOVE FROM dsa_datain+0x01a8, WHEN DATA_IN
+
+at 0x000000a6 : */	0x19000000,0x000001d0,
+/*
+	MOVE FROM dsa_datain+0x01b0, WHEN DATA_IN
+
+at 0x000000a8 : */	0x19000000,0x000001d8,
+/*
+	MOVE FROM dsa_datain+0x01b8, WHEN DATA_IN
+
+at 0x000000aa : */	0x19000000,0x000001e0,
+/*
+	MOVE FROM dsa_datain+0x01c0, WHEN DATA_IN
+
+at 0x000000ac : */	0x19000000,0x000001e8,
+/*
+	MOVE FROM dsa_datain+0x01c8, WHEN DATA_IN
+
+at 0x000000ae : */	0x19000000,0x000001f0,
+/*
+	MOVE FROM dsa_datain+0x01d0, WHEN DATA_IN
+
+at 0x000000b0 : */	0x19000000,0x000001f8,
+/*
+	MOVE FROM dsa_datain+0x01d8, WHEN DATA_IN
+
+at 0x000000b2 : */	0x19000000,0x00000200,
+/*
+	MOVE FROM dsa_datain+0x01e0, WHEN DATA_IN
+
+at 0x000000b4 : */	0x19000000,0x00000208,
+/*
+	MOVE FROM dsa_datain+0x01e8, WHEN DATA_IN
+
+at 0x000000b6 : */	0x19000000,0x00000210,
+/*
+	MOVE FROM dsa_datain+0x01f0, WHEN DATA_IN
+
+at 0x000000b8 : */	0x19000000,0x00000218,
+/*
+	MOVE FROM dsa_datain+0x01f8, WHEN DATA_IN
+
+at 0x000000ba : */	0x19000000,0x00000220,
+/*
+	MOVE FROM dsa_datain+0x0200, WHEN DATA_IN
+
+at 0x000000bc : */	0x19000000,0x00000228,
+/*
+	MOVE FROM dsa_datain+0x0208, WHEN DATA_IN
+
+at 0x000000be : */	0x19000000,0x00000230,
+/*
+	MOVE FROM dsa_datain+0x0210, WHEN DATA_IN
+
+at 0x000000c0 : */	0x19000000,0x00000238,
+/*
+	MOVE FROM dsa_datain+0x0218, WHEN DATA_IN
+
+at 0x000000c2 : */	0x19000000,0x00000240,
+/*
+	MOVE FROM dsa_datain+0x0220, WHEN DATA_IN
+
+at 0x000000c4 : */	0x19000000,0x00000248,
+/*
+	MOVE FROM dsa_datain+0x0228, WHEN DATA_IN
+
+at 0x000000c6 : */	0x19000000,0x00000250,
+/*
+	MOVE FROM dsa_datain+0x0230, WHEN DATA_IN
+
+at 0x000000c8 : */	0x19000000,0x00000258,
+/*
+	MOVE FROM dsa_datain+0x0238, WHEN DATA_IN
+
+at 0x000000ca : */	0x19000000,0x00000260,
+/*
+	MOVE FROM dsa_datain+0x0240, WHEN DATA_IN
+
+at 0x000000cc : */	0x19000000,0x00000268,
+/*
+	MOVE FROM dsa_datain+0x0248, WHEN DATA_IN
+
+at 0x000000ce : */	0x19000000,0x00000270,
+/*
+	MOVE FROM dsa_datain+0x0250, WHEN DATA_IN
+
+at 0x000000d0 : */	0x19000000,0x00000278,
+/*
+	MOVE FROM dsa_datain+0x0258, WHEN DATA_IN
+
+at 0x000000d2 : */	0x19000000,0x00000280,
+/*
+	MOVE FROM dsa_datain+0x0260, WHEN DATA_IN
+
+at 0x000000d4 : */	0x19000000,0x00000288,
+/*
+	MOVE FROM dsa_datain+0x0268, WHEN DATA_IN
+
+at 0x000000d6 : */	0x19000000,0x00000290,
+/*
+	MOVE FROM dsa_datain+0x0270, WHEN DATA_IN
+
+at 0x000000d8 : */	0x19000000,0x00000298,
+/*
+	MOVE FROM dsa_datain+0x0278, WHEN DATA_IN
+
+at 0x000000da : */	0x19000000,0x000002a0,
+/*
+	MOVE FROM dsa_datain+0x0280, WHEN DATA_IN
+
+at 0x000000dc : */	0x19000000,0x000002a8,
+/*
+	MOVE FROM dsa_datain+0x0288, WHEN DATA_IN
+
+at 0x000000de : */	0x19000000,0x000002b0,
+/*
+	MOVE FROM dsa_datain+0x0290, WHEN DATA_IN
+
+at 0x000000e0 : */	0x19000000,0x000002b8,
+/*
+	MOVE FROM dsa_datain+0x0298, WHEN DATA_IN
+
+at 0x000000e2 : */	0x19000000,0x000002c0,
+/*
+	MOVE FROM dsa_datain+0x02a0, WHEN DATA_IN
+
+at 0x000000e4 : */	0x19000000,0x000002c8,
+/*
+	MOVE FROM dsa_datain+0x02a8, WHEN DATA_IN
+
+at 0x000000e6 : */	0x19000000,0x000002d0,
+/*
+	MOVE FROM dsa_datain+0x02b0, WHEN DATA_IN
+
+at 0x000000e8 : */	0x19000000,0x000002d8,
+/*
+	MOVE FROM dsa_datain+0x02b8, WHEN DATA_IN
+
+at 0x000000ea : */	0x19000000,0x000002e0,
+/*
+	MOVE FROM dsa_datain+0x02c0, WHEN DATA_IN
+
+at 0x000000ec : */	0x19000000,0x000002e8,
+/*
+	MOVE FROM dsa_datain+0x02c8, WHEN DATA_IN
+
+at 0x000000ee : */	0x19000000,0x000002f0,
+/*
+	MOVE FROM dsa_datain+0x02d0, WHEN DATA_IN
+
+at 0x000000f0 : */	0x19000000,0x000002f8,
+/*
+	MOVE FROM dsa_datain+0x02d8, WHEN DATA_IN
+
+at 0x000000f2 : */	0x19000000,0x00000300,
+/*
+	MOVE FROM dsa_datain+0x02e0, WHEN DATA_IN
+
+at 0x000000f4 : */	0x19000000,0x00000308,
+/*
+	MOVE FROM dsa_datain+0x02e8, WHEN DATA_IN
+
+at 0x000000f6 : */	0x19000000,0x00000310,
+/*
+	MOVE FROM dsa_datain+0x02f0, WHEN DATA_IN
+
+at 0x000000f8 : */	0x19000000,0x00000318,
+/*
+	MOVE FROM dsa_datain+0x02f8, WHEN DATA_IN
+
+at 0x000000fa : */	0x19000000,0x00000320,
+/*
+	MOVE FROM dsa_datain+0x0300, WHEN DATA_IN
+
+at 0x000000fc : */	0x19000000,0x00000328,
+/*
+	MOVE FROM dsa_datain+0x0308, WHEN DATA_IN
+
+at 0x000000fe : */	0x19000000,0x00000330,
+/*
+	MOVE FROM dsa_datain+0x0310, WHEN DATA_IN
+
+at 0x00000100 : */	0x19000000,0x00000338,
+/*
+	MOVE FROM dsa_datain+0x0318, WHEN DATA_IN
+
+at 0x00000102 : */	0x19000000,0x00000340,
+/*
+	MOVE FROM dsa_datain+0x0320, WHEN DATA_IN
+
+at 0x00000104 : */	0x19000000,0x00000348,
+/*
+	MOVE FROM dsa_datain+0x0328, WHEN DATA_IN
+
+at 0x00000106 : */	0x19000000,0x00000350,
+/*
+	MOVE FROM dsa_datain+0x0330, WHEN DATA_IN
+
+at 0x00000108 : */	0x19000000,0x00000358,
+/*
+	MOVE FROM dsa_datain+0x0338, WHEN DATA_IN
+
+at 0x0000010a : */	0x19000000,0x00000360,
+/*
+	MOVE FROM dsa_datain+0x0340, WHEN DATA_IN
+
+at 0x0000010c : */	0x19000000,0x00000368,
+/*
+	MOVE FROM dsa_datain+0x0348, WHEN DATA_IN
+
+at 0x0000010e : */	0x19000000,0x00000370,
+/*
+	MOVE FROM dsa_datain+0x0350, WHEN DATA_IN
+
+at 0x00000110 : */	0x19000000,0x00000378,
+/*
+	MOVE FROM dsa_datain+0x0358, WHEN DATA_IN
+
+at 0x00000112 : */	0x19000000,0x00000380,
+/*
+	MOVE FROM dsa_datain+0x0360, WHEN DATA_IN
+
+at 0x00000114 : */	0x19000000,0x00000388,
+/*
+	MOVE FROM dsa_datain+0x0368, WHEN DATA_IN
+
+at 0x00000116 : */	0x19000000,0x00000390,
+/*
+	MOVE FROM dsa_datain+0x0370, WHEN DATA_IN
+
+at 0x00000118 : */	0x19000000,0x00000398,
+/*
+	MOVE FROM dsa_datain+0x0378, WHEN DATA_IN
+
+at 0x0000011a : */	0x19000000,0x000003a0,
+/*
+	MOVE FROM dsa_datain+0x0380, WHEN DATA_IN
+
+at 0x0000011c : */	0x19000000,0x000003a8,
+/*
+	MOVE FROM dsa_datain+0x0388, WHEN DATA_IN
+
+at 0x0000011e : */	0x19000000,0x000003b0,
+/*
+	MOVE FROM dsa_datain+0x0390, WHEN DATA_IN
+
+at 0x00000120 : */	0x19000000,0x000003b8,
+/*
+	MOVE FROM dsa_datain+0x0398, WHEN DATA_IN
+
+at 0x00000122 : */	0x19000000,0x000003c0,
+/*
+	MOVE FROM dsa_datain+0x03a0, WHEN DATA_IN
+
+at 0x00000124 : */	0x19000000,0x000003c8,
+/*
+	MOVE FROM dsa_datain+0x03a8, WHEN DATA_IN
+
+at 0x00000126 : */	0x19000000,0x000003d0,
+/*
+	MOVE FROM dsa_datain+0x03b0, WHEN DATA_IN
+
+at 0x00000128 : */	0x19000000,0x000003d8,
+/*
+	MOVE FROM dsa_datain+0x03b8, WHEN DATA_IN
+
+at 0x0000012a : */	0x19000000,0x000003e0,
+/*
+	MOVE FROM dsa_datain+0x03c0, WHEN DATA_IN
+
+at 0x0000012c : */	0x19000000,0x000003e8,
+/*
+	MOVE FROM dsa_datain+0x03c8, WHEN DATA_IN
+
+at 0x0000012e : */	0x19000000,0x000003f0,
+/*
+	MOVE FROM dsa_datain+0x03d0, WHEN DATA_IN
+
+at 0x00000130 : */	0x19000000,0x000003f8,
+/*
+	MOVE FROM dsa_datain+0x03d8, WHEN DATA_IN
+
+at 0x00000132 : */	0x19000000,0x00000400,
+/*
+	MOVE FROM dsa_datain+0x03e0, WHEN DATA_IN
+
+at 0x00000134 : */	0x19000000,0x00000408,
+/*
+	MOVE FROM dsa_datain+0x03e8, WHEN DATA_IN
+
+at 0x00000136 : */	0x19000000,0x00000410,
+/*
+	MOVE FROM dsa_datain+0x03f0, WHEN DATA_IN
+
+at 0x00000138 : */	0x19000000,0x00000418,
+/*
+	MOVE FROM dsa_datain+0x03f8, WHEN DATA_IN
+
+at 0x0000013a : */	0x19000000,0x00000420,
+/*
+	JUMP end_data_trans
+
+at 0x0000013c : */	0x80080000,0x00000908,
+/*
+
+output_data:
+	MOVE SCRATCH0 | had_dataout TO SCRATCH0
+
+at 0x0000013e : */	0x7a341000,0x00000000,
+/*
+ENTRY patch_output_data
+patch_output_data:
+	JUMP 0
+
+at 0x00000140 : */	0x80080000,0x00000000,
+/*
+	MOVE FROM dsa_dataout+0x0000, WHEN DATA_OUT
+
+at 0x00000142 : */	0x18000000,0x00000428,
+/*
+	MOVE FROM dsa_dataout+0x0008, WHEN DATA_OUT
+
+at 0x00000144 : */	0x18000000,0x00000430,
+/*
+	MOVE FROM dsa_dataout+0x0010, WHEN DATA_OUT
+
+at 0x00000146 : */	0x18000000,0x00000438,
+/*
+	MOVE FROM dsa_dataout+0x0018, WHEN DATA_OUT
+
+at 0x00000148 : */	0x18000000,0x00000440,
+/*
+	MOVE FROM dsa_dataout+0x0020, WHEN DATA_OUT
+
+at 0x0000014a : */	0x18000000,0x00000448,
+/*
+	MOVE FROM dsa_dataout+0x0028, WHEN DATA_OUT
+
+at 0x0000014c : */	0x18000000,0x00000450,
+/*
+	MOVE FROM dsa_dataout+0x0030, WHEN DATA_OUT
+
+at 0x0000014e : */	0x18000000,0x00000458,
+/*
+	MOVE FROM dsa_dataout+0x0038, WHEN DATA_OUT
+
+at 0x00000150 : */	0x18000000,0x00000460,
+/*
+	MOVE FROM dsa_dataout+0x0040, WHEN DATA_OUT
+
+at 0x00000152 : */	0x18000000,0x00000468,
+/*
+	MOVE FROM dsa_dataout+0x0048, WHEN DATA_OUT
+
+at 0x00000154 : */	0x18000000,0x00000470,
+/*
+	MOVE FROM dsa_dataout+0x0050, WHEN DATA_OUT
+
+at 0x00000156 : */	0x18000000,0x00000478,
+/*
+	MOVE FROM dsa_dataout+0x0058, WHEN DATA_OUT
+
+at 0x00000158 : */	0x18000000,0x00000480,
+/*
+	MOVE FROM dsa_dataout+0x0060, WHEN DATA_OUT
+
+at 0x0000015a : */	0x18000000,0x00000488,
+/*
+	MOVE FROM dsa_dataout+0x0068, WHEN DATA_OUT
+
+at 0x0000015c : */	0x18000000,0x00000490,
+/*
+	MOVE FROM dsa_dataout+0x0070, WHEN DATA_OUT
+
+at 0x0000015e : */	0x18000000,0x00000498,
+/*
+	MOVE FROM dsa_dataout+0x0078, WHEN DATA_OUT
+
+at 0x00000160 : */	0x18000000,0x000004a0,
+/*
+	MOVE FROM dsa_dataout+0x0080, WHEN DATA_OUT
+
+at 0x00000162 : */	0x18000000,0x000004a8,
+/*
+	MOVE FROM dsa_dataout+0x0088, WHEN DATA_OUT
+
+at 0x00000164 : */	0x18000000,0x000004b0,
+/*
+	MOVE FROM dsa_dataout+0x0090, WHEN DATA_OUT
+
+at 0x00000166 : */	0x18000000,0x000004b8,
+/*
+	MOVE FROM dsa_dataout+0x0098, WHEN DATA_OUT
+
+at 0x00000168 : */	0x18000000,0x000004c0,
+/*
+	MOVE FROM dsa_dataout+0x00a0, WHEN DATA_OUT
+
+at 0x0000016a : */	0x18000000,0x000004c8,
+/*
+	MOVE FROM dsa_dataout+0x00a8, WHEN DATA_OUT
+
+at 0x0000016c : */	0x18000000,0x000004d0,
+/*
+	MOVE FROM dsa_dataout+0x00b0, WHEN DATA_OUT
+
+at 0x0000016e : */	0x18000000,0x000004d8,
+/*
+	MOVE FROM dsa_dataout+0x00b8, WHEN DATA_OUT
+
+at 0x00000170 : */	0x18000000,0x000004e0,
+/*
+	MOVE FROM dsa_dataout+0x00c0, WHEN DATA_OUT
+
+at 0x00000172 : */	0x18000000,0x000004e8,
+/*
+	MOVE FROM dsa_dataout+0x00c8, WHEN DATA_OUT
+
+at 0x00000174 : */	0x18000000,0x000004f0,
+/*
+	MOVE FROM dsa_dataout+0x00d0, WHEN DATA_OUT
+
+at 0x00000176 : */	0x18000000,0x000004f8,
+/*
+	MOVE FROM dsa_dataout+0x00d8, WHEN DATA_OUT
+
+at 0x00000178 : */	0x18000000,0x00000500,
+/*
+	MOVE FROM dsa_dataout+0x00e0, WHEN DATA_OUT
+
+at 0x0000017a : */	0x18000000,0x00000508,
+/*
+	MOVE FROM dsa_dataout+0x00e8, WHEN DATA_OUT
+
+at 0x0000017c : */	0x18000000,0x00000510,
+/*
+	MOVE FROM dsa_dataout+0x00f0, WHEN DATA_OUT
+
+at 0x0000017e : */	0x18000000,0x00000518,
+/*
+	MOVE FROM dsa_dataout+0x00f8, WHEN DATA_OUT
+
+at 0x00000180 : */	0x18000000,0x00000520,
+/*
+	MOVE FROM dsa_dataout+0x0100, WHEN DATA_OUT
+
+at 0x00000182 : */	0x18000000,0x00000528,
+/*
+	MOVE FROM dsa_dataout+0x0108, WHEN DATA_OUT
+
+at 0x00000184 : */	0x18000000,0x00000530,
+/*
+	MOVE FROM dsa_dataout+0x0110, WHEN DATA_OUT
+
+at 0x00000186 : */	0x18000000,0x00000538,
+/*
+	MOVE FROM dsa_dataout+0x0118, WHEN DATA_OUT
+
+at 0x00000188 : */	0x18000000,0x00000540,
+/*
+	MOVE FROM dsa_dataout+0x0120, WHEN DATA_OUT
+
+at 0x0000018a : */	0x18000000,0x00000548,
+/*
+	MOVE FROM dsa_dataout+0x0128, WHEN DATA_OUT
+
+at 0x0000018c : */	0x18000000,0x00000550,
+/*
+	MOVE FROM dsa_dataout+0x0130, WHEN DATA_OUT
+
+at 0x0000018e : */	0x18000000,0x00000558,
+/*
+	MOVE FROM dsa_dataout+0x0138, WHEN DATA_OUT
+
+at 0x00000190 : */	0x18000000,0x00000560,
+/*
+	MOVE FROM dsa_dataout+0x0140, WHEN DATA_OUT
+
+at 0x00000192 : */	0x18000000,0x00000568,
+/*
+	MOVE FROM dsa_dataout+0x0148, WHEN DATA_OUT
+
+at 0x00000194 : */	0x18000000,0x00000570,
+/*
+	MOVE FROM dsa_dataout+0x0150, WHEN DATA_OUT
+
+at 0x00000196 : */	0x18000000,0x00000578,
+/*
+	MOVE FROM dsa_dataout+0x0158, WHEN DATA_OUT
+
+at 0x00000198 : */	0x18000000,0x00000580,
+/*
+	MOVE FROM dsa_dataout+0x0160, WHEN DATA_OUT
+
+at 0x0000019a : */	0x18000000,0x00000588,
+/*
+	MOVE FROM dsa_dataout+0x0168, WHEN DATA_OUT
+
+at 0x0000019c : */	0x18000000,0x00000590,
+/*
+	MOVE FROM dsa_dataout+0x0170, WHEN DATA_OUT
+
+at 0x0000019e : */	0x18000000,0x00000598,
+/*
+	MOVE FROM dsa_dataout+0x0178, WHEN DATA_OUT
+
+at 0x000001a0 : */	0x18000000,0x000005a0,
+/*
+	MOVE FROM dsa_dataout+0x0180, WHEN DATA_OUT
+
+at 0x000001a2 : */	0x18000000,0x000005a8,
+/*
+	MOVE FROM dsa_dataout+0x0188, WHEN DATA_OUT
+
+at 0x000001a4 : */	0x18000000,0x000005b0,
+/*
+	MOVE FROM dsa_dataout+0x0190, WHEN DATA_OUT
+
+at 0x000001a6 : */	0x18000000,0x000005b8,
+/*
+	MOVE FROM dsa_dataout+0x0198, WHEN DATA_OUT
+
+at 0x000001a8 : */	0x18000000,0x000005c0,
+/*
+	MOVE FROM dsa_dataout+0x01a0, WHEN DATA_OUT
+
+at 0x000001aa : */	0x18000000,0x000005c8,
+/*
+	MOVE FROM dsa_dataout+0x01a8, WHEN DATA_OUT
+
+at 0x000001ac : */	0x18000000,0x000005d0,
+/*
+	MOVE FROM dsa_dataout+0x01b0, WHEN DATA_OUT
+
+at 0x000001ae : */	0x18000000,0x000005d8,
+/*
+	MOVE FROM dsa_dataout+0x01b8, WHEN DATA_OUT
+
+at 0x000001b0 : */	0x18000000,0x000005e0,
+/*
+	MOVE FROM dsa_dataout+0x01c0, WHEN DATA_OUT
+
+at 0x000001b2 : */	0x18000000,0x000005e8,
+/*
+	MOVE FROM dsa_dataout+0x01c8, WHEN DATA_OUT
+
+at 0x000001b4 : */	0x18000000,0x000005f0,
+/*
+	MOVE FROM dsa_dataout+0x01d0, WHEN DATA_OUT
+
+at 0x000001b6 : */	0x18000000,0x000005f8,
+/*
+	MOVE FROM dsa_dataout+0x01d8, WHEN DATA_OUT
+
+at 0x000001b8 : */	0x18000000,0x00000600,
+/*
+	MOVE FROM dsa_dataout+0x01e0, WHEN DATA_OUT
+
+at 0x000001ba : */	0x18000000,0x00000608,
+/*
+	MOVE FROM dsa_dataout+0x01e8, WHEN DATA_OUT
+
+at 0x000001bc : */	0x18000000,0x00000610,
+/*
+	MOVE FROM dsa_dataout+0x01f0, WHEN DATA_OUT
+
+at 0x000001be : */	0x18000000,0x00000618,
+/*
+	MOVE FROM dsa_dataout+0x01f8, WHEN DATA_OUT
+
+at 0x000001c0 : */	0x18000000,0x00000620,
+/*
+	MOVE FROM dsa_dataout+0x0200, WHEN DATA_OUT
+
+at 0x000001c2 : */	0x18000000,0x00000628,
+/*
+	MOVE FROM dsa_dataout+0x0208, WHEN DATA_OUT
+
+at 0x000001c4 : */	0x18000000,0x00000630,
+/*
+	MOVE FROM dsa_dataout+0x0210, WHEN DATA_OUT
+
+at 0x000001c6 : */	0x18000000,0x00000638,
+/*
+	MOVE FROM dsa_dataout+0x0218, WHEN DATA_OUT
+
+at 0x000001c8 : */	0x18000000,0x00000640,
+/*
+	MOVE FROM dsa_dataout+0x0220, WHEN DATA_OUT
+
+at 0x000001ca : */	0x18000000,0x00000648,
+/*
+	MOVE FROM dsa_dataout+0x0228, WHEN DATA_OUT
+
+at 0x000001cc : */	0x18000000,0x00000650,
+/*
+	MOVE FROM dsa_dataout+0x0230, WHEN DATA_OUT
+
+at 0x000001ce : */	0x18000000,0x00000658,
+/*
+	MOVE FROM dsa_dataout+0x0238, WHEN DATA_OUT
+
+at 0x000001d0 : */	0x18000000,0x00000660,
+/*
+	MOVE FROM dsa_dataout+0x0240, WHEN DATA_OUT
+
+at 0x000001d2 : */	0x18000000,0x00000668,
+/*
+	MOVE FROM dsa_dataout+0x0248, WHEN DATA_OUT
+
+at 0x000001d4 : */	0x18000000,0x00000670,
+/*
+	MOVE FROM dsa_dataout+0x0250, WHEN DATA_OUT
+
+at 0x000001d6 : */	0x18000000,0x00000678,
+/*
+	MOVE FROM dsa_dataout+0x0258, WHEN DATA_OUT
+
+at 0x000001d8 : */	0x18000000,0x00000680,
+/*
+	MOVE FROM dsa_dataout+0x0260, WHEN DATA_OUT
+
+at 0x000001da : */	0x18000000,0x00000688,
+/*
+	MOVE FROM dsa_dataout+0x0268, WHEN DATA_OUT
+
+at 0x000001dc : */	0x18000000,0x00000690,
+/*
+	MOVE FROM dsa_dataout+0x0270, WHEN DATA_OUT
+
+at 0x000001de : */	0x18000000,0x00000698,
+/*
+	MOVE FROM dsa_dataout+0x0278, WHEN DATA_OUT
+
+at 0x000001e0 : */	0x18000000,0x000006a0,
+/*
+	MOVE FROM dsa_dataout+0x0280, WHEN DATA_OUT
+
+at 0x000001e2 : */	0x18000000,0x000006a8,
+/*
+	MOVE FROM dsa_dataout+0x0288, WHEN DATA_OUT
+
+at 0x000001e4 : */	0x18000000,0x000006b0,
+/*
+	MOVE FROM dsa_dataout+0x0290, WHEN DATA_OUT
+
+at 0x000001e6 : */	0x18000000,0x000006b8,
+/*
+	MOVE FROM dsa_dataout+0x0298, WHEN DATA_OUT
+
+at 0x000001e8 : */	0x18000000,0x000006c0,
+/*
+	MOVE FROM dsa_dataout+0x02a0, WHEN DATA_OUT
+
+at 0x000001ea : */	0x18000000,0x000006c8,
+/*
+	MOVE FROM dsa_dataout+0x02a8, WHEN DATA_OUT
+
+at 0x000001ec : */	0x18000000,0x000006d0,
+/*
+	MOVE FROM dsa_dataout+0x02b0, WHEN DATA_OUT
+
+at 0x000001ee : */	0x18000000,0x000006d8,
+/*
+	MOVE FROM dsa_dataout+0x02b8, WHEN DATA_OUT
+
+at 0x000001f0 : */	0x18000000,0x000006e0,
+/*
+	MOVE FROM dsa_dataout+0x02c0, WHEN DATA_OUT
+
+at 0x000001f2 : */	0x18000000,0x000006e8,
+/*
+	MOVE FROM dsa_dataout+0x02c8, WHEN DATA_OUT
+
+at 0x000001f4 : */	0x18000000,0x000006f0,
+/*
+	MOVE FROM dsa_dataout+0x02d0, WHEN DATA_OUT
+
+at 0x000001f6 : */	0x18000000,0x000006f8,
+/*
+	MOVE FROM dsa_dataout+0x02d8, WHEN DATA_OUT
+
+at 0x000001f8 : */	0x18000000,0x00000700,
+/*
+	MOVE FROM dsa_dataout+0x02e0, WHEN DATA_OUT
+
+at 0x000001fa : */	0x18000000,0x00000708,
+/*
+	MOVE FROM dsa_dataout+0x02e8, WHEN DATA_OUT
+
+at 0x000001fc : */	0x18000000,0x00000710,
+/*
+	MOVE FROM dsa_dataout+0x02f0, WHEN DATA_OUT
+
+at 0x000001fe : */	0x18000000,0x00000718,
+/*
+	MOVE FROM dsa_dataout+0x02f8, WHEN DATA_OUT
+
+at 0x00000200 : */	0x18000000,0x00000720,
+/*
+	MOVE FROM dsa_dataout+0x0300, WHEN DATA_OUT
+
+at 0x00000202 : */	0x18000000,0x00000728,
+/*
+	MOVE FROM dsa_dataout+0x0308, WHEN DATA_OUT
+
+at 0x00000204 : */	0x18000000,0x00000730,
+/*
+	MOVE FROM dsa_dataout+0x0310, WHEN DATA_OUT
+
+at 0x00000206 : */	0x18000000,0x00000738,
+/*
+	MOVE FROM dsa_dataout+0x0318, WHEN DATA_OUT
+
+at 0x00000208 : */	0x18000000,0x00000740,
+/*
+	MOVE FROM dsa_dataout+0x0320, WHEN DATA_OUT
+
+at 0x0000020a : */	0x18000000,0x00000748,
+/*
+	MOVE FROM dsa_dataout+0x0328, WHEN DATA_OUT
+
+at 0x0000020c : */	0x18000000,0x00000750,
+/*
+	MOVE FROM dsa_dataout+0x0330, WHEN DATA_OUT
+
+at 0x0000020e : */	0x18000000,0x00000758,
+/*
+	MOVE FROM dsa_dataout+0x0338, WHEN DATA_OUT
+
+at 0x00000210 : */	0x18000000,0x00000760,
+/*
+	MOVE FROM dsa_dataout+0x0340, WHEN DATA_OUT
+
+at 0x00000212 : */	0x18000000,0x00000768,
+/*
+	MOVE FROM dsa_dataout+0x0348, WHEN DATA_OUT
+
+at 0x00000214 : */	0x18000000,0x00000770,
+/*
+	MOVE FROM dsa_dataout+0x0350, WHEN DATA_OUT
+
+at 0x00000216 : */	0x18000000,0x00000778,
+/*
+	MOVE FROM dsa_dataout+0x0358, WHEN DATA_OUT
+
+at 0x00000218 : */	0x18000000,0x00000780,
+/*
+	MOVE FROM dsa_dataout+0x0360, WHEN DATA_OUT
+
+at 0x0000021a : */	0x18000000,0x00000788,
+/*
+	MOVE FROM dsa_dataout+0x0368, WHEN DATA_OUT
+
+at 0x0000021c : */	0x18000000,0x00000790,
+/*
+	MOVE FROM dsa_dataout+0x0370, WHEN DATA_OUT
+
+at 0x0000021e : */	0x18000000,0x00000798,
+/*
+	MOVE FROM dsa_dataout+0x0378, WHEN DATA_OUT
+
+at 0x00000220 : */	0x18000000,0x000007a0,
+/*
+	MOVE FROM dsa_dataout+0x0380, WHEN DATA_OUT
+
+at 0x00000222 : */	0x18000000,0x000007a8,
+/*
+	MOVE FROM dsa_dataout+0x0388, WHEN DATA_OUT
+
+at 0x00000224 : */	0x18000000,0x000007b0,
+/*
+	MOVE FROM dsa_dataout+0x0390, WHEN DATA_OUT
+
+at 0x00000226 : */	0x18000000,0x000007b8,
+/*
+	MOVE FROM dsa_dataout+0x0398, WHEN DATA_OUT
+
+at 0x00000228 : */	0x18000000,0x000007c0,
+/*
+	MOVE FROM dsa_dataout+0x03a0, WHEN DATA_OUT
+
+at 0x0000022a : */	0x18000000,0x000007c8,
+/*
+	MOVE FROM dsa_dataout+0x03a8, WHEN DATA_OUT
+
+at 0x0000022c : */	0x18000000,0x000007d0,
+/*
+	MOVE FROM dsa_dataout+0x03b0, WHEN DATA_OUT
+
+at 0x0000022e : */	0x18000000,0x000007d8,
+/*
+	MOVE FROM dsa_dataout+0x03b8, WHEN DATA_OUT
+
+at 0x00000230 : */	0x18000000,0x000007e0,
+/*
+	MOVE FROM dsa_dataout+0x03c0, WHEN DATA_OUT
+
+at 0x00000232 : */	0x18000000,0x000007e8,
+/*
+	MOVE FROM dsa_dataout+0x03c8, WHEN DATA_OUT
+
+at 0x00000234 : */	0x18000000,0x000007f0,
+/*
+	MOVE FROM dsa_dataout+0x03d0, WHEN DATA_OUT
+
+at 0x00000236 : */	0x18000000,0x000007f8,
+/*
+	MOVE FROM dsa_dataout+0x03d8, WHEN DATA_OUT
+
+at 0x00000238 : */	0x18000000,0x00000800,
+/*
+	MOVE FROM dsa_dataout+0x03e0, WHEN DATA_OUT
+
+at 0x0000023a : */	0x18000000,0x00000808,
+/*
+	MOVE FROM dsa_dataout+0x03e8, WHEN DATA_OUT
+
+at 0x0000023c : */	0x18000000,0x00000810,
+/*
+	MOVE FROM dsa_dataout+0x03f0, WHEN DATA_OUT
+
+at 0x0000023e : */	0x18000000,0x00000818,
+/*
+	MOVE FROM dsa_dataout+0x03f8, WHEN DATA_OUT
+
+at 0x00000240 : */	0x18000000,0x00000820,
+/*
+ENTRY end_data_trans
+end_data_trans:
+redo_msgin3:
+	JUMP get_status, WHEN STATUS
+
+at 0x00000242 : */	0x830b0000,0x000000a0,
+/*
+	JUMP get_msgin3, WHEN MSG_IN
+
+at 0x00000244 : */	0x870b0000,0x00000b20,
+/*
+	INT int_data_bad_phase
+
+at 0x00000246 : */	0x98080000,0xab93000b,
+/*
+
+get_msgin1:
+	MOVE SCRATCH0 | had_msgin TO SCRATCH0
+
+at 0x00000248 : */	0x7a344000,0x00000000,
+/*
+	MOVE 1, msgin_buf, WHEN MSG_IN
+
+at 0x0000024a : */	0x0f000001,0x00000000,
+/*
+	JUMP ext_msg1, IF 0x01		; Extended Message
+
+at 0x0000024c : */	0x800c0001,0x00000968,
+/*
+	JUMP ignore_msg1, IF 0x02	; Save Data Pointers
+
+at 0x0000024e : */	0x800c0002,0x00000958,
+/*
+	JUMP ignore_msg1, IF 0x03	; Save Restore Pointers
+
+at 0x00000250 : */	0x800c0003,0x00000958,
+/*
+	JUMP disc1, IF 0x04		; Disconnect
+
+at 0x00000252 : */	0x800c0004,0x000009c8,
+/*
+	INT int_bad_msg1
+
+at 0x00000254 : */	0x98080000,0xab930006,
+/*
+ignore_msg1:
+	CLEAR ACK
+
+at 0x00000256 : */	0x60000040,0x00000000,
+/*
+	JUMP redo_msgin1
+
+at 0x00000258 : */	0x80080000,0x00000058,
+/*
+ext_msg1:
+	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+
+at 0x0000025a : */	0x7a348000,0x00000000,
+/*
+	CLEAR ACK
+
+at 0x0000025c : */	0x60000040,0x00000000,
+/*
+	MOVE 1, msgin_buf + 1, WHEN MSG_IN
+
+at 0x0000025e : */	0x0f000001,0x00000001,
+/*
+	JUMP ext_msg1a, IF 0x03
+
+at 0x00000260 : */	0x800c0003,0x00000990,
+/*
+	INT int_bad_extmsg1a
+
+at 0x00000262 : */	0x98080000,0xab930000,
+/*
+ext_msg1a:
+	CLEAR ACK
+
+at 0x00000264 : */	0x60000040,0x00000000,
+/*
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+
+at 0x00000266 : */	0x0f000001,0x00000002,
+/*
+	JUMP ext_msg1b, IF 0x01		; Must be SDTR
+
+at 0x00000268 : */	0x800c0001,0x000009b0,
+/*
+	INT int_bad_extmsg1b
+
+at 0x0000026a : */	0x98080000,0xab930001,
+/*
+ext_msg1b:
+	CLEAR ACK
+
+at 0x0000026c : */	0x60000040,0x00000000,
+/*
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+
+at 0x0000026e : */	0x0f000002,0x00000003,
+/*
+	INT int_msg_sdtr1
+
+at 0x00000270 : */	0x98080000,0xab93000c,
+/*
+disc1:
+	CLEAR ACK
+
+at 0x00000272 : */	0x60000040,0x00000000,
+/*
+ENTRY wait_disc1
+wait_disc1:
+	WAIT DISCONNECT
+
+at 0x00000274 : */	0x48000000,0x00000000,
+/*
+	INT int_disc1
+
+at 0x00000276 : */	0x98080000,0xab930019,
+/*
+ENTRY resume_msgin1a
+resume_msgin1a:
+	CLEAR ACK
+
+at 0x00000278 : */	0x60000040,0x00000000,
+/*
+	JUMP redo_msgin1
+
+at 0x0000027a : */	0x80080000,0x00000058,
+/*
+ENTRY resume_msgin1b
+resume_msgin1b:
+	SET ATN
+
+at 0x0000027c : */	0x58000008,0x00000000,
+/*
+	CLEAR ACK
+
+at 0x0000027e : */	0x60000040,0x00000000,
+/*
+	INT int_no_msgout1, WHEN NOT MSG_OUT
+
+at 0x00000280 : */	0x9e030000,0xab93000f,
+/*
+	MOVE SCRATCH0 | had_msgout TO SCRATCH0
+
+at 0x00000282 : */	0x7a340200,0x00000000,
+/*
+	MOVE FROM dsa_msgout, when MSG_OUT
+
+at 0x00000284 : */	0x1e000000,0x00000008,
+/*
+	JUMP redo_msgin1
+
+at 0x00000286 : */	0x80080000,0x00000058,
+/*
+
+get_msgin2:
+	MOVE SCRATCH0 | had_msgin TO SCRATCH0
+
+at 0x00000288 : */	0x7a344000,0x00000000,
+/*
+	MOVE 1, msgin_buf, WHEN MSG_IN
+
+at 0x0000028a : */	0x0f000001,0x00000000,
+/*
+	JUMP ext_msg2, IF 0x01		; Extended Message
+
+at 0x0000028c : */	0x800c0001,0x00000a68,
+/*
+	JUMP ignore_msg2, IF 0x02	; Save Data Pointers
+
+at 0x0000028e : */	0x800c0002,0x00000a58,
+/*
+	JUMP ignore_msg2, IF 0x03	; Save Restore Pointers
+
+at 0x00000290 : */	0x800c0003,0x00000a58,
+/*
+	JUMP disc2, IF 0x04		; Disconnect
+
+at 0x00000292 : */	0x800c0004,0x00000ac8,
+/*
+	INT int_bad_msg2
+
+at 0x00000294 : */	0x98080000,0xab930007,
+/*
+ignore_msg2:
+	CLEAR ACK
+
+at 0x00000296 : */	0x60000040,0x00000000,
+/*
+	JUMP redo_msgin2
+
+at 0x00000298 : */	0x80080000,0x00000078,
+/*
+ext_msg2:
+	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+
+at 0x0000029a : */	0x7a348000,0x00000000,
+/*
+	CLEAR ACK
+
+at 0x0000029c : */	0x60000040,0x00000000,
+/*
+	MOVE 1, msgin_buf + 1, WHEN MSG_IN
+
+at 0x0000029e : */	0x0f000001,0x00000001,
+/*
+	JUMP ext_msg2a, IF 0x03
+
+at 0x000002a0 : */	0x800c0003,0x00000a90,
+/*
+	INT int_bad_extmsg2a
+
+at 0x000002a2 : */	0x98080000,0xab930002,
+/*
+ext_msg2a:
+	CLEAR ACK
+
+at 0x000002a4 : */	0x60000040,0x00000000,
+/*
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+
+at 0x000002a6 : */	0x0f000001,0x00000002,
+/*
+	JUMP ext_msg2b, IF 0x01		; Must be SDTR
+
+at 0x000002a8 : */	0x800c0001,0x00000ab0,
+/*
+	INT int_bad_extmsg2b
+
+at 0x000002aa : */	0x98080000,0xab930003,
+/*
+ext_msg2b:
+	CLEAR ACK
+
+at 0x000002ac : */	0x60000040,0x00000000,
+/*
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+
+at 0x000002ae : */	0x0f000002,0x00000003,
+/*
+	INT int_msg_sdtr2
+
+at 0x000002b0 : */	0x98080000,0xab93000d,
+/*
+disc2:
+	CLEAR ACK
+
+at 0x000002b2 : */	0x60000040,0x00000000,
+/*
+ENTRY wait_disc2
+wait_disc2:
+	WAIT DISCONNECT
+
+at 0x000002b4 : */	0x48000000,0x00000000,
+/*
+	INT int_disc2
+
+at 0x000002b6 : */	0x98080000,0xab93001a,
+/*
+ENTRY resume_msgin2a
+resume_msgin2a:
+	CLEAR ACK
+
+at 0x000002b8 : */	0x60000040,0x00000000,
+/*
+	JUMP redo_msgin2
+
+at 0x000002ba : */	0x80080000,0x00000078,
+/*
+ENTRY resume_msgin2b
+resume_msgin2b:
+	SET ATN
+
+at 0x000002bc : */	0x58000008,0x00000000,
+/*
+	CLEAR ACK
+
+at 0x000002be : */	0x60000040,0x00000000,
+/*
+	INT int_no_msgout2, WHEN NOT MSG_OUT
+
+at 0x000002c0 : */	0x9e030000,0xab930010,
+/*
+	MOVE SCRATCH0 | had_msgout TO SCRATCH0
+
+at 0x000002c2 : */	0x7a340200,0x00000000,
+/*
+	MOVE FROM dsa_msgout, when MSG_OUT
+
+at 0x000002c4 : */	0x1e000000,0x00000008,
+/*
+	JUMP redo_msgin2
+
+at 0x000002c6 : */	0x80080000,0x00000078,
+/*
+
+get_msgin3:
+	MOVE SCRATCH0 | had_msgin TO SCRATCH0
+
+at 0x000002c8 : */	0x7a344000,0x00000000,
+/*
+	MOVE 1, msgin_buf, WHEN MSG_IN
+
+at 0x000002ca : */	0x0f000001,0x00000000,
+/*
+	JUMP ext_msg3, IF 0x01		; Extended Message
+
+at 0x000002cc : */	0x800c0001,0x00000b68,
+/*
+	JUMP ignore_msg3, IF 0x02	; Save Data Pointers
+
+at 0x000002ce : */	0x800c0002,0x00000b58,
+/*
+	JUMP ignore_msg3, IF 0x03	; Save Restore Pointers
+
+at 0x000002d0 : */	0x800c0003,0x00000b58,
+/*
+	JUMP disc3, IF 0x04		; Disconnect
+
+at 0x000002d2 : */	0x800c0004,0x00000bc8,
+/*
+	INT int_bad_msg3
+
+at 0x000002d4 : */	0x98080000,0xab930008,
+/*
+ignore_msg3:
+	CLEAR ACK
+
+at 0x000002d6 : */	0x60000040,0x00000000,
+/*
+	JUMP redo_msgin3
+
+at 0x000002d8 : */	0x80080000,0x00000908,
+/*
+ext_msg3:
+	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+
+at 0x000002da : */	0x7a348000,0x00000000,
+/*
+	CLEAR ACK
+
+at 0x000002dc : */	0x60000040,0x00000000,
+/*
+	MOVE 1, msgin_buf + 1, WHEN MSG_IN
+
+at 0x000002de : */	0x0f000001,0x00000001,
+/*
+	JUMP ext_msg3a, IF 0x03
+
+at 0x000002e0 : */	0x800c0003,0x00000b90,
+/*
+	INT int_bad_extmsg3a
+
+at 0x000002e2 : */	0x98080000,0xab930004,
+/*
+ext_msg3a:
+	CLEAR ACK
+
+at 0x000002e4 : */	0x60000040,0x00000000,
+/*
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+
+at 0x000002e6 : */	0x0f000001,0x00000002,
+/*
+	JUMP ext_msg3b, IF 0x01		; Must be SDTR
+
+at 0x000002e8 : */	0x800c0001,0x00000bb0,
+/*
+	INT int_bad_extmsg3b
+
+at 0x000002ea : */	0x98080000,0xab930005,
+/*
+ext_msg3b:
+	CLEAR ACK
+
+at 0x000002ec : */	0x60000040,0x00000000,
+/*
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+
+at 0x000002ee : */	0x0f000002,0x00000003,
+/*
+	INT int_msg_sdtr3
+
+at 0x000002f0 : */	0x98080000,0xab93000e,
+/*
+disc3:
+	CLEAR ACK
+
+at 0x000002f2 : */	0x60000040,0x00000000,
+/*
+ENTRY wait_disc3
+wait_disc3:
+	WAIT DISCONNECT
+
+at 0x000002f4 : */	0x48000000,0x00000000,
+/*
+	INT int_disc3
+
+at 0x000002f6 : */	0x98080000,0xab93001b,
+/*
+ENTRY resume_msgin3a
+resume_msgin3a:
+	CLEAR ACK
+
+at 0x000002f8 : */	0x60000040,0x00000000,
+/*
+	JUMP redo_msgin3
+
+at 0x000002fa : */	0x80080000,0x00000908,
+/*
+ENTRY resume_msgin3b
+resume_msgin3b:
+	SET ATN
+
+at 0x000002fc : */	0x58000008,0x00000000,
+/*
+	CLEAR ACK
+
+at 0x000002fe : */	0x60000040,0x00000000,
+/*
+	INT int_no_msgout3, WHEN NOT MSG_OUT
+
+at 0x00000300 : */	0x9e030000,0xab930011,
+/*
+	MOVE SCRATCH0 | had_msgout TO SCRATCH0
+
+at 0x00000302 : */	0x7a340200,0x00000000,
+/*
+	MOVE FROM dsa_msgout, when MSG_OUT
+
+at 0x00000304 : */	0x1e000000,0x00000008,
+/*
+	JUMP redo_msgin3
+
+at 0x00000306 : */	0x80080000,0x00000908,
+/*
+
+ENTRY resume_rej_ident
+resume_rej_ident:
+	CLEAR ATN
+
+at 0x00000308 : */	0x60000008,0x00000000,
+/*
+	MOVE 1, msgin_buf, WHEN MSG_IN
+
+at 0x0000030a : */	0x0f000001,0x00000000,
+/*
+	INT int_not_rej, IF NOT 0x07		; Reject
+
+at 0x0000030c : */	0x98040007,0xab93001c,
+/*
+	CLEAR ACK
+
+at 0x0000030e : */	0x60000040,0x00000000,
+/*
+	JUMP done_ident
+
+at 0x00000310 : */	0x80080000,0x00000050,
+/*
+
+ENTRY reselect
+reselect:
+	; Disable selection timer
+	MOVE CTEST7 | 0x10 TO CTEST7
+
+at 0x00000312 : */	0x7a1b1000,0x00000000,
+/*
+	WAIT RESELECT resel_err
+
+at 0x00000314 : */	0x50000000,0x00000c70,
+/*
+	INT int_resel_not_msgin, WHEN NOT MSG_IN
+
+at 0x00000316 : */	0x9f030000,0xab930016,
+/*
+	MOVE 1, reselected_identify, WHEN MSG_IN
+
+at 0x00000318 : */	0x0f000001,0x00000000,
+/*
+	INT int_reselected
+
+at 0x0000031a : */	0x98080000,0xab930017,
+/*
+resel_err:
+	MOVE CTEST2 & 0x40 TO SFBR
+
+at 0x0000031c : */	0x74164000,0x00000000,
+/*
+	JUMP selected, IF 0x00
+
+at 0x0000031e : */	0x800c0000,0x00000cb0,
+/*
+	MOVE SFBR & 0 TO SFBR
+
+at 0x00000320 : */	0x7c080000,0x00000000,
+/*
+ENTRY patch_new_dsa
+patch_new_dsa:
+	MOVE SFBR | 0x11 TO DSA0
+
+at 0x00000322 : */	0x6a101100,0x00000000,
+/*
+	MOVE SFBR | 0x22 TO DSA1
+
+at 0x00000324 : */	0x6a112200,0x00000000,
+/*
+	MOVE SFBR | 0x33 TO DSA2
+
+at 0x00000326 : */	0x6a123300,0x00000000,
+/*
+	MOVE SFBR | 0x44 TO DSA3
+
+at 0x00000328 : */	0x6a134400,0x00000000,
+/*
+	JUMP do_select
+
+at 0x0000032a : */	0x80080000,0x00000000,
+/*
+
+selected:
+	INT int_selected
+
+at 0x0000032c : */	0x98080000,0xab930018,
+};
+
+#define A_dsa_cmnd	0x00000010
+u32 A_dsa_cmnd_used[] = {
+	0x0000001d,
+};
+
+#define A_dsa_datain	0x00000028
+u32 A_dsa_datain_used[] = {
+	0x0000003d,
+	0x0000003f,
+	0x00000041,
+	0x00000043,
+	0x00000045,
+	0x00000047,
+	0x00000049,
+	0x0000004b,
+	0x0000004d,
+	0x0000004f,
+	0x00000051,
+	0x00000053,
+	0x00000055,
+	0x00000057,
+	0x00000059,
+	0x0000005b,
+	0x0000005d,
+	0x0000005f,
+	0x00000061,
+	0x00000063,
+	0x00000065,
+	0x00000067,
+	0x00000069,
+	0x0000006b,
+	0x0000006d,
+	0x0000006f,
+	0x00000071,
+	0x00000073,
+	0x00000075,
+	0x00000077,
+	0x00000079,
+	0x0000007b,
+	0x0000007d,
+	0x0000007f,
+	0x00000081,
+	0x00000083,
+	0x00000085,
+	0x00000087,
+	0x00000089,
+	0x0000008b,
+	0x0000008d,
+	0x0000008f,
+	0x00000091,
+	0x00000093,
+	0x00000095,
+	0x00000097,
+	0x00000099,
+	0x0000009b,
+	0x0000009d,
+	0x0000009f,
+	0x000000a1,
+	0x000000a3,
+	0x000000a5,
+	0x000000a7,
+	0x000000a9,
+	0x000000ab,
+	0x000000ad,
+	0x000000af,
+	0x000000b1,
+	0x000000b3,
+	0x000000b5,
+	0x000000b7,
+	0x000000b9,
+	0x000000bb,
+	0x000000bd,
+	0x000000bf,
+	0x000000c1,
+	0x000000c3,
+	0x000000c5,
+	0x000000c7,
+	0x000000c9,
+	0x000000cb,
+	0x000000cd,
+	0x000000cf,
+	0x000000d1,
+	0x000000d3,
+	0x000000d5,
+	0x000000d7,
+	0x000000d9,
+	0x000000db,
+	0x000000dd,
+	0x000000df,
+	0x000000e1,
+	0x000000e3,
+	0x000000e5,
+	0x000000e7,
+	0x000000e9,
+	0x000000eb,
+	0x000000ed,
+	0x000000ef,
+	0x000000f1,
+	0x000000f3,
+	0x000000f5,
+	0x000000f7,
+	0x000000f9,
+	0x000000fb,
+	0x000000fd,
+	0x000000ff,
+	0x00000101,
+	0x00000103,
+	0x00000105,
+	0x00000107,
+	0x00000109,
+	0x0000010b,
+	0x0000010d,
+	0x0000010f,
+	0x00000111,
+	0x00000113,
+	0x00000115,
+	0x00000117,
+	0x00000119,
+	0x0000011b,
+	0x0000011d,
+	0x0000011f,
+	0x00000121,
+	0x00000123,
+	0x00000125,
+	0x00000127,
+	0x00000129,
+	0x0000012b,
+	0x0000012d,
+	0x0000012f,
+	0x00000131,
+	0x00000133,
+	0x00000135,
+	0x00000137,
+	0x00000139,
+	0x0000013b,
+};
+
+#define A_dsa_dataout	0x00000428
+u32 A_dsa_dataout_used[] = {
+	0x00000143,
+	0x00000145,
+	0x00000147,
+	0x00000149,
+	0x0000014b,
+	0x0000014d,
+	0x0000014f,
+	0x00000151,
+	0x00000153,
+	0x00000155,
+	0x00000157,
+	0x00000159,
+	0x0000015b,
+	0x0000015d,
+	0x0000015f,
+	0x00000161,
+	0x00000163,
+	0x00000165,
+	0x00000167,
+	0x00000169,
+	0x0000016b,
+	0x0000016d,
+	0x0000016f,
+	0x00000171,
+	0x00000173,
+	0x00000175,
+	0x00000177,
+	0x00000179,
+	0x0000017b,
+	0x0000017d,
+	0x0000017f,
+	0x00000181,
+	0x00000183,
+	0x00000185,
+	0x00000187,
+	0x00000189,
+	0x0000018b,
+	0x0000018d,
+	0x0000018f,
+	0x00000191,
+	0x00000193,
+	0x00000195,
+	0x00000197,
+	0x00000199,
+	0x0000019b,
+	0x0000019d,
+	0x0000019f,
+	0x000001a1,
+	0x000001a3,
+	0x000001a5,
+	0x000001a7,
+	0x000001a9,
+	0x000001ab,
+	0x000001ad,
+	0x000001af,
+	0x000001b1,
+	0x000001b3,
+	0x000001b5,
+	0x000001b7,
+	0x000001b9,
+	0x000001bb,
+	0x000001bd,
+	0x000001bf,
+	0x000001c1,
+	0x000001c3,
+	0x000001c5,
+	0x000001c7,
+	0x000001c9,
+	0x000001cb,
+	0x000001cd,
+	0x000001cf,
+	0x000001d1,
+	0x000001d3,
+	0x000001d5,
+	0x000001d7,
+	0x000001d9,
+	0x000001db,
+	0x000001dd,
+	0x000001df,
+	0x000001e1,
+	0x000001e3,
+	0x000001e5,
+	0x000001e7,
+	0x000001e9,
+	0x000001eb,
+	0x000001ed,
+	0x000001ef,
+	0x000001f1,
+	0x000001f3,
+	0x000001f5,
+	0x000001f7,
+	0x000001f9,
+	0x000001fb,
+	0x000001fd,
+	0x000001ff,
+	0x00000201,
+	0x00000203,
+	0x00000205,
+	0x00000207,
+	0x00000209,
+	0x0000020b,
+	0x0000020d,
+	0x0000020f,
+	0x00000211,
+	0x00000213,
+	0x00000215,
+	0x00000217,
+	0x00000219,
+	0x0000021b,
+	0x0000021d,
+	0x0000021f,
+	0x00000221,
+	0x00000223,
+	0x00000225,
+	0x00000227,
+	0x00000229,
+	0x0000022b,
+	0x0000022d,
+	0x0000022f,
+	0x00000231,
+	0x00000233,
+	0x00000235,
+	0x00000237,
+	0x00000239,
+	0x0000023b,
+	0x0000023d,
+	0x0000023f,
+	0x00000241,
+};
+
+#define A_dsa_msgin	0x00000020
+u32 A_dsa_msgin_used[] = {
+	0x0000002f,
+};
+
+#define A_dsa_msgout	0x00000008
+u32 A_dsa_msgout_used[] = {
+	0x00000013,
+	0x00000285,
+	0x000002c5,
+	0x00000305,
+};
+
+#define A_dsa_select	0x00000000
+u32 A_dsa_select_used[] = {
+	0x00000006,
+};
+
+#define A_dsa_size	0x00000828
+u32 A_dsa_size_used[] = {
+};
+
+#define A_dsa_status	0x00000018
+u32 A_dsa_status_used[] = {
+	0x0000002b,
+};
+
+#define A_had_cmdout	0x00000004
+u32 A_had_cmdout_used[] = {
+	0x0000001a,
+};
+
+#define A_had_datain	0x00000008
+u32 A_had_datain_used[] = {
+	0x00000038,
+};
+
+#define A_had_dataout	0x00000010
+u32 A_had_dataout_used[] = {
+	0x0000013e,
+};
+
+#define A_had_extmsg	0x00000080
+u32 A_had_extmsg_used[] = {
+	0x0000025a,
+	0x0000029a,
+	0x000002da,
+};
+
+#define A_had_msgin	0x00000040
+u32 A_had_msgin_used[] = {
+	0x00000248,
+	0x00000288,
+	0x000002c8,
+};
+
+#define A_had_msgout	0x00000002
+u32 A_had_msgout_used[] = {
+	0x00000010,
+	0x00000282,
+	0x000002c2,
+	0x00000302,
+};
+
+#define A_had_select	0x00000001
+u32 A_had_select_used[] = {
+	0x0000000c,
+};
+
+#define A_had_status	0x00000020
+u32 A_had_status_used[] = {
+};
+
+#define A_int_bad_extmsg1a	0xab930000
+u32 A_int_bad_extmsg1a_used[] = {
+	0x00000263,
+};
+
+#define A_int_bad_extmsg1b	0xab930001
+u32 A_int_bad_extmsg1b_used[] = {
+	0x0000026b,
+};
+
+#define A_int_bad_extmsg2a	0xab930002
+u32 A_int_bad_extmsg2a_used[] = {
+	0x000002a3,
+};
+
+#define A_int_bad_extmsg2b	0xab930003
+u32 A_int_bad_extmsg2b_used[] = {
+	0x000002ab,
+};
+
+#define A_int_bad_extmsg3a	0xab930004
+u32 A_int_bad_extmsg3a_used[] = {
+	0x000002e3,
+};
+
+#define A_int_bad_extmsg3b	0xab930005
+u32 A_int_bad_extmsg3b_used[] = {
+	0x000002eb,
+};
+
+#define A_int_bad_msg1	0xab930006
+u32 A_int_bad_msg1_used[] = {
+	0x00000255,
+};
+
+#define A_int_bad_msg2	0xab930007
+u32 A_int_bad_msg2_used[] = {
+	0x00000295,
+};
+
+#define A_int_bad_msg3	0xab930008
+u32 A_int_bad_msg3_used[] = {
+	0x000002d5,
+};
+
+#define A_int_cmd_bad_phase	0xab930009
+u32 A_int_cmd_bad_phase_used[] = {
+	0x00000027,
+};
+
+#define A_int_cmd_complete	0xab93000a
+u32 A_int_cmd_complete_used[] = {
+	0x00000037,
+};
+
+#define A_int_data_bad_phase	0xab93000b
+u32 A_int_data_bad_phase_used[] = {
+	0x00000247,
+};
+
+#define A_int_disc1	0xab930019
+u32 A_int_disc1_used[] = {
+	0x00000277,
+};
+
+#define A_int_disc2	0xab93001a
+u32 A_int_disc2_used[] = {
+	0x000002b7,
+};
+
+#define A_int_disc3	0xab93001b
+u32 A_int_disc3_used[] = {
+	0x000002f7,
+};
+
+#define A_int_msg_sdtr1	0xab93000c
+u32 A_int_msg_sdtr1_used[] = {
+	0x00000271,
+};
+
+#define A_int_msg_sdtr2	0xab93000d
+u32 A_int_msg_sdtr2_used[] = {
+	0x000002b1,
+};
+
+#define A_int_msg_sdtr3	0xab93000e
+u32 A_int_msg_sdtr3_used[] = {
+	0x000002f1,
+};
+
+#define A_int_no_msgout1	0xab93000f
+u32 A_int_no_msgout1_used[] = {
+	0x00000281,
+};
+
+#define A_int_no_msgout2	0xab930010
+u32 A_int_no_msgout2_used[] = {
+	0x000002c1,
+};
+
+#define A_int_no_msgout3	0xab930011
+u32 A_int_no_msgout3_used[] = {
+	0x00000301,
+};
+
+#define A_int_not_cmd_complete	0xab930012
+u32 A_int_not_cmd_complete_used[] = {
+	0x00000031,
+};
+
+#define A_int_not_rej	0xab93001c
+u32 A_int_not_rej_used[] = {
+	0x0000030d,
+};
+
+#define A_int_resel_not_msgin	0xab930016
+u32 A_int_resel_not_msgin_used[] = {
+	0x00000317,
+};
+
+#define A_int_reselected	0xab930017
+u32 A_int_reselected_used[] = {
+	0x0000031b,
+};
+
+#define A_int_sel_no_ident	0xab930013
+u32 A_int_sel_no_ident_used[] = {
+	0x0000000f,
+};
+
+#define A_int_sel_not_cmd	0xab930014
+u32 A_int_sel_not_cmd_used[] = {
+	0x00000019,
+};
+
+#define A_int_selected	0xab930018
+u32 A_int_selected_used[] = {
+	0x0000032d,
+};
+
+#define A_int_status_not_msgin	0xab930015
+u32 A_int_status_not_msgin_used[] = {
+	0x0000002d,
+};
+
+#define A_msgin_buf	0x00000000
+u32 A_msgin_buf_used[] = {
+	0x0000024b,
+	0x0000025f,
+	0x00000267,
+	0x0000026f,
+	0x0000028b,
+	0x0000029f,
+	0x000002a7,
+	0x000002af,
+	0x000002cb,
+	0x000002df,
+	0x000002e7,
+	0x000002ef,
+	0x0000030b,
+};
+
+#define A_reselected_identify	0x00000000
+u32 A_reselected_identify_used[] = {
+	0x00000319,
+};
+
+#define Ent_do_select	0x00000000
+#define Ent_done_ident	0x00000050
+#define Ent_end_data_trans	0x00000908
+#define Ent_patch_input_data	0x000000e8
+#define Ent_patch_new_dsa	0x00000c88
+#define Ent_patch_output_data	0x00000500
+#define Ent_reselect	0x00000c48
+#define Ent_resume_cmd	0x00000068
+#define Ent_resume_msgin1a	0x000009e0
+#define Ent_resume_msgin1b	0x000009f0
+#define Ent_resume_msgin2a	0x00000ae0
+#define Ent_resume_msgin2b	0x00000af0
+#define Ent_resume_msgin3a	0x00000be0
+#define Ent_resume_msgin3b	0x00000bf0
+#define Ent_resume_pmm	0x00000078
+#define Ent_resume_rej_ident	0x00000c20
+#define Ent_wait_disc1	0x000009d0
+#define Ent_wait_disc2	0x00000ad0
+#define Ent_wait_disc3	0x00000bd0
+#define Ent_wait_disc_complete	0x000000d0
+u32 LABELPATCHES[] = {
+	0x00000007,
+	0x00000009,
+	0x00000015,
+	0x00000017,
+	0x0000001f,
+	0x00000021,
+	0x00000023,
+	0x00000025,
+	0x0000013d,
+	0x00000243,
+	0x00000245,
+	0x0000024d,
+	0x0000024f,
+	0x00000251,
+	0x00000253,
+	0x00000259,
+	0x00000261,
+	0x00000269,
+	0x0000027b,
+	0x00000287,
+	0x0000028d,
+	0x0000028f,
+	0x00000291,
+	0x00000293,
+	0x00000299,
+	0x000002a1,
+	0x000002a9,
+	0x000002bb,
+	0x000002c7,
+	0x000002cd,
+	0x000002cf,
+	0x000002d1,
+	0x000002d3,
+	0x000002d9,
+	0x000002e1,
+	0x000002e9,
+	0x000002fb,
+	0x00000307,
+	0x00000311,
+	0x00000315,
+	0x0000031f,
+	0x0000032b,
+};
+
+struct {
+	u32	offset;
+	void		*address;
+} EXTERNAL_PATCHES[] = {
+};
+
+u32 INSTRUCTIONS	= 407;
+u32 PATCHES	= 42;
+u32 EXTERNAL_PATCHES_LEN	= 0;
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/sim710_u.h linux/drivers/scsi/sim710_u.h
--- v2.3.19/linux/drivers/scsi/sim710_u.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/sim710_u.h	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,67 @@
+#undef A_dsa_cmnd
+#undef A_dsa_datain
+#undef A_dsa_dataout
+#undef A_dsa_msgin
+#undef A_dsa_msgout
+#undef A_dsa_select
+#undef A_dsa_size
+#undef A_dsa_status
+#undef A_had_cmdout
+#undef A_had_datain
+#undef A_had_dataout
+#undef A_had_extmsg
+#undef A_had_msgin
+#undef A_had_msgout
+#undef A_had_select
+#undef A_had_status
+#undef A_int_bad_extmsg1a
+#undef A_int_bad_extmsg1b
+#undef A_int_bad_extmsg2a
+#undef A_int_bad_extmsg2b
+#undef A_int_bad_extmsg3a
+#undef A_int_bad_extmsg3b
+#undef A_int_bad_msg1
+#undef A_int_bad_msg2
+#undef A_int_bad_msg3
+#undef A_int_cmd_bad_phase
+#undef A_int_cmd_complete
+#undef A_int_data_bad_phase
+#undef A_int_disc1
+#undef A_int_disc2
+#undef A_int_disc3
+#undef A_int_msg_sdtr1
+#undef A_int_msg_sdtr2
+#undef A_int_msg_sdtr3
+#undef A_int_no_msgout1
+#undef A_int_no_msgout2
+#undef A_int_no_msgout3
+#undef A_int_not_cmd_complete
+#undef A_int_not_rej
+#undef A_int_resel_not_msgin
+#undef A_int_reselected
+#undef A_int_sel_no_ident
+#undef A_int_sel_not_cmd
+#undef A_int_selected
+#undef A_int_status_not_msgin
+#undef A_msgin_buf
+#undef A_reselected_identify
+#undef Ent_do_select
+#undef Ent_done_ident
+#undef Ent_end_data_trans
+#undef Ent_patch_input_data
+#undef Ent_patch_new_dsa
+#undef Ent_patch_output_data
+#undef Ent_reselect
+#undef Ent_resume_cmd
+#undef Ent_resume_msgin1a
+#undef Ent_resume_msgin1b
+#undef Ent_resume_msgin2a
+#undef Ent_resume_msgin2b
+#undef Ent_resume_msgin3a
+#undef Ent_resume_msgin3b
+#undef Ent_resume_pmm
+#undef Ent_resume_rej_ident
+#undef Ent_wait_disc1
+#undef Ent_wait_disc2
+#undef Ent_wait_disc3
+#undef Ent_wait_disc_complete
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.3.19/linux/drivers/scsi/sym53c8xx.c	Fri Sep 10 23:57:35 1999
+++ linux/drivers/scsi/sym53c8xx.c	Thu Oct  7 10:17:09 1999
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-1999  Gerard Roudier <groudier@club-internet.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
@@ -55,7 +55,7 @@
 */
 
 /*
-**	April 2 1999, sym53c8xx version 1.3c
+**	Sep 10 1999, sym53c8xx 1.5e
 **
 **	Supported SCSI features:
 **	    Synchronous data transfers
@@ -64,13 +64,14 @@
 **	    Tagged command queuing
 **	    SCSI Parity checking
 **
-**	Supported NCR chips:
+**	Supported NCR/SYMBIOS chips:
 **		53C810A	  (8 bits, Fast 10,	 no rom BIOS) 
 **		53C825A	  (Wide,   Fast 10,	 on-board rom BIOS)
 **		53C860	  (8 bits, Fast 20,	 no rom BIOS)
 **		53C875	  (Wide,   Fast 20,	 on-board rom BIOS)
 **		53C876	  (Wide,   Fast 20 Dual, on-board rom BIOS)
 **		53C895	  (Wide,   Fast 40,	 on-board rom BIOS)
+**		53C895A	  (Wide,   Fast 40,	 on-board rom BIOS)
 **		53C896	  (Wide,   Fast 40 Dual, on-board rom BIOS)
 **
 **	Other features:
@@ -82,7 +83,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.3c"
+#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.5e"
 
 /* #define DEBUG_896R1 */
 #define SCSI_NCR_OPTIMIZE_896
@@ -109,8 +110,10 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
 #include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#include <asm/spinlock.h>
 #endif
 #include <linux/delay.h>
 #include <linux/signal.h>
@@ -130,13 +133,13 @@
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
 #include <linux/init.h>
-#else
-#ifndef	__initdata
-#define	__initdata
 #endif
+
 #ifndef	__init
 #define	__init
 #endif
+#ifndef	__initdata
+#define	__initdata
 #endif
 
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
@@ -314,26 +317,34 @@
 #endif
 
 /*
-**    TAGS are actually limited to 64 tags/lun.
-**    We need to deal with power of 2, for alignment constraints.
+**    TAGS are actually unlimited (256 tags/lun).
+**    But Linux only supports 255. :)
 */
-#if	SCSI_NCR_MAX_TAGS > 64
-#undef	SCSI_NCR_MAX_TAGS
-#define	SCSI_NCR_MAX_TAGS (64)
+#if	SCSI_NCR_MAX_TAGS > 255
+#define	MAX_TAGS	255
+#else
+#define	MAX_TAGS SCSI_NCR_MAX_TAGS
 #endif
 
-#define NO_TAG	(255)
-
 /*
-**	Choose appropriate type for tag bitmap.
+**    Since the ncr chips only have a 8 bit ALU, we try to be clever 
+**    about offset calculation in the TASK TABLE per LUN that is an 
+**    array of DWORDS = 4 bytes.
 */
-#if	SCSI_NCR_MAX_TAGS > 32
-typedef u_int64 tagmap_t;
+#if	MAX_TAGS > (512/4)
+#define MAX_TASKS  (1024/4)
+#elif	MAX_TAGS > (256/4) 
+#define MAX_TASKS  (512/4)
 #else
-typedef u_int32 tagmap_t;
+#define MAX_TASKS  (256/4)
 #endif
 
 /*
+**    This one means 'NO TAG for this job'
+*/
+#define NO_TAG	(256)
+
+/*
 **    Number of targets supported by the driver.
 **    n permits target numbers 0..n-1.
 **    Default is 16, meaning targets #0..#15.
@@ -354,7 +365,7 @@
 */
 
 #ifdef SCSI_NCR_MAX_LUN
-#define MAX_LUN    SCSI_NCR_MAX_LUN
+#define MAX_LUN    64
 #else
 #define MAX_LUN    (1)
 #endif
@@ -377,51 +388,34 @@
 #ifdef SCSI_NCR_CAN_QUEUE
 #define MAX_START   (SCSI_NCR_CAN_QUEUE + 4)
 #else
-#define MAX_START   (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS)
+#define MAX_START   (MAX_TARGET + 7 * MAX_TAGS)
+#endif
+
+/*
+**    We donnot want to allocate more than 1 PAGE for the 
+**    the start queue and the done queue. We hard-code entry 
+**    size to 8 in order to let cpp do the checking.
+**    Allows 512-4=508 pending IOs for i386 but Linux seems for 
+**    now not able to provide the driver with this amount of IOs.
+*/
+#if	MAX_START > PAGE_SIZE/8
+#undef	MAX_START
+#define MAX_START (PAGE_SIZE/8)
 #endif
 
 /*
 **    The maximum number of segments a transfer is split into.
 **    We support up to 127 segments for both read and write.
-**    Since we try to avoid phase mismatches by testing the PHASE 
-**    before each MOV, the both DATA_IN and DATA_OUT scripts do 
-**    not fit in the 4K on-chip RAM. For this reason, the data 
-**    scripts are broken into 2 sub-scripts.
-**    80 (MAX_SCATTERL) segments are moved from a sub-script 
-**    in on-chip RAM. This makes data transfers shorter than 
-**    80k (assuming 1k fs) as fast as possible.
-**    The 896 allows to handle phase mismatches from SCRIPTS.
-**    So, for this chip, we use a simple array of MOV's.
-**    Perhaps, using a simple array of MOV's and going with 
-**    the phase mismatch interrupt is also the best solution 
-**    for the 895 in Ultra2-mode, since the PHASE test + MOV 
-**    latency may be enough to fill the SCSI offset for very  
-**    fast disks like the Cheatah Wide LVD and so, may waste 
-**    SCSI BUS bandwitch.
 */
 
 #define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
-
-#ifdef	SCSI_NCR_OPTIMIZE_896
 #define	SCR_SG_SIZE	(2)
-#define MAX_SCATTERL	MAX_SCATTER
-#define MAX_SCATTERH	0
-#else
-#if (MAX_SCATTER > 80)
-#define	SCR_SG_SIZE	(4)
-#define MAX_SCATTERL	80
-#define	MAX_SCATTERH	(MAX_SCATTER - MAX_SCATTERL)
-#else
-#define MAX_SCATTERL	MAX_SCATTER
-#define	MAX_SCATTERH	0
-#endif
-#endif	/* SCSI_NCR_OPTIMIZE_896 */
 
 /*
 **    Io mapped or memory mapped.
 */
 
-#if defined(SCSI_NCR_IOMAPPED)
+#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
 #define NCR_IOMAPPED
 #endif
 
@@ -464,17 +458,14 @@
 
 #define DEBUG_ALLOC    (0x0001)
 #define DEBUG_PHASE    (0x0002)
-#define DEBUG_POLL     (0x0004)
 #define DEBUG_QUEUE    (0x0008)
 #define DEBUG_RESULT   (0x0010)
-#define DEBUG_SCATTER  (0x0020)
+#define DEBUG_POINTER  (0x0020)
 #define DEBUG_SCRIPT   (0x0040)
 #define DEBUG_TINY     (0x0080)
 #define DEBUG_TIMING   (0x0100)
 #define DEBUG_NEGO     (0x0200)
 #define DEBUG_TAGS     (0x0400)
-#define DEBUG_FREEZE   (0x0800)
-#define DEBUG_RESTART  (0x1000)
 
 /*
 **    Enable/Disable debug messages.
@@ -569,12 +560,19 @@
 #endif
 
 #ifdef __sparc__
-#define pcivtobus(p)			((p) & pci_dvma_mask)
-#else	/* __sparc__ */
-#define pcivtobus(p)			(p)
+#  define ioremap(base, size)	((u_long) __va(base))
+#  define iounmap(vaddr)
+#  define pcivtobus(p)			((p) & pci_dvma_mask)
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((u_long) (a), (b), (c))
+#elif defined(__alpha__)
+#  define pcivtobus(p)			((p) & 0xfffffffful)
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
+#else	/* others */
+#  define pcivtobus(p)			(p)
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
 #endif
 
-#if !defined(NCR_IOMAPPED) || defined(__i386__)
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 static u_long __init remap_pci_mem(u_long base, u_long size)
 {
 	u_long page_base	= ((u_long) base) & PAGE_MASK;
@@ -589,7 +587,8 @@
 	if (vaddr)
 		iounmap((void *) (vaddr & PAGE_MASK));
 }
-#endif	/* !NCR_IOMAPPED || __i386__ */
+
+#endif /* not def SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
 
 /*
 **	Insert a delay in micro-seconds and milli-seconds.
@@ -760,7 +759,7 @@
 	NCR_UNLOCK_DRIVER(flags);
 
 	if (DEBUG_FLAGS & DEBUG_ALLOC)
-		printk ("new %s[%d] @%p.\n", name, size, p);
+		printk ("new %-10s[%4d] @%p.\n", name, size, p);
 
 	if (p)
 		memset(p, 0, size);
@@ -775,13 +774,26 @@
 	u_long flags;
 
 	if (DEBUG_FLAGS & DEBUG_ALLOC)
-		printk ("freeing %s[%d] @%p.\n", name, size, ptr);
+		printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
 
 	NCR_LOCK_DRIVER(flags);
 	__m_free(ptr, size);
 	NCR_UNLOCK_DRIVER(flags);
 }
 
+static void ncr_print_hex(u_char *p, int n)
+{
+	while (n-- > 0)
+		printk (" %x", *p++);
+}
+
+static void ncr_printl_hex(char *label, u_char *p, int n)
+{
+	printk("%s", label);
+	ncr_print_hex(p, n);
+	printk (".\n");
+}
+
 /*
 **	Transfer direction
 **
@@ -831,34 +843,6 @@
 **	This structure is initialized from linux config options.
 **	It can be overridden at boot-up by the boot command line.
 */
-#define SCSI_NCR_MAX_EXCLUDES 8
-struct ncr_driver_setup {
-	u_char	master_parity;
-	u_char	scsi_parity;
-	u_char	disconnection;
-	u_char	special_features;
-	u_char	ultra_scsi;
-	u_char	force_sync_nego;
-	u_char	reverse_probe;
-	u_char	pci_fix_up;
-	u_char	use_nvram;
-	u_char	verbose;
-	u_char	default_tags;
-	u_short	default_sync;
-	u_short	debug;
-	u_char	burst_max;
-	u_char	led_pin;
-	u_char	max_wide;
-	u_char	settle_delay;
-	u_char	diff_support;
-	u_char	irqm;
-	u_char	bus_check;
-	u_char	optimize;
-	u_char	recovery;
-	u_int	excludes[SCSI_NCR_MAX_EXCLUDES];
-	char	tag_ctrl[100];
-};
-
 static struct ncr_driver_setup
 	driver_setup			= SCSI_NCR_DRIVER_SETUP;
 
@@ -888,134 +872,7 @@
 #define bootverbose (np->verbose)
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
-/*
-**	Symbios NvRAM data format
-*/
-#define SYMBIOS_NVRAM_SIZE 368
-#define SYMBIOS_NVRAM_ADDRESS 0x100
-
-struct Symbios_nvram {
-/* Header 6 bytes */
-	u_short type;		/* 0x0000 */
-	u_short byte_count;	/* excluding header/trailer */
-	u_short checksum;
-
-/* Controller set up 20 bytes */
-	u_char	v_major;	/* 0x00 */
-	u_char	v_minor;	/* 0x30 */
-	u_int32	boot_crc;
-	u_short	flags;
-#define SYMBIOS_SCAM_ENABLE	(1)
-#define SYMBIOS_PARITY_ENABLE	(1<<1)
-#define SYMBIOS_VERBOSE_MSGS	(1<<2)
-#define SYMBIOS_CHS_MAPPING	(1<<3)
-#define SYMBIOS_NO_NVRAM	(1<<3)	/* ??? */
-	u_short	flags1;
-#define SYMBIOS_SCAN_HI_LO	(1)
-	u_short	term_state;
-#define SYMBIOS_TERM_CANT_PROGRAM	(0)
-#define SYMBIOS_TERM_ENABLED		(1)
-#define SYMBIOS_TERM_DISABLED		(2)
-	u_short	rmvbl_flags;
-#define SYMBIOS_RMVBL_NO_SUPPORT	(0)
-#define SYMBIOS_RMVBL_BOOT_DEVICE	(1)
-#define SYMBIOS_RMVBL_MEDIA_INSTALLED	(2)
-	u_char	host_id;
-	u_char	num_hba;	/* 0x04 */
-	u_char	num_devices;	/* 0x10 */
-	u_char	max_scam_devices;	/* 0x04 */
-	u_char	num_valid_scam_devives;	/* 0x00 */
-	u_char	rsvd;
-
-/* Boot order 14 bytes * 4 */
-	struct Symbios_host{
-		u_short	type;		/* 4:8xx / 0:nok */
-		u_short	device_id;	/* PCI device id */
-		u_short	vendor_id;	/* PCI vendor id */
-		u_char	bus_nr;		/* PCI bus number */
-		u_char	device_fn;	/* PCI device/function number << 3*/
-		u_short	word8;
-		u_short	flags;
-#define	SYMBIOS_INIT_SCAN_AT_BOOT	(1)
-		u_short	io_port;	/* PCI io_port address */
-	} host[4];
-
-/* Targets 8 bytes * 16 */
-	struct Symbios_target {
-		u_char	flags;
-#define SYMBIOS_DISCONNECT_ENABLE	(1)
-#define SYMBIOS_SCAN_AT_BOOT_TIME	(1<<1)
-#define SYMBIOS_SCAN_LUNS		(1<<2)
-#define SYMBIOS_QUEUE_TAGS_ENABLED	(1<<3)
-		u_char	rsvd;
-		u_char	bus_width;	/* 0x08/0x10 */
-		u_char	sync_offset;
-		u_short	sync_period;	/* 4*period factor */
-		u_short	timeout;
-	} target[16];
-/* Scam table 8 bytes * 4 */
-	struct Symbios_scam {
-		u_short	id;
-		u_short	method;
-#define SYMBIOS_SCAM_DEFAULT_METHOD	(0)
-#define SYMBIOS_SCAM_DONT_ASSIGN	(1)
-#define SYMBIOS_SCAM_SET_SPECIFIC_ID	(2)
-#define SYMBIOS_SCAM_USE_ORDER_GIVEN	(3)
-		u_short status;
-#define SYMBIOS_SCAM_UNKNOWN		(0)
-#define SYMBIOS_SCAM_DEVICE_NOT_FOUND	(1)
-#define SYMBIOS_SCAM_ID_NOT_SET		(2)
-#define SYMBIOS_SCAM_ID_VALID		(3)
-		u_char	target_id;
-		u_char	rsvd;
-	} scam[4];
-
-	u_char	spare_devices[15*8];
-	u_char	trailer[6];		/* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
-};
-typedef struct Symbios_nvram	Symbios_nvram;
-typedef struct Symbios_host	Symbios_host;
-typedef struct Symbios_target	Symbios_target;
-typedef struct Symbios_scam	Symbios_scam;
-
-/*
-**	Tekram NvRAM data format.
-*/
-#define TEKRAM_NVRAM_SIZE 64
-#define TEKRAM_NVRAM_ADDRESS 0
-
-struct Tekram_nvram {
-	struct Tekram_target {
-		u_char	flags;
-#define	TEKRAM_PARITY_CHECK		(1)
-#define TEKRAM_SYNC_NEGO		(1<<1)
-#define TEKRAM_DISCONNECT_ENABLE	(1<<2)
-#define	TEKRAM_START_CMD		(1<<3)
-#define TEKRAM_TAGGED_COMMANDS		(1<<4)
-#define TEKRAM_WIDE_NEGO		(1<<5)
-		u_char	sync_index;
-		u_short	word2;
-	} target[16];
-	u_char	host_id;
-	u_char	flags;
-#define TEKRAM_MORE_THAN_2_DRIVES	(1)
-#define TEKRAM_DRIVES_SUP_1GB		(1<<1)
-#define	TEKRAM_RESET_ON_POWER_ON	(1<<2)
-#define TEKRAM_ACTIVE_NEGATION		(1<<3)
-#define TEKRAM_IMMEDIATE_SEEK		(1<<4)
-#define	TEKRAM_SCAN_LUNS		(1<<5)
-#define	TEKRAM_REMOVABLE_FLAGS		(3<<6)	/* 0: disable; 1: boot device; 2:all */
-	u_char	boot_delay_index;
-	u_char	max_tags_index;
-	u_short	flags1;
-#define TEKRAM_F2_F6_ENABLED		(1)
-	u_short	spare[29];
-};
-typedef struct Tekram_nvram	Tekram_nvram;
-typedef struct Tekram_target	Tekram_target;
-
 static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21};
-
 #endif /* SCSI_NCR_NVRAM_SUPPORT */
 
 /*
@@ -1282,36 +1139,38 @@
 
 #define	SIR_BAD_STATUS		(1)
 #define	SIR_SEL_ATN_NO_MSG_OUT	(2)
-#define	SIR_NEGO_SYNC		(3)
-#define	SIR_NEGO_WIDE		(4)
+#define	SIR_MSG_RECEIVED	(3)
+#define	SIR_MSG_WEIRD		(4)
 #define	SIR_NEGO_FAILED		(5)
 #define	SIR_NEGO_PROTO		(6)
-#define	SIR_REJECT_RECEIVED	(7)
+#define	SIR_SCRIPT_STOPPED	(7)
 #define	SIR_REJECT_TO_SEND	(8)
-#define	SIR_IGN_RESIDUE		(9)
-#define	SIR_MISSING_SAVE	(10)
+#define	SIR_SWIDE_OVERRUN	(9)
+#define	SIR_SODL_UNDERRUN	(10)
 #define	SIR_RESEL_NO_MSG_IN	(11)
 #define	SIR_RESEL_NO_IDENTIFY	(12)
 #define	SIR_RESEL_BAD_LUN	(13)
-#define	SIR_UNUSED_14		(14)
+#define	SIR_TARGET_SELECTED	(14)
 #define	SIR_RESEL_BAD_I_T_L	(15)
 #define	SIR_RESEL_BAD_I_T_L_Q	(16)
-#define	SIR_UNUSED_17		(17)
+#define	SIR_ABORT_SENT		(17)
 #define	SIR_RESEL_ABORTED	(18)
 #define	SIR_MSG_OUT_DONE	(19)
-#define	SIR_MAX			(19)
+#define	SIR_AUTO_SENSE_DONE	(20)
+#define	SIR_DUMMY_INTERRUPT	(21)
+#define	SIR_MAX			(21)
 
 /*==========================================================
 **
-**	Extended error codes.
+**	Extended error bits.
 **	xerr_status field of struct ccb.
 **
 **==========================================================
 */
 
-#define	XE_OK		(0)
-#define	XE_EXTRA_DATA	(1)	/* unexpected data phase */
-#define	XE_BAD_PHASE	(2)	/* illegal phase (4/5)   */
+#define	XE_EXTRA_DATA	(1)	/* unexpected data phase	 */
+#define	XE_BAD_PHASE	(2)	/* illegal phase (4/5)		 */
+#define	XE_PARITY_ERR	(4)	/* unrecovered SCSI parity error */
 
 /*==========================================================
 **
@@ -1334,9 +1193,6 @@
 */
 
 #define	QUIRK_AUTOSAVE	(0x01)
-#define	QUIRK_NOMSG	(0x02)
-#define QUIRK_NOSYNC	(0x10)
-#define QUIRK_NOWIDE16	(0x20)
 
 /*==========================================================
 **
@@ -1400,6 +1256,8 @@
 #define UC_SETFLAG	15
 #define UC_CLEARPROF	16
 #define UC_SETVERBOSE	17
+#define UC_RESETDEV	18
+#define UC_CLEARDEV	19
 
 #define	UF_TRACE	(0x01)
 #define	UF_NODISC	(0x02)
@@ -1443,8 +1301,11 @@
 	*/
 	u_int32		*luntbl;	/* lcbs bus address table	*/
 	u_int32		b_luntbl;	/* bus address of this table	*/
-	lcb_p		lp[MAX_LUN];	/* The lcb's of this tcb	*/
-
+	u_int32		b_lun0;		/* bus address of lun0		*/
+	lcb_p		l0p;		/* lcb of LUN #0 (normal case)	*/
+#if MAX_LUN > 1
+	lcb_p		*lmp;		/* Other lcb's [1..MAX_LUN]	*/
+#endif
 	/*----------------------------------------------------------------
 	**	Target capabilities.
 	**----------------------------------------------------------------
@@ -1453,6 +1314,12 @@
 	u_char		inq_byte7;	/* Contains these capabilities	*/
 
 	/*----------------------------------------------------------------
+	**	Some flags.
+	**----------------------------------------------------------------
+	*/
+	u_char		to_reset;	/* This target is to be reset	*/
+
+	/*----------------------------------------------------------------
 	**	Pointer to the ccb used for negotiation.
 	**	Prevent from starting a negotiation for all queued commands 
 	**	when tagged command queuing is enabled.
@@ -1488,8 +1355,8 @@
 	*/
 	u_char	usrsync;
 	u_char	usrwide;
-	u_char	usrtags;
 	u_char	usrflag;
+	u_short	usrtags;
 };
 
 /*========================================================================
@@ -1526,11 +1393,11 @@
 	*/
 	XPT_QUEHEAD	busy_ccbq;	/* Queue of busy CCBs		*/
 	XPT_QUEHEAD	wait_ccbq;	/* Queue of waiting for IO CCBs	*/
-	u_char		busyccbs;	/* CCBs busy for this lun	*/
-	u_char		queuedccbs;	/* CCBs queued to the controller*/
-	u_char		queuedepth;	/* Queue depth for this lun	*/
-	u_char		scdev_depth;	/* SCSI device queue depth	*/
-	u_char		maxnxs;		/* Max possible nexuses		*/
+	u_short		busyccbs;	/* CCBs busy for this lun	*/
+	u_short		queuedccbs;	/* CCBs queued to the controller*/
+	u_short		queuedepth;	/* Queue depth for this lun	*/
+	u_short		scdev_depth;	/* SCSI device queue depth	*/
+	u_short		maxnxs;		/* Max possible nexuses		*/
 
 	/*----------------------------------------------------------------
 	**	Control of tagged command queuing.
@@ -1538,22 +1405,23 @@
 	**	This avoids using a loop for tag allocation.
 	**----------------------------------------------------------------
 	*/
-	u_char		ia_tag;		/* Tag allocation index		*/
-	u_char		if_tag;		/* Tag release index		*/
-	u_char cb_tags[SCSI_NCR_MAX_TAGS]; /* Circular tags buffer	*/
+	u_short		ia_tag;		/* Tag allocation index		*/
+	u_short		if_tag;		/* Tag release index		*/
+	u_char		*cb_tags;	/* Circular tags buffer		*/
+	u_char		inq_byte7;	/* Store unit CmdQ capability	*/
 	u_char		usetags;	/* Command queuing is active	*/
-	u_char		maxtags;	/* Max NR of tags asked by user	*/
-	u_char		numtags;	/* Current number of tags	*/
-	u_char		inq_byte7;	/* Store unit CmdQ capabitility	*/
+	u_char		to_clear;	/* User wants to clear all tasks*/
+	u_short		maxtags;	/* Max NR of tags asked by user	*/
+	u_short		numtags;	/* Current number of tags	*/
 
 	/*----------------------------------------------------------------
 	**	QUEUE FULL and ORDERED tag control.
 	**----------------------------------------------------------------
 	*/
 	u_short		num_good;	/* Nr of GOOD since QUEUE FULL	*/
-	tagmap_t	tags_umap;	/* Used tags bitmap		*/
-	tagmap_t	tags_smap;	/* Tags in use at 'tag_stime'	*/
-	u_long		tags_stime;	/* Last time we set smap=umap	*/
+	u_short		tags_sum[2];	/* Tags sum counters		*/
+	u_char		tags_si;	/* Current index to tags sum	*/
+	u_long		tags_stime;	/* Last time we switch tags_sum	*/
 };
 
 /*========================================================================
@@ -1641,6 +1509,18 @@
 };
 
 /*
+**	LUN control block lookup.
+**	We use a direct pointer for LUN #0, and a table of pointers 
+**	which is only allocated for devices that support LUN(s) > 0.
+*/
+#if MAX_LUN <= 1
+#define ncr_lp(np, tp, lun) (!lun) ? (tp)->l0p : 0
+#else
+#define ncr_lp(np, tp, lun) \
+	(!lun) ? (tp)->l0p : (tp)->lmp ? (tp)->lmp[(lun)] : 0
+#endif
+
+/*
 **	The status bytes are used by the host and the script processor.
 **
 **	The last four bytes (status[4]) are copied to the scratchb register
@@ -1683,10 +1563,14 @@
 #define HF_IN_PM1	(1u<<1)
 #define HF_ACT_PM	(1u<<2)
 #define HF_DP_SAVED	(1u<<3)
-#define HF_PAR_ERR	(1u<<4)
+#define HF_AUTO_SENSE	(1u<<4)
 #define HF_DATA_ST	(1u<<5)
 #define HF_PM_TO_C	(1u<<6)
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define HF_HINT_IARB	(1u<<7)
+#endif
+
 /*
 **	First four bytes (script)
 */
@@ -1731,6 +1615,7 @@
 
 	struct scr_tblsel  select;
 	struct scr_tblmove smsg  ;
+	struct scr_tblmove smsg_ext ;
 	struct scr_tblmove cmd   ;
 	struct scr_tblmove sense ;
 	struct scr_tblmove data [MAX_SCATTER];
@@ -1744,6 +1629,12 @@
 	struct pm_ctx pm0;
 	struct pm_ctx pm1;
 
+	/*
+	**	Extra bytes count transferred 
+	**	in case of data overrun.
+	*/
+	u_int32	extra_bytes;
+
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 	/*
 	**	Disconnection counter
@@ -1774,8 +1665,8 @@
 	**----------------------------------------------------------------
 	*/
 	Scsi_Cmnd	*cmd;		/* SCSI command 		*/
-	u_long		tlimit;		/* Deadline for this job	*/
 	int		data_len;	/* Total data length		*/
+	int		segments;	/* Number of SG segments	*/
 
 	/*----------------------------------------------------------------
 	**	Message areas.
@@ -1791,21 +1682,34 @@
 	u_char		scsi_smsg2[8];
 
 	/*----------------------------------------------------------------
+	**	Saved info for auto-sense
+	**----------------------------------------------------------------
+	*/
+	u_char		sv_scsi_status;
+	u_char		sv_xerr_status;
+
+	/*----------------------------------------------------------------
 	**	Other fields.
 	**----------------------------------------------------------------
 	*/
 	u_long		p_ccb;		/* BUS address of this CCB	*/
 	u_char		sensecmd[6];	/* Sense command		*/
-	u_char		tag;		/* Tag for this transfer	*/
-					/*  255 means no tag		*/
+	u_char		to_abort;	/* This CCB is to be aborted	*/
+	u_short		tag;		/* Tag for this transfer	*/
+					/*  NO_TAG means no tag		*/
+	u_char		tags_si;	/* Lun tags sum index (0,1)	*/
+
 	u_char		target;
 	u_char		lun;
-	u_char		queued;
-	u_char		auto_sense;
+	u_short		queued;
 	ccb_p		link_ccb;	/* Host adapter CCB chain	*/
 	ccb_p		link_ccbh;	/* Host adapter CCB hash chain	*/
 	XPT_QUEHEAD	link_ccbq;	/* Link to unit CCB queue	*/
 	u_int32		startp;		/* Initial data pointer		*/
+	u_int32		lastp0;		/* Initial 'lastp'		*/
+	int		ext_sg;		/* Extreme data pointer, used	*/
+	int		ext_ofs;	/*  to calculate the residual.	*/
+	int		resid;
 };
 
 #define CCB_PHYS(cp,lbl)	(cp->p_ccb + offsetof(struct ccb, lbl))
@@ -1899,11 +1803,15 @@
 	**	Virtual and physical bus addresses of the chip.
 	**----------------------------------------------------------------
 	*/
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 	u_long		base_va;	/* MMIO base virtual address	*/
+	u_long		base2_va;	/* On-chip RAM virtual address	*/
+#endif
 	u_long		base_ba;	/* MMIO base bus address	*/
 	u_long		base_io;	/* IO space base address	*/
 	u_long		base_ws;	/* (MM)IO window size		*/
-	u_long		base2_ba;	/* On-chip RAM bus address.	*/
+	u_long		base2_ba;	/* On-chip RAM bus address	*/
+	u_long		base2_ws;	/* On-chip RAM window size	*/
 	u_int		irq;		/* IRQ number			*/
 	volatile			/* Pointer to volatile for 	*/
 	struct ncr_reg	*reg;		/*  memory mapped IO.		*/
@@ -1912,7 +1820,7 @@
 	**	SCRIPTS virtual and physical bus addresses.
 	**	'script'  is loaded in the on-chip RAM if present.
 	**	'scripth' stays in main memory for all chips except the 
-	**	53C896 that provides 8K on-chip RAM.
+	**	53C895A and 53C896 that provide 8K on-chip RAM.
 	**----------------------------------------------------------------
 	*/
 	struct script	*script0;	/* Copies of script and scripth	*/
@@ -2004,6 +1912,24 @@
 	XPT_QUEHEAD	free_ccbq;	/* Queue of available CCBs	*/
 
 	/*----------------------------------------------------------------
+	**	IMMEDIATE ARBITRATION (IARB) control.
+	**	We keep track in 'last_cp' of the last CCB that has been 
+	**	queued to the SCRIPTS processor and clear 'last_cp' when 
+	**	this CCB completes. If last_cp is not zero at the moment 
+	**	we queue a new CCB, we set a flag in 'last_cp' that is 
+	**	used by the SCRIPTS as a hint for setting IARB.
+	**	We donnot set more than 'iarb_max' consecutive hints for 
+	**	IARB in order to leave devices a chance to reselect.
+	**	By the way, any non zero value of 'iarb_max' is unfair. :)
+	**----------------------------------------------------------------
+	*/
+#ifdef SCSI_NCR_IARB_SUPPORT
+	struct ccb	*last_cp;	/* Last queud CCB used for IARB	*/
+	u_short		iarb_max;	/* Max. # consecutive IARB hints*/
+	u_short		iarb_count;	/* Actual # of these hints	*/
+#endif
+
+	/*----------------------------------------------------------------
 	**	We need the LCB in order to handle disconnections and 
 	**	to count active CCBs for task management. So, we use 
 	**	a unique CCB for LUNs we donnot have the LCB yet.
@@ -2019,6 +1945,17 @@
 	int (*scatter) (ccb_p, Scsi_Cmnd *);
 
 	/*----------------------------------------------------------------
+	**	Command abort handling.
+	**	We need to synchronize tightly with the SCRIPTS 
+	**	processor in order to handle things correctly.
+	**----------------------------------------------------------------
+	*/
+	u_char		abrt_msg[4];	/* Message to send buffer	*/
+	struct scr_tblmove abrt_tbl;	/* Table for the MOV of it 	*/
+	struct scr_tblsel  abrt_sel;	/* Sync params for selection	*/
+	u_char		istat_sem;	/* Tells the chip to stop (SEM)	*/
+
+	/*----------------------------------------------------------------
 	**	Fields that should be removed or changed.
 	**----------------------------------------------------------------
 	*/
@@ -2053,34 +1990,53 @@
 
 /*
 **	Script fragments which are loaded into the on-chip RAM 
-**	of 825A, 875, 876, 895 and 896 chips.
+**	of 825A, 875, 876, 895, 895A and 896 chips.
 */
 struct script {
-	ncrcmd	start		[ 10];
+	ncrcmd	start		[ 18];
 	ncrcmd	getjob_begin	[  4];
 	ncrcmd	getjob_end	[  4];
-	ncrcmd	select		[  4];
+	ncrcmd	select		[  8];
 	ncrcmd	wf_sel_done	[  2];
 	ncrcmd	send_ident	[  2];
-	ncrcmd	select2		[  6];
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd	select2		[  8];
+#else
+	ncrcmd	select2		[  2];
+#endif
 	ncrcmd  command		[  2];
-	ncrcmd  dispatch	[ 26];
+	ncrcmd  dispatch	[ 28];
 	ncrcmd  sel_no_cmd	[ 10];
 	ncrcmd  init		[  6];
 	ncrcmd  clrack		[  4];
-	ncrcmd  databreak	[  2];
+	ncrcmd  disp_msg_in	[  2];
+	ncrcmd  disp_status	[  4];
+	ncrcmd  datai_done	[ 16];
+	ncrcmd  datao_done	[ 10];
+	ncrcmd  ign_i_w_r_msg	[  4];
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 	ncrcmd  dataphase	[  4];
 #else
 	ncrcmd  dataphase	[  2];
 #endif
-	ncrcmd  status		[  8];
 	ncrcmd  msg_in		[  2];
-	ncrcmd  msg_in2		[ 16];
-	ncrcmd  msg_bad		[  6];
+	ncrcmd  msg_in2		[ 10];
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd  status		[ 14];
+#else
+	ncrcmd  status		[ 10];
+#endif
 	ncrcmd  complete	[  8];
-	ncrcmd  complete2	[  6];
+#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+	ncrcmd  complete2	[ 12];
+#else
+	ncrcmd  complete2	[ 10];
+#endif
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+	ncrcmd	done		[ 18];
+#else
 	ncrcmd	done		[ 14];
+#endif
 	ncrcmd	done_end	[  2];
 	ncrcmd  save_dp		[  8];
 	ncrcmd  restore_dp	[  4];
@@ -2089,57 +2045,64 @@
 #else
 	ncrcmd  disconnect	[ 20];
 #endif
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd  idle		[  4];
+#else
 	ncrcmd  idle		[  2];
+#endif
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd  ungetjob	[  6];
+#else
 	ncrcmd  ungetjob	[  4];
+#endif
 	ncrcmd	reselect	[  4];
-	ncrcmd	reselected	[ 44];
+	ncrcmd	reselected	[ 48];
+#if   MAX_TASKS*4 > 512
+	ncrcmd	resel_tag	[ 16];
+#elif MAX_TASKS*4 > 256
+	ncrcmd	resel_tag	[ 10];
+#else
 	ncrcmd	resel_tag	[  6];
+#endif
 	ncrcmd	resel_go	[  6];
 	ncrcmd	resel_notag	[  4];
 	ncrcmd	resel_dsa	[  8];
-	ncrcmd  data_in		[MAX_SCATTERL * SCR_SG_SIZE];
+	ncrcmd  data_in		[MAX_SCATTER * SCR_SG_SIZE];
 	ncrcmd  data_in2	[  4];
-	ncrcmd  data_out	[MAX_SCATTERL * SCR_SG_SIZE];
+	ncrcmd  data_out	[MAX_SCATTER * SCR_SG_SIZE];
 	ncrcmd  data_out2	[  4];
 	ncrcmd  pm0_data	[ 16];
 	ncrcmd  pm1_data	[ 16];
-
-	/* Data area */
-	ncrcmd	saved_dsa	[  1];
-	ncrcmd	done_pos	[  1];
-	ncrcmd	startpos	[  1];
-	ncrcmd	targtbl		[  1];
 };
 
 /*
 **	Script fragments which stay in main memory for all chips 
-**	except for the 896 that support 8K on-chip RAM.
+**	except for the 895A and 896 that support 8K on-chip RAM.
 */
 struct scripth {
 	ncrcmd	start64		[  2];
-	ncrcmd	select_no_atn	[  4];
+	ncrcmd	sel_for_abort	[ 18];
+	ncrcmd	sel_for_abort_1	[  2];
+	ncrcmd	select_no_atn	[  8];
 	ncrcmd	wf_sel_done_no_atn [ 4];
-	ncrcmd	cancel		[  4];
-	ncrcmd	msg_reject	[  8];
-	ncrcmd	msg_ign_residue	[ 24];
-	ncrcmd  msg_extended	[ 10];
-	ncrcmd  msg_ext_2	[ 10];
-	ncrcmd	msg_wdtr	[ 14];
+
+	ncrcmd	msg_in_etc	[ 14];
+	ncrcmd	msg_received	[  4];
+	ncrcmd	msg_weird_seen	[  4];
+	ncrcmd	msg_extended	[ 20];
+	ncrcmd  msg_bad		[  6];
+	ncrcmd	msg_weird	[  4];
+	ncrcmd	msg_weird1	[  8];
+
+	ncrcmd	wdtr_resp	[  6];
 	ncrcmd	send_wdtr	[  4];
-	ncrcmd  msg_ext_3	[ 10];
-	ncrcmd	msg_sdtr	[ 14];
+	ncrcmd	sdtr_resp	[  6];
 	ncrcmd	send_sdtr	[  4];
 	ncrcmd	nego_bad_phase	[  4];
 	ncrcmd	msg_out_abort	[ 12];
 	ncrcmd	msg_out		[  6];
 	ncrcmd	msg_out_done	[  4];
-	ncrcmd	no_data		[ 16];
-#if	MAX_SCATTERH != 0
-	ncrcmd  hdata_in	[MAX_SCATTERH * SCR_SG_SIZE];
-	ncrcmd  hdata_in2	[  2];
-	ncrcmd  hdata_out	[MAX_SCATTERH * SCR_SG_SIZE];
-	ncrcmd  hdata_out2	[  2];
-#endif
+	ncrcmd	no_data		[ 28];
 	ncrcmd	abort_resel	[ 16];
 	ncrcmd	resend_ident	[  4];
 	ncrcmd	ident_break	[  4];
@@ -2156,22 +2119,39 @@
 	ncrcmd	pm_handle	[ 20];
 	ncrcmd	pm_handle1	[  4];
 	ncrcmd	pm_save		[  4];
-	ncrcmd	pm0_save	[ 10];
-	ncrcmd	pm1_save	[ 10];
+	ncrcmd	pm0_save	[ 14];
+	ncrcmd	pm1_save	[ 14];
+
+	/* SWIDE handling */
+	ncrcmd	swide_ma_32	[  4];
+	ncrcmd	swide_ma_64	[  6];
+	ncrcmd	swide_scr_64	[ 26];
+	ncrcmd	swide_scr_64_1	[ 12];
+	ncrcmd	swide_com_64	[  6];
+	ncrcmd	swide_common	[ 10];
+	ncrcmd	swide_fin_32	[ 24];
 
 	/* Data area */
+	ncrcmd	zero		[  1];
+	ncrcmd	scratch		[  1];
+	ncrcmd	scratch1	[  1];
 	ncrcmd	pm0_data_addr	[  1];
 	ncrcmd	pm1_data_addr	[  1];
+	ncrcmd	saved_dsa	[  1];
+	ncrcmd	saved_drs	[  1];
+	ncrcmd	done_pos	[  1];
+	ncrcmd	startpos	[  1];
+	ncrcmd	targtbl		[  1];
 	/* End of data area */
 
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 	ncrcmd	start_ram	[  1];
 	ncrcmd	script0_ba	[  4];
-
 	ncrcmd	start_ram64	[  3];
 	ncrcmd	script0_ba64	[  3];
 	ncrcmd	scripth0_ba64	[  6];
 	ncrcmd	ram_seg64	[  1];
-
+#endif
 	ncrcmd	snooptest	[  6];
 	ncrcmd	snoopend	[  2];
 };
@@ -2195,6 +2175,7 @@
 static	lcb_p	ncr_setup_lcb	(ncb_p np, u_char tn, u_char ln,
 				 u_char *inq_data);
 static	void	ncr_getclock	(ncb_p np, int mult);
+static	u_int	ncr_getpciclock (ncb_p np);
 static	void	ncr_selectclock	(ncb_p np, u_char scntl3);
 static	ccb_p	ncr_get_ccb	(ncb_p np, u_char tn, u_char ln);
 static	void	ncr_init	(ncb_p np, int reset, char * msg, u_long code);
@@ -2204,8 +2185,8 @@
 static	void	ncr_int_sir	(ncb_p np);
 static  void    ncr_int_sto     (ncb_p np);
 static  void    ncr_int_udc     (ncb_p np);
-static	u_long	ncr_lookup	(char* id);
-static	void	ncr_negotiate	(struct ncb* np, struct tcb* tp);
+static	void	ncr_negotiate	(ncb_p np, tcb_p tp);
+static	int	ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr);
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 static	void	ncb_profile	(ncb_p np, ccb_p cp);
 #endif
@@ -2219,6 +2200,7 @@
 static	void	ncr_setup_tags	(ncb_p np, u_char tn, u_char ln);
 static	void	ncr_setwide	(ncb_p np, ccb_p cp, u_char wide, u_char ack);
 static	int	ncr_show_msg	(u_char * msg);
+static	void	ncr_print_msg	(ccb_p cp, char *label, u_char * msg);
 static	int	ncr_snooptest	(ncb_p np);
 static	void	ncr_timeout	(ncb_p np);
 static  void    ncr_wakeup      (ncb_p np, u_long code);
@@ -2228,6 +2210,7 @@
 static	void	ncr_soft_reset	(ncb_p np);
 static	void	ncr_start_reset	(ncb_p np);
 static	int	ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay);
+static	int	ncr_compute_residual (ncb_p np, ccb_p cp);
 
 #ifdef SCSI_NCR_USER_COMMAND_SUPPORT
 static	void	ncr_usercmd	(ncb_p np);
@@ -2328,6 +2311,25 @@
 	*/
 	SCR_FROM_REG (ctest2),
 		0,
+
+	/*
+	**	Stop here if the C code wants to perform 
+	**	some error recovery procedure manually.
+	**	(Indicate this by setting SEM in ISTAT)
+	*/
+	SCR_FROM_REG (istat),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (SEM, SEM)),
+		16,
+	/*
+	**	Report to the C code the next position in 
+	**	the start queue the SCRIPTS will schedule.
+	*/
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDRH (startpos),
+	SCR_INT,
+		SIR_SCRIPT_STOPPED,
+
 	/*
 	**	Start the next job.
 	**
@@ -2343,14 +2345,14 @@
 	**	and the the next queue position points to the next JOB.
 	*/
 	SCR_LOAD_ABS (scratcha, 4),
-		PADDR (startpos),
+		PADDRH (startpos),
 	SCR_LOAD_ABS (dsa, 4),
-		PADDR (startpos),
+		PADDRH (startpos),
 	SCR_LOAD_REL (temp, 4),
 		4,
 }/*-------------------------< GETJOB_BEGIN >------------------*/,{
 	SCR_STORE_ABS (temp, 4),
-		PADDR (startpos),
+		PADDRH (startpos),
 	SCR_LOAD_REL (dsa, 4),
 		0,
 }/*-------------------------< GETJOB_END >--------------------*/,{
@@ -2407,6 +2409,19 @@
 	**	So we have to wait immediately for the next phase 
 	**	or the selection to complete or time-out.
 	*/
+
+	/*
+	**      load the savep (saved pointer) into
+	**      the actual data pointer.
+	*/
+	SCR_LOAD_REL (temp, 4),
+		offsetof (struct ccb, phys.header.savep),
+	/*
+	**      Initialize the status registers
+	*/
+	SCR_LOAD_REL (scr0, 4),
+		offsetof (struct ccb, phys.header.status),
+
 }/*-------------------------< WF_SEL_DONE >----------------------*/,{
 	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
 		SIR_SEL_ATN_NO_MSG_OUT,
@@ -2419,17 +2434,18 @@
 	SCR_MOVE_TBL ^ SCR_MSG_OUT,
 		offsetof (struct dsb, smsg),
 }/*-------------------------< SELECT2 >----------------------*/,{
+#ifdef SCSI_NCR_IARB_SUPPORT
 	/*
-	**      load the savep (saved pointer) into
-	**      the actual data pointer.
-	*/
-	SCR_LOAD_REL (temp, 4),
-		offsetof (struct ccb, phys.header.savep),
-	/*
-	**      Initialize the status registers
+	**	Set IMMEDIATE ARBITRATION if we have been given 
+	**	a hint to do so. (Some job to do after this one).
 	*/
-	SCR_LOAD_REL (scr0, 4),
-		offsetof (struct ccb, phys.header.status),
+	SCR_FROM_REG (HF_REG),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
+		8,
+	SCR_REG_REG (scntl1, SCR_OR, IARB),
+		0,
+#endif
 	/*
 	**	Anticipate the COMMAND phase.
 	**	This is the PHASE we expect at this point.
@@ -2465,7 +2481,9 @@
 	/*
 	**      Discard one illegal phase byte, if required.
 	*/
-	SCR_LOAD_REG (scratcha, XE_BAD_PHASE),
+	SCR_LOAD_REL (scratcha, 1),
+		offsetof (struct ccb, xerr_status),
+	SCR_REG_REG (scratcha, SCR_OR, XE_BAD_PHASE),
 		0,
 	SCR_STORE_REL (scratcha, 1),
 		offsetof (struct ccb, xerr_status),
@@ -2517,7 +2535,7 @@
 	SCR_FROM_REG (sstat0),
 		0,
 	SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)),
-		-8,
+		-16,
 	SCR_JUMP,
 		PADDR (start),
 }/*-------------------------< CLRACK >----------------------*/,{
@@ -2529,37 +2547,115 @@
 	SCR_JUMP,
 		PADDR (dispatch),
 
-}/*-------------------------< DATABREAK >-------------------*/,{
+}/*-------------------------< DISP_MSG_IN >----------------------*/,{
 	/*
-	**	Jump to dispatcher.
+	**	Anticipate MSG_IN phase then STATUS phase.
+	**
+	**	May spare 2 SCRIPTS instructions when we have 
+	**	completed the OUTPUT of the data and the device 
+	**	goes directly to STATUS phase.
 	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR (msg_in),
+
+}/*-------------------------< DISP_STATUS >----------------------*/,{
+	/*
+	**	Anticipate STATUS phase.
+	**
+	**	Does spare 3 SCRIPTS instructions when we have 
+	**	completed the INPUT of the data.
+	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
+		PADDR (status),
 	SCR_JUMP,
 		PADDR (dispatch),
 
-}/*-------------------------< DATAPHASE >------------------*/,{
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	SCR_REG_REG (HF_REG, SCR_OR, HF_DATA_ST),
+}/*-------------------------< DATAI_DONE >-------------------*/,{
+	/*
+	**	If the SWIDE is not full, jump to dispatcher.
+	**	We anticipate a STATUS phase.
+	**	If we get later an IGNORE WIDE RESIDUE, we 
+	**	will alias it as a MODIFY DP (-1).
+	*/
+	SCR_FROM_REG (scntl2),
 		0,
-#endif
-	SCR_RETURN,
- 		0,
-
-}/*-------------------------< STATUS >--------------------*/,{
+	SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)),
+		PADDR (disp_status),
 	/*
-	**	get the status
+	**	The SWIDE is full.
+	**	Clear this condition.
 	*/
-	SCR_MOVE_ABS (1) ^ SCR_STATUS,
-		NADDR (scratch),
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
 	/*
-	**	save status to scsi_status.
-	**	mark as complete.
+	**	Since the device is required to send any 
+	**	IGNORE WIDE RESIDUE message prior to any
+	**	other information, we just snoop the SCSI 
+	**	BUS to check for such a message.
 	*/
-	SCR_TO_REG (SS_REG),
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (disp_status),
+	SCR_FROM_REG (sbdl),
 		0,
-	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+	SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		PADDR (disp_status),
+	/*
+	**	We have been ODD at the end of the transfer, 
+	**	but the device hasn't be so.
+	**	Signal a DATA OVERRUN condition to the C code.
+	*/
+	SCR_INT,
+		SIR_SWIDE_OVERRUN,
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< DATAO_DONE >-------------------*/,{
+	/*
+	**	If the SODL is not full jump to dispatcher.
+	**	We anticipate a MSG IN phase or a STATUS phase.
+	*/
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
+		PADDR (disp_msg_in),
+	/*
+	**	The SODL is full, clear this condition.
+	*/
+	SCR_REG_REG (scntl2, SCR_OR, WSS),
 		0,
+	/*
+	**	And signal a DATA UNDERRUN condition 
+	**	to the C code.
+	*/
+	SCR_INT,
+		SIR_SODL_UNDERRUN,
 	SCR_JUMP,
 		PADDR (dispatch),
+
+}/*-------------------------< IGN_I_W_R_MSG >--------------*/,{
+	/*
+	**	We jump here from the phase mismatch interrupt, 
+	**	When we have a SWIDE and the device has presented 
+	**	a IGNORE WIDE RESIDUE message on the BUS.
+	**	We just have to throw away this message and then 
+	**	to jump to dispatcher.
+	*/
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+		NADDR (scratch),
+	/*
+	**	Clear ACK and jump to dispatcher.
+	*/
+	SCR_JUMP,
+		PADDR (clrack),
+
+}/*-------------------------< DATAPHASE >------------------*/,{
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	SCR_REG_REG (HF_REG, SCR_OR, HF_DATA_ST),
+		0,
+#endif
+	SCR_RETURN,
+ 		0,
+
 }/*-------------------------< MSG_IN >--------------------*/,{
 	/*
 	**	Get the first byte of the message.
@@ -2571,7 +2667,8 @@
 		NADDR (msgin[0]),
 }/*-------------------------< MSG_IN2 >--------------------*/,{
 	/*
-	**	Handle this message.
+	**	Check first against 1 byte messages 
+	**	that we handle from SCRIPTS.
 	*/
 	SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
 		PADDR (complete),
@@ -2581,31 +2678,47 @@
 		PADDR (save_dp),
 	SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
 		PADDR (restore_dp),
-	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
-		PADDRH (msg_extended),
-	SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
-		PADDR (clrack),
-	SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
-		PADDRH (msg_reject),
-	SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
-		PADDRH (msg_ign_residue),
 	/*
-	**	Rest of the messages left as
-	**	an exercise ...
-	**
-	**	Unimplemented messages:
-	**	fall through to MSG_BAD.
+	**	We handle all other messages from the 
+	**	C code, so no need to waste on-chip RAM 
+	**	for those ones.
 	*/
-}/*-------------------------< MSG_BAD >------------------*/,{
+	SCR_JUMP,
+		PADDRH (msg_in_etc),
+
+}/*-------------------------< STATUS >--------------------*/,{
 	/*
-	**	unimplemented message - reject it.
+	**	get the status
 	*/
-	SCR_INT,
-		SIR_REJECT_TO_SEND,
-	SCR_SET (SCR_ATN),
+	SCR_MOVE_ABS (1) ^ SCR_STATUS,
+		NADDR (scratch),
+#ifdef SCSI_NCR_IARB_SUPPORT
+	/*
+	**	If STATUS is not GOOD, clear IMMEDIATE ARBITRATION, 
+	**	since we may have to tamper the start queue from 
+	**	the C code.
+	*/
+	SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
+		8,
+	SCR_REG_REG (scntl1, SCR_AND, ~IARB),
 		0,
+#endif
+	/*
+	**	save status to scsi_status.
+	**	mark as complete.
+	*/
+	SCR_TO_REG (SS_REG),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+		0,
+	/*
+	**	Anticipate the MESSAGE PHASE for 
+	**	the TASK COMPLETE message.
+	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR (msg_in),
 	SCR_JUMP,
-		PADDR (clrack),
+		PADDR (dispatch),
 
 }/*-------------------------< COMPLETE >-----------------*/,{
 	/*
@@ -2642,6 +2755,18 @@
 	SCR_STORE_REL (scr0, 4),
 		offsetof (struct ccb, phys.header.status),
 
+#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+	/*
+	**	Some bridges may reorder DMA writes to memory.
+	**	We donnot want the CPU to deal with completions  
+	**	without all the posted write having been flushed 
+	**	to memory. This DUMMY READ should flush posted 
+	**	buffers prior to the CPU having to deal with 
+	**	completions.
+	*/
+	SCR_LOAD_REL (scr0, 4),	/* DUMMY READ */
+		offsetof (struct ccb, phys.header.status),
+#endif
 	/*
 	**	If command resulted in not GOOD status,
 	**	call the C code if needed.
@@ -2651,7 +2776,35 @@
 	SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
 		PADDRH (bad_status),
 
+	/*
+	**	If we performed an auto-sense, call 
+	**	the C code to synchronyze task aborts 
+	**	with UNIT ATTENTION conditions.
+	*/
+	SCR_FROM_REG (HF_REG),
+		0,
+	SCR_INT ^ IFTRUE (MASK (HF_AUTO_SENSE, HF_AUTO_SENSE)),
+		SIR_AUTO_SENSE_DONE,
+
 }/*------------------------< DONE >-----------------*/,{
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+	/*
+	**	It seems that some bridges flush everything 
+	**	when the INTR line is raised. For these ones, 
+	**	we can just ensure that the INTR line will be 
+	**	raised before each completion. So, if it happens 
+	**	that we have been faster that the CPU, we just 
+	**	have to synchronize with it. A dummy programmed 
+	**	interrupt will do the trick.
+	**	Note that we overlap at most 1 IO with the CPU 
+	**	in this situation and that the IRQ line must not 
+	**	be shared.
+	*/
+	SCR_FROM_REG (istat),
+		0,
+	SCR_INT ^ IFTRUE (MASK (INTF, INTF)),
+		SIR_DUMMY_INTERRUPT,
+#endif
 	/*
 	**	Copy the DSA to the DONE QUEUE and 
 	**	signal completion to the host.
@@ -2660,11 +2813,11 @@
 	**	the completed CCB will be lost.
 	*/
 	SCR_STORE_ABS (dsa, 4),
-		PADDR (saved_dsa),
+		PADDRH (saved_dsa),
 	SCR_LOAD_ABS (dsa, 4),
-		PADDR (done_pos),
+		PADDRH (done_pos),
 	SCR_LOAD_ABS (scratcha, 4),
-		PADDR(saved_dsa),
+		PADDRH (saved_dsa),
 	SCR_STORE_REL (scratcha, 4),
 		0,
 	/*
@@ -2679,7 +2832,7 @@
 	SCR_INT_FLY,
 		0,
 	SCR_STORE_ABS (temp, 4),
-		PADDR (done_pos),
+		PADDRH (done_pos),
 }/*------------------------< DONE_END >-----------------*/,{
 	SCR_JUMP,
 		PADDR (start),
@@ -2791,9 +2944,22 @@
 	*/
 	SCR_NO_OP,
 		0,
+#ifdef SCSI_NCR_IARB_SUPPORT
+	SCR_JUMPR,
+		8,
+#endif
 }/*-------------------------< UNGETJOB >-----------------*/,{
+#ifdef SCSI_NCR_IARB_SUPPORT
 	/*
-	**	We are not able to restart the SCRIPTS if we are 
+	**	Set IMMEDIATE ARBITRATION, for the next time.
+	**	This will give us better chance to win arbitration 
+	**	for the job we just wanted to do.
+	*/
+	SCR_REG_REG (scntl1, SCR_OR, IARB),
+		0,
+#endif
+	/*
+	**	We are not able to restart the SCRIPTS if we are 
 	**	interrupted and these instruction haven't been 
 	**	all executed. BTW, this is very unlikely to 
 	**	happen, but we check that from the C code.
@@ -2801,7 +2967,7 @@
 	SCR_LOAD_REG (dsa, 0xff),
 		0,
 	SCR_STORE_ABS (scratcha, 4),
-		PADDR (startpos),
+		PADDRH (startpos),
 }/*-------------------------< RESELECT >--------------------*/,{
 	/*
 	**	make the host status invalid.
@@ -2834,7 +3000,7 @@
 	**	load the target control block address
 	*/
 	SCR_LOAD_ABS (dsa, 4),
-		PADDR (targtbl),
+		PADDRH (targtbl),
 	SCR_SFBR_REG (dsa, SCR_SHL, 0),
 		0,
 	SCR_REG_REG (dsa, SCR_SHL, 0),
@@ -2870,12 +3036,13 @@
 	/*
 	**	It is an IDENTIFY message,
 	**	Load the LUN control block address.
-	**	Avoid nasty address calculation if LUN #0.
+	**	If LUN 0, avoid a PCI BUS ownership by loading 
+	**	directly 'b_lun0' from the TCB.
 	*/
+	SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)),
+		48,
 	SCR_LOAD_REL (dsa, 4),
 		offsetof(struct tcb, b_luntbl),
-	SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)),
-		24,
 	SCR_SFBR_REG (dsa, SCR_SHL, 0),
 		0,
 	SCR_REG_REG (dsa, SCR_SHL, 0),
@@ -2884,6 +3051,14 @@
 		0,
 	SCR_LOAD_REL (dsa, 4),
 		0,
+	SCR_JUMPR,
+		8,
+	/*
+	**	LUN 0 special case (but usual one :))
+	*/
+	SCR_LOAD_REL (dsa, 4),
+		offsetof(struct tcb, b_lun0),
+
 	/*
 	**	Load the reselect task action for this LUN.
 	**	Load the tasks DSA array for this LUN.
@@ -2914,6 +3089,23 @@
 	*/
 	SCR_REG_SFBR (sidl, SCR_SHL, 0),
 		0,
+#if MAX_TASKS*4 > 512
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 2),
+		0,
+	SCR_REG_REG (sfbr, SCR_SHL, 0),
+		0,
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 1),
+		0,
+#elif MAX_TASKS*4 > 256
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 1),
+		0,
+#endif
 	/*
 	**	Retrieve the DSA of this task.
 	**	JUMP indirectly to the restart point of the CCB.
@@ -2966,13 +3158,11 @@
 }/*-------------------------< DATA_IN >--------------------*/,{
 /*
 **	Because the size depends on the
-**	#define MAX_SCATTERL parameter,
+**	#define MAX_SCATTER parameter,
 **	it is filled in at runtime.
 **
-**  ##===========< i=0; i<MAX_SCATTERL >=========
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
+**  ##===========< i=0; i<MAX_SCATTER >=========
+**  ||	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 **  ||		offsetof (struct dsb, data[ i]),
 **  ##==========================================
 **
@@ -2981,19 +3171,17 @@
 0
 }/*-------------------------< DATA_IN2 >-------------------*/,{
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (datai_done),
 	SCR_JUMP,
 		PADDRH (no_data),
 }/*-------------------------< DATA_OUT >--------------------*/,{
 /*
 **	Because the size depends on the
-**	#define MAX_SCATTERL parameter,
+**	#define MAX_SCATTER parameter,
 **	it is filled in at runtime.
 **
-**  ##===========< i=0; i<MAX_SCATTERL >=========
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+**  ##===========< i=0; i<MAX_SCATTER >=========
+**  ||	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 **  ||		offsetof (struct dsb, data[ i]),
 **  ##==========================================
 **
@@ -3002,7 +3190,7 @@
 0
 }/*-------------------------< DATA_OUT2 >-------------------*/,{
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (datao_done),
 	SCR_JUMP,
 		PADDRH (no_data),
 
@@ -3019,11 +3207,11 @@
 	*/
 	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
 		16,
-	SCR_MOVE_TBL ^ SCR_DATA_IN,
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 		offsetof (struct ccb, phys.pm0.sg),
 	SCR_JUMPR,
 		8,
-	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 		offsetof (struct ccb, phys.pm0.sg),
 	/*
 	**	Clear the flag that told we were in 
@@ -3053,11 +3241,11 @@
 	*/
 	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
 		16,
-	SCR_MOVE_TBL ^ SCR_DATA_IN,
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 		offsetof (struct ccb, phys.pm1.sg),
 	SCR_JUMPR,
 		8,
-	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 		offsetof (struct ccb, phys.pm1.sg),
 	/*
 	**	Clear the flag that told we were in 
@@ -3074,27 +3262,76 @@
 		offsetof (struct ccb, phys.pm1.ret),
 	SCR_RETURN,
 		0,
-
-}/*-------------------------< SAVED_DSA >-------------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< DONE_POS >--------------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< STARTPOS >--------------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< TARGTBL >---------------------*/,{
-	SCR_DATA_ZERO,
-}/*--------------------------------------------------------*/
+}/*---------------------------------------------------------*/
 };
 
 static	struct scripth scripth0 __initdata = {
 /*------------------------< START64 >-----------------------*/{
 	/*
-	**	SCRIPT entry point for the 896.
+	**	SCRIPT entry point for the 895A and the 896.
 	**	For now, there is no specific stuff for that 
 	**	chip at this point, but this may come.
 	*/
 	SCR_JUMP,
 		PADDR (init),
+
+}/*-----------------------< SEL_FOR_ABORT >------------------*/,{
+	/*
+	**	We are jumped here by the C code, if we have 
+	**	some target to reset or some disconnected 
+	**	job to abort. Since error recovery is a serious 
+	**	busyness, we will really reset the SCSI BUS, if 
+	**	case of a SCSI interrupt occuring in this path.
+	*/
+
+	/*
+	**	Set initiator mode.
+	*/
+	SCR_CLR (SCR_TRG),
+		0,
+	/*
+	**      And try to select this target.
+	*/
+	SCR_SEL_TBL_ATN ^ offsetof (struct ncb, abrt_sel),
+		PADDR (reselect),
+
+	/*
+	**	Wait for the selection to complete or 
+	**	the selection to time out.
+	*/
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		-8,
+	/*
+	**	Call the C code.
+	*/
+	SCR_INT,
+		SIR_TARGET_SELECTED,
+	/*
+	**	The C code should let us continue here. 
+	**	Send the 'kiss of death' message.
+	**	We expect an immediate disconnect once 
+	**	the target has eaten the message.
+	*/
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct ncb, abrt_tbl),
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	/*
+	**	Tell the C code that we are done.
+	*/
+	SCR_INT,
+		SIR_ABORT_SENT,
+}/*-----------------------< SEL_FOR_ABORT_1 >--------------*/,{
+	/*
+	**	Jump at scheduler.
+	*/
+	SCR_JUMP,
+		PADDR (start),
+
 }/*------------------------< SELECT_NO_ATN >-----------------*/,{
 	/*
 	**	Set Initiator mode.
@@ -3105,6 +3342,18 @@
 		0,
 	SCR_SEL_TBL ^ offsetof (struct dsb, select),
 		PADDR (ungetjob),
+	/*
+	**      load the savep (saved pointer) into
+	**      the actual data pointer.
+	*/
+	SCR_LOAD_REL (temp, 4),
+		offsetof (struct ccb, phys.header.savep),
+	/*
+	**      Initialize the status registers
+	*/
+	SCR_LOAD_REL (scr0, 4),
+		offsetof (struct ccb, phys.header.status),
+
 }/*------------------------< WF_SEL_DONE_NO_ATN >-----------------*/,{
 	/*
 	**	Wait immediately for the next phase or 
@@ -3115,129 +3364,111 @@
 	SCR_JUMP,
 		PADDR (select2),
 
-}/*-------------------------< CANCEL >------------------------*/,{
+}/*-------------------------< MSG_IN_ETC >--------------------*/,{
 	/*
-	**	Load the host status.
+	**	If it is an EXTENDED (variable size message)
+	**	Handle it.
 	*/
-	SCR_LOAD_REG (HS_REG, HS_ABORTED),
-		0,
-	SCR_JUMP,
-		PADDR (complete2),
-
-}/*-------------------------< MSG_REJECT >---------------*/,{
+	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+		PADDRH (msg_extended),
 	/*
-	**	If a negotiation was in progress,
-	**	negotiation failed.
-	**	Otherwise just make host log this message
+	**	Let the C code handle any other 
+	**	1 byte message.
 	*/
-	SCR_FROM_REG (HS_REG),
+	SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)),
+		PADDRH (msg_received),
+	SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)),
+		PADDRH (msg_received),
+	/*
+	**	We donnot handle 2 bytes messages from SCRIPTS.
+	**	So, let the C code deal with these ones too.
+	*/
+	SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)),
+		PADDRH (msg_weird_seen),
+	SCR_CLR (SCR_ACK),
 		0,
-	SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
-		SIR_REJECT_RECEIVED,
-	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
-		SIR_NEGO_FAILED,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[1]),
 	SCR_JUMP,
-		PADDR (clrack),
+		PADDRH (msg_received),
+
+}/*-------------------------< MSG_RECEIVED >--------------------*/,{
+	SCR_LOAD_REL (scratcha, 4),	/* DUMMY READ */
+		0,
+	SCR_INT,
+		SIR_MSG_RECEIVED,
+
+}/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{
+	SCR_LOAD_REL (scratcha1, 4),	/* DUMMY READ */
+		0,
+	SCR_INT,
+		SIR_MSG_WEIRD,
 
-}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
+}/*-------------------------< MSG_EXTENDED >--------------------*/,{
 	/*
-	**	Terminate cycle
+	**	Clear ACK and get the next byte 
+	**	assumed to be the message length.
 	*/
 	SCR_CLR (SCR_ACK),
 		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get residue size.
-	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[1]),
 	/*
-	**	Size is 0 .. ignore message.
+	**	Try to catch some unlikely situations as 0 length 
+	**	or too large the length.
 	*/
 	SCR_JUMP ^ IFTRUE (DATA (0)),
-		PADDR (clrack),
-	/*
-	**	Size is not 1 .. have to interrupt.
-	*/
-	SCR_JUMPR ^ IFFALSE (DATA (1)),
-		40,
-	/*
-	**	Check for residue byte in swide register
-	*/
-	SCR_FROM_REG (scntl2),
+		PADDRH (msg_weird_seen),
+	SCR_TO_REG (scratcha),
 		0,
-	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
-		16,
+	SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
+		0,
+	SCR_JUMP ^ IFTRUE (CARRYSET),
+		PADDRH (msg_weird_seen),
 	/*
-	**	There IS data in the swide register.
-	**	Discard it.
+	**	We donnot handle extended messages from SCRIPTS.
+	**	Read the amount of data correponding to the 
+	**	message length and call the C code.
 	*/
-	SCR_REG_REG (scntl2, SCR_OR, WSR),
+	SCR_STORE_REL (scratcha, 1),
+		offsetof (struct dsb, smsg_ext.size),
+	SCR_CLR (SCR_ACK),
 		0,
+	SCR_MOVE_TBL ^ SCR_MSG_IN,
+		offsetof (struct dsb, smsg_ext),
 	SCR_JUMP,
-		PADDR (clrack),
+		PADDRH (msg_received),
+
+}/*-------------------------< MSG_BAD >------------------*/,{
 	/*
-	**	Load again the size to the sfbr register.
+	**	unimplemented message - reject it.
 	*/
-	SCR_FROM_REG (scratcha),
-		0,
 	SCR_INT,
-		SIR_IGN_RESIDUE,
+		SIR_REJECT_TO_SEND,
+	SCR_SET (SCR_ATN),
+		0,
 	SCR_JUMP,
 		PADDR (clrack),
 
-}/*-------------------------< MSG_EXTENDED >-------------*/,{
+}/*-------------------------< MSG_WEIRD >--------------------*/,{
 	/*
-	**	Terminate cycle
+	**	weird message received
+	**	ignore all MSG IN phases and reject it.
 	*/
-	SCR_CLR (SCR_ACK),
+	SCR_INT,
+		SIR_REJECT_TO_SEND,
+	SCR_SET (SCR_ATN),
 		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get length.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[1]),
-	/*
-	*/
-	SCR_JUMP ^ IFTRUE (DATA (3)),
-		PADDRH (msg_ext_3),
-	SCR_JUMP ^ IFFALSE (DATA (2)),
-		PADDR (msg_bad),
-}/*-------------------------< MSG_EXT_2 >----------------*/,{
+}/*-------------------------< MSG_WEIRD1 >--------------------*/,{
 	SCR_CLR (SCR_ACK),
 		0,
 	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
 		PADDR (dispatch),
-	/*
-	**	get extended message code.
-	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[2]),
-	SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
-		PADDRH (msg_wdtr),
-	/*
-	**	unknown extended message
-	*/
+		NADDR (scratch),
 	SCR_JUMP,
-		PADDR (msg_bad)
-}/*-------------------------< MSG_WDTR >-----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get data bus width
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[3]),
-	/*
-	**	let the host do the real work.
-	*/
-	SCR_INT,
-		SIR_NEGO_WIDE,
+		PADDRH (msg_weird1),
+}/*-------------------------< WDTR_RESP >----------------*/,{
 	/*
 	**	let the target fetch our answer.
 	*/
@@ -3257,39 +3488,7 @@
 	SCR_JUMP,
 		PADDRH (msg_out_done),
 
-}/*-------------------------< MSG_EXT_3 >----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get extended message code.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[2]),
-	SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
-		PADDRH (msg_sdtr),
-	/*
-	**	unknown extended message
-	*/
-	SCR_JUMP,
-		PADDR (msg_bad)
-
-}/*-------------------------< MSG_SDTR >-----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get period and offset
-	*/
-	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
-		NADDR (msgin[3]),
-	/*
-	**	let the host do the real work.
-	*/
-	SCR_INT,
-		SIR_NEGO_SYNC,
+}/*-------------------------< SDTR_RESP >-------------*/,{
 	/*
 	**	let the target fetch our answer.
 	*/
@@ -3372,7 +3571,9 @@
 	**	or in the wrong direction.
 	**      Remember that in extended error.
 	*/
-	SCR_LOAD_REG (scratcha, XE_EXTRA_DATA),
+	SCR_LOAD_REL (scratcha, 1),
+		offsetof (struct ccb, xerr_status),
+	SCR_REG_REG (scratcha, SCR_OR, XE_EXTRA_DATA),
 		0,
 	SCR_STORE_REL (scratcha, 1),
 		offsetof (struct ccb, xerr_status),
@@ -3388,57 +3589,28 @@
 	SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
 		NADDR (scratch),
 	/*
+	**	Count this byte.
+	**	This will allow to return a positive 
+	**	residual to user.
+	*/
+	SCR_LOAD_REL (scratcha, 4),
+		offsetof (struct ccb, phys.extra_bytes),
+	SCR_REG_REG (scratcha,  SCR_ADD,  0x01),
+		0,
+	SCR_REG_REG (scratcha1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (scratcha2, SCR_ADDC, 0),
+		0,
+	SCR_STORE_REL (scratcha, 4),
+		offsetof (struct ccb, phys.extra_bytes),
+	/*
 	**      .. and repeat as required.
 	*/
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (dispatch),
 	SCR_JUMP,
 		PADDRH (no_data),
 
-#if	MAX_SCATTERH != 0
-
-}/*-------------------------< HDATA_IN >-------------------*/,{
-/*
-**	Because the size depends on the
-**	#define MAX_SCATTERH parameter,
-**	it is filled in at runtime.
-**
-**  ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
-**  ||		offsetof (struct dsb, data[ i]),
-**  ##===================================================
-**
-**---------------------------------------------------------
-*/
-0
-}/*-------------------------< HDATA_IN2 >------------------*/,{
-	SCR_JUMP,
-		PADDR (data_in),
-
-}/*-------------------------< HDATA_OUT >-------------------*/,{
-/*
-**	Because the size depends on the
-**	#define MAX_SCATTERH parameter,
-**	it is filled in at runtime.
-**
-**  ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
-**  ||		offsetof (struct dsb, data[ i]),
-**  ##===================================================
-**
-**---------------------------------------------------------
-*/
-0
-}/*-------------------------< HDATA_OUT2 >------------------*/,{
-	SCR_JUMP,
-		PADDR (data_out),
-
-#endif	/* MAX_SCATTERH */
-
 }/*-------------------------< ABORT_RESEL >----------------*/,{
 	SCR_SET (SCR_ATN),
 		0,
@@ -3482,10 +3654,10 @@
 	SCR_JUMP,
 		PADDR (select2),
 }/*-------------------------< SDATA_IN >-------------------*/,{
-	SCR_MOVE_TBL ^ SCR_DATA_IN,
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 		offsetof (struct dsb, sense),
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (dispatch),
 	SCR_JUMP,
 		PADDRH (no_data),
 
@@ -3588,7 +3760,7 @@
 	**	call the C code.
 	*/
 	SCR_LOAD_ABS (scratcha, 4),
-		PADDR (startpos),
+		PADDRH (startpos),
 	SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
 		SIR_BAD_STATUS,
 	SCR_INT ^ IFTRUE (DATA (S_CHECK_COND)),
@@ -3690,6 +3862,17 @@
 	SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)),
 		PADDRH (pm1_save),
 }/*-------------------------< PM0_SAVE >-------------------*/,{
+	SCR_STORE_REL (ia, 4),
+		offsetof(struct ccb, phys.pm0.ret),
+	/*
+	**	If WSR bit is set, either UA and RBC may 
+	**	have to be changed whatever the device wants 
+	**	to ignore this residue ot not.
+	*/
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+		PADDRH (swide_scr_64),
 	/*
 	**	Save the remaining byte count, the updated 
 	**	address and the return address.
@@ -3698,16 +3881,25 @@
 		offsetof(struct ccb, phys.pm0.sg.size),
 	SCR_STORE_REL (ua, 4),
 		offsetof(struct ccb, phys.pm0.sg.addr),
-	SCR_STORE_REL (ia, 4),
-		offsetof(struct ccb, phys.pm0.ret),
 	/*
 	**	Set the current pointer at the PM0 DATA mini-script.
 	*/
 	SCR_LOAD_ABS (temp, 4),
 		PADDRH (pm0_data_addr),
 	SCR_JUMP,
-		PADDR (databreak),
+		PADDR (dispatch),
 }/*-------------------------< PM1_SAVE >-------------------*/,{
+	SCR_STORE_REL (ia, 4),
+		offsetof(struct ccb, phys.pm1.ret),
+	/*
+	**	If WSR bit is set, either UA and RBC may 
+	**	have been changed whatever the device wants 
+	**	to ignore this residue or not.
+	*/
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+		PADDRH (swide_scr_64),
 	/*
 	**	Save the remaining byte count, the updated 
 	**	address and the return address.
@@ -3716,49 +3908,267 @@
 		offsetof(struct ccb, phys.pm1.sg.size),
 	SCR_STORE_REL (ua, 4),
 		offsetof(struct ccb, phys.pm1.sg.addr),
-	SCR_STORE_REL (ia, 4),
-		offsetof(struct ccb, phys.pm1.ret),
 	/*
 	**	Set the current pointer at the PM1 DATA mini-script.
 	*/
 	SCR_LOAD_ABS (temp, 4),
 		PADDRH (pm1_data_addr),
 	SCR_JUMP,
-		PADDR (databreak),
-}/*-------------------------< PM0_DATA_ADDR >---------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< PM1_DATA_ADDR >---------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< START_RAM >-------------------*/,{
+		PADDR (dispatch),
+
+}/*--------------------------< SWIDE_MA_32 >-----------------------*/,{
 	/*
-	**	Load the script into on-chip RAM, 
-	**	and jump to start point.
+	**	Handling of the SWIDE for 32 bit chips.
+	**
+	**	We jump here from the C code with SCRATCHA 
+	**	containing the address to write the SWIDE.
+	**	- Save 32 bit address in <scratch>.
 	*/
-	SCR_COPY (sizeof (struct script)),
-}/*-------------------------< SCRIPT0_BA >--------------------*/,{
-		0,
-		PADDR (start),
+	SCR_STORE_ABS (scratcha, 4),
+		PADDRH (scratch),
 	SCR_JUMP,
-		PADDR (init),
-
-}/*-------------------------< START_RAM64 >--------------------*/,{
+		PADDRH (swide_common),
+}/*--------------------------< SWIDE_MA_64 >-----------------------*/,{
 	/*
-	**	Load the RAM and start for 64 bit PCI (896).
-	**	Both scripts (script and scripth) are loaded into 
-	**	the RAM which is 8K (4K for 825A/875/895).
-	**	We also need to load some 32-63 bit segments 
-	**	address of the SCRIPTS processor.
-	**	LOAD/STORE ABSOLUTE always refers to on-chip RAM 
-	**	in our implementation. The main memory is 
-	**	accessed using LOAD/STORE DSA RELATIVE.
+	**	Handling of the SWIDE for 64 bit chips when the 
+	**	hardware handling of phase mismatch is disabled.
+	**
+	**	We jump here from the C code with SCRATCHA 
+	**	containing the address to write the SWIDE and 
+	**	SBR containing bit 32..39 of this address.
+	**	- Save 32 bit address in <scratch>.
+	**	- Move address bit 32..39 to SFBR.
 	*/
-	SCR_LOAD_REL (mmws, 4),
-		offsetof (struct ncb, scr_ram_seg),
-	SCR_COPY (sizeof(struct script)),
-}/*-------------------------< SCRIPT0_BA64 >--------------------*/,{
+	SCR_STORE_ABS (scratcha, 4),
+		PADDRH (scratch),
+	SCR_FROM_REG (sbr),
 		0,
-		PADDR (start),
-	SCR_COPY (sizeof(struct scripth)),
+	SCR_JUMP,
+		PADDRH (swide_com_64),
+}/*--------------------------< SWIDE_SCR_64 >-----------------------*/,{
+	/*
+	**	Handling of the SWIDE for 64 bit chips when 
+	**	hardware phase mismatch is enabled.
+	**	We are entered with a SCR_CALL from PMO_SAVE 
+	**	and PM1_SAVE sub-scripts.
+	**
+	**	Snoop the SCSI BUS in case of the device 
+	**	willing to ignore this residue.
+	**	If it does, we must only increment the RBC, 
+	**	since this register does reflect all bytes 
+	**	received from the SCSI BUS including the SWIDE.
+	*/
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDRH (swide_scr_64_1),
+	SCR_FROM_REG (sbdl),
+		0,
+	SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		PADDRH (swide_scr_64_1),
+	SCR_REG_REG (rbc, SCR_ADD, 1),
+		0,
+	SCR_REG_REG (rbc1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (rbc2, SCR_ADDC, 0),
+		0,
+	/*
+	**	Save UA and RBC, since the PM0/1_SAVE 
+	**	sub-scripts haven't moved them to the 
+	**	context yet and the below MOV may just 
+	**	change their value.
+	*/
+	SCR_STORE_ABS (ua, 4),
+		PADDRH (scratch),
+	SCR_STORE_ABS (rbc, 4),
+		PADDRH (scratch1),
+	/*
+	**	Throw away the IGNORE WIDE RESIDUE message.
+	**	since we just did take care of it.
+	*/
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+		NADDR (scratch),
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	**	Restore UA and RBC registers and return.
+	*/
+	SCR_LOAD_ABS (ua, 4),
+		PADDRH (scratch),
+	SCR_LOAD_ABS (rbc, 4),
+		PADDRH (scratch1),
+	SCR_RETURN,
+		0,
+}/*--------------------------< SWIDE_SCR_64_1 >---------------------*/,{
+	/*
+	**	We must grab the SWIDE and move it to 
+	**	memory.
+	**
+	**	- Save UA (32 bit address) in <scratch>.
+	**	- Move address bit 32..39 to SFBR.
+	**	- Increment UA (updated address).
+	*/
+	SCR_STORE_ABS (ua, 4),
+		PADDRH (scratch),
+	SCR_FROM_REG (rbc3),
+		0,
+	SCR_REG_REG (ua, SCR_ADD, 1),
+		0,
+	SCR_REG_REG (ua1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (ua2, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (ua3, SCR_ADDC, 0),
+		0,
+}/*--------------------------< SWIDE_COM_64 >-----------------------*/,{
+	/*
+	**	- Save DRS.
+	**	- Load DRS with address bit 32..39 of the
+	**	  location to write the SWIDE.
+	**	  SFBR has been loaded with these bits.
+	**	  (Look above).
+	*/
+	SCR_STORE_ABS (drs, 4),
+		PADDRH (saved_drs),
+	SCR_LOAD_ABS (drs, 4),
+		PADDRH (zero),
+	SCR_TO_REG (drs),
+		0,
+}/*--------------------------< SWIDE_COMMON >-----------------------*/,{
+	/*
+	**	- Save current DSA
+	**	- Load DSA with bit 0..31 of the memory 
+	**	  location to write the SWIDE.
+	*/
+	SCR_STORE_ABS (dsa, 4),
+		PADDRH (saved_dsa),
+	SCR_LOAD_ABS (dsa, 4),
+		PADDRH (scratch),
+	/*
+	**	Move the SWIDE to memory.
+	**	Clear the WSR bit.
+	*/
+	SCR_STORE_REL (swide, 1),
+		0,
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
+	/*
+	**	Restore the original DSA.
+	*/
+	SCR_LOAD_ABS (dsa, 4),
+		PADDRH (saved_dsa),
+}/*--------------------------< SWIDE_FIN_32 >-----------------------*/,{
+	/*
+	**	For 32 bit chip, the following SCRIPTS 
+	**	instruction is patched with a JUMP to dispatcher.
+	**	(Look into the C code).
+	*/
+	SCR_LOAD_ABS (drs, 4),
+		PADDRH (saved_drs),
+	/*
+	**	64 bit chip only.
+	**	If PM handling from SCRIPTS, we are just 
+	**	a helper for the C code, so jump to 
+	**	dispatcher now.
+	*/
+	SCR_FROM_REG (ccntl0),
+		0,
+	SCR_JUMP ^ IFFALSE (MASK (ENPMJ, ENPMJ)),
+		PADDR (dispatch),
+	/*
+	**	64 bit chip with hardware PM handling enabled.
+	**
+	**	Since we are paranoid:), we donnot want 
+	**	a SWIDE followed by a CHMOV(1) to lead to 
+	**	a CHMOV(0) in our PM context.
+	**	We check against such a condition.
+	**	Also does the C code.
+	*/
+	SCR_FROM_REG (rbc),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	SCR_FROM_REG (rbc1),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	SCR_FROM_REG (rbc2),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	/*
+	**	If we are there, RBC(0..23) is zero, 
+	**	and we just have to load the current 
+	**	DATA SCRIPTS address (register TEMP) 
+	**	with the IA and go to dispatch.
+	**	No PM context is needed.
+	*/
+	SCR_STORE_ABS (ia, 4),
+		PADDRH (scratch),
+	SCR_LOAD_ABS (temp, 4),
+		PADDRH (scratch),
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< ZERO >------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH >---------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH1 >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< PM0_DATA_ADDR >---------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< PM1_DATA_ADDR >---------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SAVED_DSA >-------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SAVED_DRS >-------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< DONE_POS >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< STARTPOS >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< TARGTBL >---------------------*/,{
+	SCR_DATA_ZERO,
+
+
+/*
+** We may use MEMORY MOVE instructions to load the on chip-RAM,
+** if it happens that mapping PCI memory is not possible.
+** But writing the RAM from the CPU is the preferred method, 
+** since PCI 2.2 seems to disallow PCI self-mastering.
+*/
+
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+
+}/*-------------------------< START_RAM >-------------------*/,{
+	/*
+	**	Load the script into on-chip RAM, 
+	**	and jump to start point.
+	*/
+	SCR_COPY (sizeof (struct script)),
+}/*-------------------------< SCRIPT0_BA >--------------------*/,{
+		0,
+		PADDR (start),
+	SCR_JUMP,
+		PADDR (init),
+
+}/*-------------------------< START_RAM64 >--------------------*/,{
+	/*
+	**	Load the RAM and start for 64 bit PCI (895A,896).
+	**	Both scripts (script and scripth) are loaded into 
+	**	the RAM which is 8K (4K for 825A/875/895).
+	**	We also need to load some 32-63 bit segments 
+	**	address of the SCRIPTS processor.
+	**	LOAD/STORE ABSOLUTE always refers to on-chip RAM 
+	**	in our implementation. The main memory is 
+	**	accessed using LOAD/STORE DSA RELATIVE.
+	*/
+	SCR_LOAD_REL (mmws, 4),
+		offsetof (struct ncb, scr_ram_seg),
+	SCR_COPY (sizeof(struct script)),
+}/*-------------------------< SCRIPT0_BA64 >--------------------*/,{
+		0,
+		PADDR (start),
+	SCR_COPY (sizeof(struct scripth)),
 }/*-------------------------< SCRIPTH0_BA64 >--------------------*/,{
 		0,
 		PADDRH  (start64),
@@ -3768,6 +4178,9 @@
 		PADDRH (start64),
 }/*-------------------------< RAM_SEG64 >--------------------*/,{
 		0,
+
+#endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
+
 }/*-------------------------< SNOOPTEST >-------------------*/,{
 	/*
 	**	Read the variable.
@@ -3801,50 +4214,17 @@
 	int	i;
 	ncrcmd	*p;
 
-#if	MAX_SCATTERH != 0
-	p = scrh->hdata_in;
-	for (i=0; i<MAX_SCATTERH; i++) {
-#if	SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
-		*p++ =offsetof (struct dsb, data[i]);
-	};
-	assert ((u_long)p == (u_long)&scrh->hdata_in + sizeof (scrh->hdata_in));
-#endif
-
 	p = scr->data_in;
-	for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
-#if	SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+	for (i=0; i<MAX_SCATTER; i++) {
+		*p++ =SCR_CHMOV_TBL ^ SCR_DATA_IN;
 		*p++ =offsetof (struct dsb, data[i]);
 	};
-	assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
 
-#if	MAX_SCATTERH != 0
-	p = scrh->hdata_out;
-	for (i=0; i<MAX_SCATTERH; i++) {
-#if	SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
-		*p++ =offsetof (struct dsb, data[i]);
-	};
-	assert ((u_long)p==(u_long)&scrh->hdata_out + sizeof (scrh->hdata_out));
-#endif
+	assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
 
 	p = scr->data_out;
-	for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
-#if SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+	for (i=0; i<MAX_SCATTER; i++) {
+		*p++ =SCR_CHMOV_TBL ^ SCR_DATA_OUT;
 		*p++ =offsetof (struct dsb, data[i]);
 	};
 
@@ -3860,7 +4240,8 @@
 **==========================================================
 */
 
-static void __init ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len)
+static void __init 
+ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len)
 {
 	ncrcmd  opcode, new, old, tmp1, tmp2;
 	ncrcmd	*start, *end;
@@ -3950,11 +4331,22 @@
 
 		case 0x0:
 			/*
-			**	MOVE (absolute address)
+			**	MOVE/CHMOV (absolute address)
 			*/
+			if (!(np->features & FE_WIDE))
+				dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
 			relocs = 1;
 			break;
 
+		case 0x1:
+			/*
+			**	MOVE/CHMOV (table indirect)
+			*/
+			if (!(np->features & FE_WIDE))
+				dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
+			relocs = 0;
+			break;
+
 		case 0x8:
 			/*
 			**	JUMP / CALL
@@ -4016,6 +4408,7 @@
 				}
 				/* fall through */
 			default:
+				new = 0;	/* For 'cc' not to complain */
 				panic("ncr_script_copy_and_bind: "
 				      "weird relocation %x\n", old);
 				break;
@@ -4083,9 +4476,16 @@
 **	Prepare io register values used by ncr_init() according 
 **	to selected and supported features.
 **
-**	NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 
-**	transfers. 32,64,128 are only supported by 825A, 875, 895 
-**	and 896 chips.
+**	NCR/SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64,
+**	128 transfers. All chips support at least 16 transfers bursts. 
+**	The 825A, 875 and 895 chips support bursts of up to 128 
+**	transfers and the 895A and 896 support bursts of up to 64 
+**	transfers. All other chips support up to 16 transfers bursts.
+**
+**	For PCI 32 bit data transfers each transfer is a DWORD (4 bytes).
+**	It is a QUADWORD (8 bytes) for PCI 64 bit data transfers.
+**	Only the 896 is able to perform 64 bit data transfers.
+**
 **	We use log base 2 (burst length) as internal code, with 
 **	value 0 meaning "burst disabled".
 **
@@ -4128,8 +4528,8 @@
 **	Get target set-up from Symbios format NVRAM.
 */
 
-static void __init
-	ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
+static void __init 
+ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
 {
 	tcb_p tp = &np->target[target];
 	Symbios_target *tn = &nvram->target[target];
@@ -4137,7 +4537,7 @@
 	tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255;
 	tp->usrwide = tn->bus_width == 0x10 ? 1 : 0;
 	tp->usrtags =
-		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SCSI_NCR_MAX_TAGS : 0;
+		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0;
 
 	if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
 		tp->usrflag |= UF_NODISC;
@@ -4150,7 +4550,7 @@
 */
 
 static void __init
-	ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
+ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
 {
 	tcb_p tp = &np->target[target];
 	struct Tekram_target *tn = &nvram->target[target];
@@ -4261,7 +4661,7 @@
 	np->maxsync = period > 2540 ? 254 : period / 10;
 
 	/*
-	**	64 bit (53C896) ?
+	**	64 bit (53C895A or 53C896) ?
 	*/
 	if (np->features & FE_64BIT)
 #if BITS_PER_LONG > 32
@@ -4271,8 +4671,8 @@
 #endif
 
 	/*
-	**	Phase mismatch handled by SCRIPTS (53C896) ?
-	*/
+	**	Phase mismatch handled by SCRIPTS (53C895A or 53C896) ?
+  	*/
 	if (np->features & FE_NOPM)
 		np->rv_ccntl0	|= (ENPMJ);
 
@@ -4383,28 +4783,50 @@
 	ncr_init_burst(np, burst_max);
 
 	/*
-	**	Set differential mode and LED support.
-	**	Ignore these features for boards known to use a 
-	**	specific GPIO wiring (Tekram only for now) and 
-	**	for the 896 that drives the LED directly.
-	**	Probe initial setting of GPREG and GPCNTL for 
-	**	other ones.
-	*/
-	if (!nvram || nvram->type != SCSI_NCR_TEKRAM_NVRAM) {
+	**	Set SCSI BUS mode.
+	**
+	**	- ULTRA2 chips (895/895A/896) report the current 
+	**	  BUS mode through the STEST4 IO register.
+	**	- For previous generation chips (825/825A/875), 
+	**	  user has to tell us how to check against HVD, 
+	**	  since a 100% safe algorithm is not possible.
+	*/
+	np->scsi_mode = SMODE_SE;
+	if	(np->features & FE_ULTRA2)
+		np->scsi_mode = (np->sv_stest4 & SMODE);
+	else if	(np->features & FE_DIFF) {
 		switch(driver_setup.diff_support) {
-		case 3:
+		case 4:	/* Trust previous settings if present, then GPIO3 */
+			if (np->sv_scntl3) {
+				if (np->sv_stest2 & 0x20)
+					np->scsi_mode = SMODE_HVD;
+				break;
+			}
+		case 3:	/* SYMBIOS controllers report HVD through GPIO3 */
+			if (nvram && nvram->type != SCSI_NCR_SYMBIOS_NVRAM)
+				break;
 			if (INB(nc_gpreg) & 0x08)
+				break;
+		case 2:	/* Set HVD unconditionally */
+			np->scsi_mode = SMODE_HVD;
+		case 1:	/* Trust previous settings for HVD */
+			if (np->sv_stest2 & 0x20)
+				np->scsi_mode = SMODE_HVD;
 			break;
-		case 2:
-			np->rv_stest2	|= 0x20;
-			break;
-		case 1:
-			np->rv_stest2	|= (np->sv_stest2 & 0x20);
-			break;
-		default:
+		default:/* Don't care about HVD */	
 			break;
 		}
 	}
+	if (np->scsi_mode == SMODE_HVD)
+		np->rv_stest2 |= 0x20;
+
+	/*
+	**	Set LED support from SCRIPTS.
+	**	Ignore this feature for boards known to use a 
+	**	specific GPIO wiring and for the 895A or 896 
+	**	that drive the LED directly.
+	**	Also probe initial setting of GPIO0 as output.
+	*/
 	if ((driver_setup.led_pin ||
 	     (nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) &&
 	    !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
@@ -4457,7 +4879,7 @@
 #endif
 			tp->usrsync = driver_setup.default_sync;
 			tp->usrwide = driver_setup.max_wide;
-			tp->usrtags = SCSI_NCR_MAX_TAGS;
+			tp->usrtags = MAX_TAGS;
 			if (!driver_setup.disconnection)
 				np->target[i].usrflag = UF_NODISC;
 		}
@@ -4587,7 +5009,8 @@
 **	start the timer daemon.
 */
 
-static int __init ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
+static int __init 
+ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
 {
         struct host_data *host_data;
 	ncb_p np = 0;
@@ -4758,6 +5181,19 @@
 	(void) ncr_prepare_setting(np, nvram);
 
 	/*
+	**	Check the PCI clock frequency.
+	**	Must be done after prepare_setting since it 
+	**	destroys STEST1 that is used to probe for 
+	**	the clock doubler.
+	*/
+	i = (int) ncr_getpciclock(np);
+	if (i > 37000) {
+		printk(KERN_ERR "%s: PCI clock seems too high (%u KHz).\n",
+		       ncr_name(np), i);
+		goto attach_error;
+	}
+
+	/*
 	**	Patch script to physical addresses
 	*/
 	ncr_script_fill (&script0, &scripth0);
@@ -4769,17 +5205,36 @@
 	if (np->base2_ba) {
 		np->p_script	= pcivtobus(np->base2_ba);
 		if (np->features & FE_RAM8K) {
+			np->base2_ws = 8192;
 			np->p_scripth = np->p_script + 4096;
 #if BITS_PER_LONG > 32
 			np->scr_ram_seg = cpu_to_scr(np->base2_ba >> 32);
 #endif
 		}
+		else
+			np->base2_ws = 4096;
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+		np->base2_va = remap_pci_mem(np->base2_ba, np->base2_ws);
+		if (!np->base2_va) {
+			printk(KERN_ERR "%s: can't map PCI MEMORY region\n",
+			       ncr_name(np));
+			goto attach_error;
+		}
+#endif
 	}
 
 	ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script));
 	ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
 
 	/*
+	**	If not 64 bit chip, patch some places in SCRIPTS.
+	*/
+	if (!(np->features & FE_64BIT)) {
+		np->scripth0->swide_fin_32[0] = cpu_to_scr(SCR_JUMP);
+		np->scripth0->swide_fin_32[1] = 
+				cpu_to_scr(NCB_SCRIPT_PHYS(np, dispatch));
+	}
+	/*
 	**	Patch some variables in SCRIPTS
 	*/
 	np->scripth0->pm0_data_addr[0] = 
@@ -4787,11 +5242,12 @@
 	np->scripth0->pm1_data_addr[0] = 
 			cpu_to_scr(NCB_SCRIPT_PHYS(np, pm1_data));
 
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 	np->scripth0->script0_ba[0]	= cpu_to_scr(vtobus(np->script0));
 	np->scripth0->script0_ba64[0]	= cpu_to_scr(vtobus(np->script0));
 	np->scripth0->scripth0_ba64[0]	= cpu_to_scr(vtobus(np->scripth0));
 	np->scripth0->ram_seg64[0]	= np->scr_ram_seg;
-
+#endif
 	/*
 	**	Prepare the idle and invalid task actions.
 	*/
@@ -4827,10 +5283,11 @@
 	/*
 	**	Prepare the target bus address array.
 	*/
-	np->script0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl));
+	np->scripth0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl));
 	for (i = 0 ; i < MAX_TARGET ; i++) {
 		np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i]));
 		np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl));
+		np->target[i].b_lun0   = cpu_to_scr(vtobus(&np->resel_badlun));
 	}
 
 	/*
@@ -4846,6 +5303,23 @@
 				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
 	}
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+	/*
+	**    If user does not want to use IMMEDIATE ARBITRATION
+	**    when we are reselected while attempting to arbitrate,
+	**    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
+	*/
+	if (!(driver_setup.iarb & 1))
+		np->script0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
+	/*
+	**    If user wants IARB to be set when we win arbitration 
+	**    and have other jobs, compute the max number of consecutive 
+	**    settings of IARB hint before we leave devices a chance to 
+	**    arbitrate for reselection.
+	*/
+	np->iarb_max = (driver_setup.iarb >> 4);
+#endif
+
 	/*
 	**	DEL 472 - 53C896 Rev 1 - Part Number 609-0393055 - ITEM 5.
 	*/
@@ -4890,14 +5364,20 @@
 
 	/*
 	**	Install the interrupt handler.
+	**	If we synchonize the C code with SCRIPTS on interrupt, 
+	**	we donnot want to share the INTR line at all.
 	*/
 	if (request_irq(device->slot.irq, sym53c8xx_intr,
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+			((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT),
+#else
 			((driver_setup.irqm & 0x10) ? 0 : SA_SHIRQ) |
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0)
 			((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT),
 #else
 			0,
 #endif
+#endif
 			NAME53C8XX, np)) {
 		printk(KERN_ERR "%s: request irq %d failure\n",
 			ncr_name(np), device->slot.irq);
@@ -4957,8 +5437,9 @@
 	**	and return success.
 	*/
 	instance->max_channel	= 0;
+	instance->this_id	= np->myaddr;
 	instance->max_id	= np->maxwide ? 16 : 8;
-	instance->max_lun	= SCSI_NCR_MAX_LUN;
+	instance->max_lun	= MAX_LUN;
 #ifndef NCR_IOMAPPED
 	instance->base		= (char *) np->reg;
 #endif
@@ -4967,6 +5448,9 @@
 	instance->io_port	= np->base_io;
 	instance->n_io_port	= np->base_ws;
 	instance->dma_channel	= 0;
+	instance->cmd_per_lun	= MAX_TAGS;
+	instance->can_queue	= (MAX_START-4);
+	
 	instance->select_queue_depths = sym53c8xx_select_queue_depths;
 
 	NCR_UNLOCK_NCB(np, flags);
@@ -5002,9 +5486,11 @@
 		free_irq(np->irq, np);
 	if (np->base_io)
 		release_region(np->base_io, np->base_ws);
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 	if (np->base_va)
 		unmap_pci_mem(np->base_va, np->base_ws);
+	if (np->base2_va)
+		unmap_pci_mem(np->base2_va, np->base2_ws);
 #endif
 	if (np->scripth0)
 		m_free(np->scripth0, sizeof(struct scripth), "SCRIPTH");
@@ -5026,13 +5512,19 @@
 	for (target = 0; target < MAX_TARGET ; target++) {
 		tp = &np->target[target];
 		for (lun = 0 ; lun < MAX_LUN ; lun++) {
-			lp = tp->lp[lun];
+			lp = ncr_lp(np, tp, lun);
 			if (!lp)
 				continue;
 			if (lp->tasktbl != &lp->tasktbl_0)
-				m_free(lp->tasktbl, 256, "TASKTBL");
+				m_free(lp->tasktbl, MAX_TASKS*4, "TASKTBL");
+			if (lp->cb_tags)
+				m_free(lp->cb_tags, MAX_TAGS, "CB_TAGS");
 			m_free(lp, sizeof(*lp), "LCB");
 		}
+#if MAX_LUN > 1
+		if (tp->lmp)
+			m_free(tp->lmp, MAX_LUN * sizeof(lcb_p), "LMP");
+#endif 
 	}
 
 	m_free(np, sizeof(*np), "NCB");
@@ -5074,6 +5566,81 @@
 	}
 }
 
+/*==========================================================
+**
+**
+**	Prepare the next negotiation message if needed.
+**
+**	Fill in the part of message buffer that contains the 
+**	negotiation and the nego_status field of the CCB.
+**	Returns the size of the message in bytes.
+**
+**
+**==========================================================
+*/
+
+static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr)
+{
+	tcb_p tp = &np->target[cp->target];
+	int msglen = 0;
+	int nego = 0;
+
+	if (tp->inq_done) {
+
+		/*
+		**	negotiate wide transfers ?
+		*/
+
+		if (!tp->widedone) {
+			if (tp->inq_byte7 & INQ7_WIDE16) {
+				nego = NS_WIDE;
+			} else
+				tp->widedone=1;
+		};
+
+		/*
+		**	negotiate synchronous transfers?
+		*/
+
+		if (!nego && !tp->period) {
+			if (tp->inq_byte7 & INQ7_SYNC) {
+				nego = NS_SYNC;
+			} else {
+				tp->period  =0xffff;
+				PRINT_TARGET(np, cp->target);
+				printk ("target did not report SYNC.\n");
+			};
+		};
+	};
+
+	switch (nego) {
+	case NS_SYNC:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 3;
+		msgptr[msglen++] = M_X_SYNC_REQ;
+		msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
+		msgptr[msglen++] = tp->maxoffs;
+		break;
+	case NS_WIDE:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 2;
+		msgptr[msglen++] = M_X_WIDE_REQ;
+		msgptr[msglen++] = tp->usrwide;
+		break;
+	};
+
+	cp->nego_status = nego;
+
+	if (nego) {
+		tp->nego_cp = cp;
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, nego == NS_WIDE ?
+					  "wide msgout":"sync_msgout", msgptr);
+		};
+	};
+
+	return msglen;
+}
 
 /*==========================================================
 **
@@ -5088,12 +5655,12 @@
 {
 /*	Scsi_Device        *device    = cmd->device; */
 	tcb_p tp                      = &np->target[cmd->target];
-	lcb_p lp		      = tp->lp[cmd->lun];
+	lcb_p lp		      = ncr_lp(np, tp, cmd->lun);
 	ccb_p cp;
 
 	int	segments;
-	u_char	nego, idmsg, *msgptr;
-	u_int  msglen;
+	u_char	idmsg, *msgptr;
+	u_int   msglen;
 	int	direction;
 	u_int32	lastp, goalp;
 
@@ -5138,9 +5705,10 @@
 	**
 	**----------------------------------------------------
 	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ &&
-		np->settle_time > jiffies + cmd->timeout_per_command - HZ) {
-		np->settle_time = jiffies + cmd->timeout_per_command - HZ;
+	if (np->settle_time && cmd->timeout_per_command >= HZ) {
+		u_long tlimit = ktime_get(cmd->timeout_per_command - HZ);
+		if (ktime_dif(np->settle_time, tlimit) > 0)
+			np->settle_time = tlimit;
 	}
 
         if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
@@ -5166,85 +5734,39 @@
 	cp->phys.num_disc = 0;
 #endif
 
-	/*---------------------------------------------------
+	/*----------------------------------------------------
 	**
-	**	negotiation required?
+	**	Build the identify / tag / sdtr message
 	**
-	**---------------------------------------------------
+	**----------------------------------------------------
 	*/
 
-	nego = 0;
+	idmsg = M_IDENTIFY | cp->lun;
+
+	if (cp ->tag != NO_TAG || (lp && !(tp->usrflag & UF_NODISC)))
+		idmsg |= 0x40;
+
+	msgptr = cp->scsi_smsg;
+	msglen = 0;
+	msgptr[msglen++] = idmsg;
 
-	if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done && lp) {
+	if (cp->tag != NO_TAG) {
+		char order = np->order;
 
 		/*
-		**	negotiate wide transfers ?
+		**	Force ordered tag if necessary to avoid timeouts 
+		**	and to preserve interactivity.
 		*/
-
-		if (!tp->widedone) {
-			if (tp->inq_byte7 & INQ7_WIDE16) {
-				nego = NS_WIDE;
-			} else
-				tp->widedone=1;
-		};
-
-		/*
-		**	negotiate synchronous transfers?
-		*/
-
-		if (!nego && !tp->period) {
-			if (tp->inq_byte7 & INQ7_SYNC) {
-				nego = NS_SYNC;
-			} else {
-				tp->period  =0xffff;
-				PRINT_TARGET(np, cp->target);
-				printk ("target did not report SYNC.\n");
-			};
-		};
-
-		/*
-		**	remember nego is pending for the target.
-		**	Avoid to start a nego for all queued commands 
-		**	when tagged command queuing is enabled.
-		*/
-
-		if (nego)
-			tp->nego_cp = cp;
-	};
-
-	/*----------------------------------------------------
-	**
-	**	Build the identify / tag / sdtr message
-	**
-	**----------------------------------------------------
-	*/
-
-	idmsg = M_IDENTIFY | cp->lun;
-
-	if (cp ->tag != NO_TAG || (lp && !(tp->usrflag & UF_NODISC)))
-		idmsg |= 0x40;
-
-	msgptr = cp->scsi_smsg;
-	msglen = 0;
-	msgptr[msglen++] = idmsg;
-
-	if (cp->tag != NO_TAG) {
-		char order = np->order;
-
-		/*
-		**	Force ordered tag if necessary to avoid timeouts 
-		**	and to preserve interactivity.
-		*/
-		if (lp && lp->tags_stime + (3*HZ) <= jiffies) {
-			if (lp->tags_smap) {
+		if (lp && ktime_exp(lp->tags_stime)) {
+			lp->tags_si = !(lp->tags_si);
+			if (lp->tags_sum[lp->tags_si]) {
 				order = M_ORDERED_TAG;
-				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ 
+				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>0){ 
 					PRINT_ADDR(cmd);
 					printk("ordered tag forced.\n");
 				}
 			}
-			lp->tags_stime = jiffies;
-			lp->tags_smap = lp->tags_umap;
+			lp->tags_stime = ktime_get(3*HZ);
 		}
 
 		if (order == 0) {
@@ -5263,41 +5785,19 @@
 		}
 		msgptr[msglen++] = order;
 		/*
-		**	Actual tags are numbered 1,3,5,..2*MAXTAGS+1,
-		**	since we may have to deal with devices that have 
-		**	problems with #TAG 0 or too great #TAG numbers.
+		**	For less than 128 tags, actual tags are numbered 
+		**	1,3,5,..2*MAXTAGS+1,since we may have to deal 
+		**	with devices that have problems with #TAG 0 or too 
+		**	great #TAG numbers. For more tags (up to 256), 
+		**	we use directly our tag number.
 		*/
+#if MAX_TASKS > (512/4)
+		msgptr[msglen++] = cp->tag;
+#else
 		msgptr[msglen++] = (cp->tag << 1) + 1;
+#endif
 	}
 
-	switch (nego) {
-	case NS_SYNC:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 3;
-		msgptr[msglen++] = M_X_SYNC_REQ;
-		msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
-		msgptr[msglen++] = tp->maxoffs;
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgout: ");
-			ncr_show_msg (&cp->scsi_smsg [msglen-5]);
-			printk (".\n");
-		};
-		break;
-	case NS_WIDE:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 2;
-		msgptr[msglen++] = M_X_WIDE_REQ;
-		msgptr[msglen++] = tp->usrwide;
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgout: ");
-			ncr_show_msg (&cp->scsi_smsg [msglen-4]);
-			printk (".\n");
-		};
-		break;
-	};
-
 	cp->host_flags	= 0;
 
 	/*----------------------------------------------------
@@ -5307,7 +5807,7 @@
 	**----------------------------------------------------
 	*/
 
-	segments = np->scatter (cp, cp->cmd);
+	cp->segments = segments = np->scatter (cp, cp->cmd);
 
 	if (segments < 0) {
 		ncr_free_ccb(np, cp);
@@ -5357,16 +5857,8 @@
 	*/
 	if (direction & XFER_OUT) {
 		goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
-#if	MAX_SCATTERH != 0
-		if (segments <= MAX_SCATTERL)
-			lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-		else {
-			lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
-			lastp -= (segments - MAX_SCATTERL) * (SCR_SG_SIZE*4);
-		}
-#else
 		lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-#endif
+
 		/*
 		**	If actual data direction is unknown, save pointers 
 		**	in header. The SCRIPTS will swap them to current 
@@ -5383,16 +5875,7 @@
 	*/
 	if (direction & XFER_IN) {
 		goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
-#if	MAX_SCATTERH != 0
-		if (segments <= MAX_SCATTERL)
-			lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-		else {
-			lastp = NCB_SCRIPTH_PHYS (np, hdata_in2);
-			lastp -= (segments - MAX_SCATTERL) * (SCR_SG_SIZE*4);
-		}
-#else
 		lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-#endif
 	}
 
 	/*
@@ -5411,8 +5894,26 @@
 	/*
 	**	Save the initial data pointer in order to be able 
 	**	to redo the command.
+	**	We also have to save the initial lastp, since it 
+	**	will be changed to DATA_IO if we don't know the data 
+	**	direction and the device completes the command with 
+	**	QUEUE FULL status (without entering the data phase).
 	*/
 	cp->startp = cp->phys.header.savep;
+	cp->lastp0 = cp->phys.header.lastp;
+
+	/*---------------------------------------------------
+	**
+	**	negotiation required?
+	**
+	**	(nego_status is filled by ncr_prepare_nego())
+	**
+	**---------------------------------------------------
+	*/
+
+	cp->nego_status = 0;
+	if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp)
+		msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
 
 	/*----------------------------------------------------
 	**
@@ -5439,24 +5940,30 @@
 	/*
 	**	message
 	*/
-	cp->phys.smsg.addr		= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
-	cp->phys.smsg.size		= cpu_to_scr(msglen);
+	cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
+	cp->phys.smsg.size	= cpu_to_scr(msglen);
 
 	/*
 	**	command
 	*/
-	cp->phys.cmd.addr		= cpu_to_scr(vtobus (&cmd->cmnd[0]));
-	cp->phys.cmd.size		= cpu_to_scr(cmd->cmd_len);
+	cp->phys.cmd.addr	= cpu_to_scr(vtobus (&cmd->cmnd[0]));
+	cp->phys.cmd.size	= cpu_to_scr(cmd->cmd_len);
 
 	/*
 	**	status
 	*/
-	cp->actualquirks		= tp->quirks;
-	cp->host_status			= nego ? HS_NEGOTIATE : HS_BUSY;
-	cp->scsi_status			= S_ILLEGAL;
+	cp->actualquirks	= tp->quirks;
+	cp->host_status		= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
+	cp->scsi_status		= S_ILLEGAL;
+	cp->xerr_status		= 0;
+	cp->phys.extra_bytes	= 0;
 
-	cp->xerr_status			= XE_OK;
-	cp->nego_status			= nego;
+	/*
+	**	extreme data pointer.
+	**	shall be positive, so -1 is lower than lowest.:)
+	*/
+	cp->ext_sg  = -1;
+	cp->ext_ofs = 0;
 
 	/*----------------------------------------------------
 	**
@@ -5469,17 +5976,10 @@
 	**	activate this job.
 	*/
 
-	/* Compute a time limit greater than the middle-level driver one */
-	if (cmd->timeout_per_command > 0)
-		cp->tlimit	= jiffies + cmd->timeout_per_command + HZ;
-	else
-		cp->tlimit	= jiffies + 86400 * HZ;/* No timeout=24 hours */
-
 	/*
 	**	insert next CCBs into start queue.
 	**	2 max at a time is enough to flush the CCB wait queue.
 	*/
-	cp->auto_sense = 0;
 	if (lp)
 		ncr_start_next_ccb(np, lp, 2);
 	else
@@ -5525,6 +6025,24 @@
 {
 	u_short	qidx;
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+	/*
+	**	If the previously queued CCB is not yet done, 
+	**	set the IARB hint. The SCRIPTS will go with IARB 
+	**	for this job when starting the previous one.
+	**	We leave devices a chance to win arbitration by 
+	**	not using more than 'iarb_max' consecutive 
+	**	immediate arbitrations.
+	*/
+	if (np->last_cp && np->iarb_count < np->iarb_max) {
+		np->last_cp->host_flags |= HF_HINT_IARB;
+		++np->iarb_count;
+	}
+	else
+		np->iarb_count = 0;
+	np->last_cp = cp;
+#endif
+	
 	/*
 	**	insert into start queue.
 	*/
@@ -5546,7 +6064,7 @@
 	**	Wake it up.
 	*/
 	MEMORY_BARRIER();
-	OUTB (nc_istat, SIGP);
+	OUTB (nc_istat, SIGP|np->istat_sem);
 }
 
 
@@ -5593,7 +6111,6 @@
 **
 **
 **	Start reset process.
-**	If reset in progress do nothing.
 **	The interrupt handler will reinitialize the chip.
 **	The timeout handler will wait for settle_time before 
 **	clearing it and so resuming command processing.
@@ -5603,17 +6120,15 @@
 */
 static void ncr_start_reset(ncb_p np)
 {
-	if (!np->settle_time) {
-		(void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay);
- 	}
- }
+	(void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay);
+}
  
 static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
 {
 	u_int32 term;
 	int retv = 0;
 
-	np->settle_time	= jiffies + settle_delay * HZ;
+	np->settle_time	= ktime_get(settle_delay * HZ);
 
 	if (bootverbose > 1)
 		printk("%s: resetting, "
@@ -5747,8 +6262,6 @@
 {
 /*	Scsi_Device        *device    = cmd->device; */
 	ccb_p cp;
-	int found;
-	int retv;
 
 /*
  * First, look for the scsi command in the waiting list
@@ -5762,58 +6275,41 @@
 /*
  * Then, look in the wakeup list
  */
-	for (found=0, cp=np->ccbc; cp; cp=cp->link_ccb) {
+	for (cp=np->ccbc; cp; cp=cp->link_ccb) {
 		/*
 		**	look for the ccb of this command.
 		*/
 		if (cp->host_status == HS_IDLE) continue;
-		if (cp->cmd == cmd) {
-			found = 1;
+		if (cp->cmd == cmd)
 			break;
-		}
 	}
 
-	if (!found) {
+	if (!cp) {
 		return SCSI_ABORT_NOT_RUNNING;
 	}
 
-	if (np->settle_time) {
-		return SCSI_ABORT_SNOOZE;
-	}
-
 	/*
-	**	If the CCB is active, patch schedule jumps for the 
-	**	script to abort the command.
+	**	Keep track we have to abort this job.
 	*/
+	cp->to_abort = 1;
 
-	cp->tlimit = 0;
-	switch(cp->host_status) {
-	case HS_BUSY:
-	case HS_NEGOTIATE:
-		printk ("%s: abort ccb=%p (cancel)\n", ncr_name (np), cp);
-			cp->phys.header.go.start =
-				cpu_to_scr(NCB_SCRIPTH_PHYS (np, cancel));
-		retv = SCSI_ABORT_PENDING;
-		break;
-	case HS_DISCONNECT:
-		cp->phys.header.go.restart =
-				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
-		retv = SCSI_ABORT_PENDING;
-		break;
-	default:
-		retv = SCSI_ABORT_NOT_RUNNING;
-		break;
-
-	}
+	/*
+	**	Tell the SCRIPTS processor to stop 
+	**	and synchronize with us.
+	*/
+	np->istat_sem = SEM;
 
 	/*
 	**      If there are no requests, the script
 	**      processor will sleep on SEL_WAIT_RESEL.
 	**      Let's wake it up, since it may have to work.
 	*/
-	OUTB (nc_istat, SIGP);
+	OUTB (nc_istat, SIGP|SEM);
 
-	return retv;
+	/*
+	**	Tell user we are working for him.
+	*/
+	return SCSI_ABORT_PENDING;
 }
 
 /*==========================================================
@@ -5917,7 +6413,7 @@
 	cmd = cp->cmd;
 	cp->cmd = NULL;
 	tp = &np->target[cp->target];
-	lp = tp->lp[cp->lun];
+	lp = ncr_lp(np, tp, cp->lun);
 
 	/*
 	**	We donnot queue more than 1 ccb per target 
@@ -5928,41 +6424,47 @@
 	if (cp == tp->nego_cp)
 		tp->nego_cp = 0;
 
+#ifdef SCSI_NCR_IARB_SUPPORT
 	/*
-	**	If auto-sense performed, change scsi status.
+	**	We just complete the last queued CCB.
+	**	Clear this info that is no more relevant.
 	*/
-	if (cp->auto_sense) {
-		cp->scsi_status = cp->auto_sense;
-	}
+	if (cp == np->last_cp)
+		np->last_cp = 0;
+#endif
 
 	/*
-	**	Check for parity errors.
+	**	If auto-sense performed, change scsi status, 
+	**	Otherwise, compute the residual.
 	*/
-
-	if (cp->host_flags & HF_PAR_ERR) {
-		PRINT_ADDR(cmd);
-		printk ("unrecovered SCSI parity error.\n");
-		if (cp->host_status==HS_COMPLETE)
-			cp->host_status = HS_FAIL;
+	if (cp->host_flags & HF_AUTO_SENSE) {
+		cp->scsi_status = cp->sv_scsi_status;
+		cp->xerr_status = cp->sv_xerr_status;
+	}
+	else {
+		cp->resid = 0;
+		if (cp->phys.header.lastp != cp->phys.header.goalp)
+			cp->resid = ncr_compute_residual(np, cp);
 	}
 
 	/*
 	**	Check for extended errors.
 	*/
 
-	if (cp->xerr_status != XE_OK) {
-		PRINT_ADDR(cmd);
-		switch (cp->xerr_status) {
-		case XE_EXTRA_DATA:
+	if (cp->xerr_status) {
+		if (cp->xerr_status & XE_PARITY_ERR) {
+			PRINT_ADDR(cp->cmd);
+			printk ("unrecovered SCSI parity error.\n");
+		}
+		if (cp->xerr_status & XE_EXTRA_DATA) {
+			PRINT_ADDR(cp->cmd);
 			printk ("extraneous data discarded.\n");
-			break;
-		case XE_BAD_PHASE:
+		}
+		if (cp->xerr_status & XE_BAD_PHASE) {
+			PRINT_ADDR(cp->cmd);
 			printk ("illegal scsi phase (4/5).\n");
-			break;
-		default:
-			printk ("extended error %d.\n", cp->xerr_status);
-			break;
 		}
+
 		if (cp->host_status==HS_COMPLETE)
 			cp->host_status = HS_FAIL;
 	}
@@ -5971,10 +6473,13 @@
 	**	Print out any error for debugging purpose.
 	*/
 	if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
-		if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD) {
+		if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD ||
+		    cp->resid) {
 			PRINT_ADDR(cmd);
-			printk ("ERROR: cmd=%x host_status=%x scsi_status=%x\n",
-				cmd->cmnd[0], cp->host_status, cp->scsi_status);
+			printk ("ERROR: cmd=%x host_status=%x scsi_status=%x "
+				"data_len=%d residual=%d\n",
+				cmd->cmnd[0], cp->host_status, cp->scsi_status,
+				cp->data_len, -cp->resid);
 		}
 	}
 
@@ -5992,13 +6497,6 @@
 		SetScsiResult(cmd, DID_OK, cp->scsi_status);
 
 		/*
-		**	@RESID@
-		**	Could dig out the correct value for resid,
-		**	but it would be quite complicated.
-		*/
-		/* if (cp->phys.header.lastp != cp->phys.header.goalp) */
-
-		/*
 		**	Allocate the lcb if not yet.
 		*/
 		if (!lp)
@@ -6038,12 +6536,8 @@
 		SetScsiResult(cmd, DID_OK, S_CHECK_COND);
 
 		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
-			u_char * p = (u_char*) & cmd->sense_buffer;
-			int i;
 			PRINT_ADDR(cmd);
-			printk ("sense data:");
-			for (i=0; i<14; i++) printk (" %x", *p++);
-			printk (".\n");
+			ncr_printl_hex("sense data:", cmd->sense_buffer, 14);
 		}
 
 	} else if ((cp->host_status == HS_COMPLETE)
@@ -6078,6 +6572,7 @@
 		SetScsiResult(cmd, DID_ABORT, cp->scsi_status);
 
 	} else {
+		int did_status;
 
 		/*
 		**  Other protocol messes
@@ -6086,7 +6581,11 @@
 		printk ("COMMAND FAILED (%x %x) @%p.\n",
 			cp->host_status, cp->scsi_status, cp);
 
-		SetScsiResult(cmd, DID_ERROR, cp->scsi_status);
+		did_status = DID_ERROR;
+		if (cp->xerr_status & XE_PARITY_ERR)
+			did_status = DID_PARITY;
+
+		SetScsiResult(cmd, did_status, cp->scsi_status);
 	}
 
 	/*
@@ -6094,12 +6593,9 @@
 	*/
 
 	if (tp->usrflag & UF_TRACE) {
-		u_char * p;
-		int i;
 		PRINT_ADDR(cmd);
 		printk (" CMD:");
-		p = (u_char*) &cmd->cmnd[0];
-		for (i=0; i<cmd->cmd_len; i++) printk (" %x", *p++);
+		ncr_print_hex(cmd->cmnd, cmd->cmd_len);
 
 		if (cp->host_status==HS_COMPLETE) {
 			switch (cp->scsi_status) {
@@ -6108,9 +6604,7 @@
 				break;
 			case S_CHECK_COND:
 				printk ("  SENSE:");
-				p = (u_char*) &cmd->sense_buffer;
-				for (i=0; i<14; i++)
-					printk (" %x", *p++);
+				ncr_print_hex(cmd->sense_buffer, 14);
 				break;
 			default:
 				printk ("  STAT: %x\n", cp->scsi_status);
@@ -6250,7 +6744,7 @@
 	**	Start at first entry.
 	*/
 	np->squeueput = 0;
-	np->script0->startpos[0] = cpu_to_scr(phys);
+	np->scripth0->startpos[0] = cpu_to_scr(phys);
 
 	/*
 	**	Clear Done Queue
@@ -6265,7 +6759,7 @@
 	/*
 	**	Start at first entry.
 	*/
-	np->script0->done_pos[0] = cpu_to_scr(phys);
+	np->scripth0->done_pos[0] = cpu_to_scr(phys);
 	np->dqueueget = 0;
 
 	/*
@@ -6313,7 +6807,7 @@
 		np->rv_ccntl0 |= DPR;
 
 	/*
-	**	If 64 bit (53C896) enable 40 bit address table 
+	**	If 64 bit (53C895A or 53C896) enable 40 bit address table 
 	**	indirect addressing for MOVE.
 	*/
 
@@ -6322,7 +6816,7 @@
 	}
 
 	/*
-	**	If phase mismatch handled by scripts (53C896),
+	**	If phase mismatch handled by scripts (53C895A or 53C896),
 	**	set PM jump addresses.
 	*/
 
@@ -6370,6 +6864,8 @@
 	for (i=0;i<MAX_TARGET;i++) {
 		tcb_p tp = &np->target[i];
 
+		tp->to_reset = 0;
+
 		tp->sval    = 0;
 		tp->wval    = np->rv_scntl3;
 
@@ -6390,21 +6886,41 @@
 	}
 
 	/*
-	**    Start script processor.
+	**    Download SCSI SCRIPTS to on-chip RAM if present,
+	**    and start script processor.
+	**    We do the download preferently from the CPU.
+	**    For platforms that may not support PCI memory mapping,
+	**    we use a simple SCRIPTS that performs MEMORY MOVEs.
 	*/
 	MEMORY_BARRIER();
 	if (np->base2_ba) {
 		if (bootverbose)
 			printk ("%s: Downloading SCSI SCRIPTS.\n",
 				ncr_name(np));
-		if (np->features & FE_RAM8K)
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+		if (np->base2_ws == 8192)
 			phys = NCB_SCRIPTH0_PHYS (np, start_ram64);
 		else
 			phys = NCB_SCRIPTH_PHYS (np, start_ram);
+#else
+		if (np->base2_ws == 8192) {
+			memcpy_to_pci(np->base2_va + 4096,
+					np->scripth0, sizeof(struct scripth));
+			OUTL (nc_mmws, np->scr_ram_seg);
+			OUTL (nc_mmrs, np->scr_ram_seg);
+			OUTL (nc_sfs,  np->scr_ram_seg);
+			phys = NCB_SCRIPTH_PHYS (np, start64);
+		}
+		else
+			phys = NCB_SCRIPT_PHYS (np, init);
+		memcpy_to_pci(np->base2_va, np->script0, sizeof(struct script));
+#endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
 	}
 	else
 		phys = NCB_SCRIPT_PHYS (np, init);
 
+	np->istat_sem = 0;
+
 	OUTL (nc_dsa, vtobus(np));
 	OUTL (nc_dsp, phys);
 }
@@ -6609,7 +7125,11 @@
 
 	/*
 	**	Bells and whistles   ;-)
+	**	Donnot announce negotiations due to auto-sense, 
+	**	unless user really want us to be verbose. :)
 	*/
+	if (bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE))
+		goto next;
 	PRINT_TARGET(np, target);
 	if (sxfer & 0x01f) {
 		unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
@@ -6634,7 +7154,7 @@
 			mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
 	} else
 		printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
-
+next:
 	/*
 	**	set actual value and sync_status
 	**	patch ALL ccbs of this target.
@@ -6705,8 +7225,8 @@
 static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln)
 {
 	tcb_p tp = &np->target[tn];
-	lcb_p lp = tp->lp[ln];
-	u_char   reqtags, maxdepth;
+	lcb_p lp = ncr_lp(np, tp, ln);
+	u_short reqtags, maxdepth;
 
 	/*
 	**	Just in case ...
@@ -6800,35 +7320,12 @@
 {
 	u_char t;
 	tcb_p tp;
+	int ln;
+	u_long size;
 
 	switch (np->user.cmd) {
-
 	case 0: return;
 
-	case UC_SETSYNC:
-		for (t=0; t<MAX_TARGET; t++) {
-			if (!((np->user.target>>t)&1)) continue;
-			tp = &np->target[t];
-			tp->usrsync = np->user.data;
-			ncr_negotiate (np, tp);
-		};
-		break;
-
-	case UC_SETTAGS:
-		for (t=0; t<MAX_TARGET; t++) {
-			int ln;
-			if (!((np->user.target>>t)&1)) continue;
-			np->target[t].usrtags = np->user.data;
-			for (ln = 0; ln < MAX_LUN; ln++) {
-				lcb_p lp = np->target[t].lp[ln];
-				if (!lp)
-					continue;
-				lp->maxtags = lp->numtags = np->user.data;
-				ncr_setup_tags (np, t, ln);
-			}
-		};
-		break;
-
 	case UC_SETDEBUG:
 #ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 		ncr_debug = np->user.data;
@@ -6843,31 +7340,73 @@
 		np->verbose = np->user.data;
 		break;
 
-	case UC_SETWIDE:
-		for (t=0; t<MAX_TARGET; t++) {
-			u_long size;
-			if (!((np->user.target>>t)&1)) continue;
-			tp = &np->target[t];
-			size = np->user.data;
-			if (size > np->maxwide) size=np->maxwide;
-			tp->usrwide = size;
-			ncr_negotiate (np, tp);
-		};
-		break;
-
-	case UC_SETFLAG:
-		for (t=0; t<MAX_TARGET; t++) {
-			if (!((np->user.target>>t)&1)) continue;
-			tp = &np->target[t];
-			tp->usrflag = np->user.data;
-		};
-		break;
-
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 	case UC_CLEARPROF:
 		bzero(&np->profile, sizeof(np->profile));
 		break;
 #endif
+	default:
+		/*
+		**	We assume that other commands apply to targets.
+		**	This should always be the case and avoid the below 
+		**	4 lines to be repeated 5 times.
+		*/
+		for (t = 0; t < MAX_TARGET; t++) {
+			if (!((np->user.target >> t) & 1))
+				continue;
+			tp = &np->target[t];
+
+			switch (np->user.cmd) {
+
+			case UC_SETSYNC:
+				tp->usrsync = np->user.data;
+				ncr_negotiate (np, tp);
+				break;
+
+			case UC_SETWIDE:
+				size = np->user.data;
+				if (size > np->maxwide)
+					size=np->maxwide;
+				tp->usrwide = size;
+				ncr_negotiate (np, tp);
+				break;
+
+			case UC_SETTAGS:
+				tp->usrtags = np->user.data;
+				for (ln = 0; ln < MAX_LUN; ln++) {
+					lcb_p lp;
+					lp = ncr_lp(np, tp, ln);
+					if (!lp)
+						continue;
+					lp->numtags = np->user.data;
+					lp->maxtags = lp->numtags;
+					ncr_setup_tags (np, t, ln);
+				}
+				break;
+
+			case UC_RESETDEV:
+				tp->to_reset = 1;
+				np->istat_sem = SEM;
+				OUTB (nc_istat, SIGP|SEM);
+				break;
+
+			case UC_CLEARDEV:
+				for (ln = 0; ln < MAX_LUN; ln++) {
+					lcb_p lp;
+					lp = ncr_lp(np, tp, ln);
+					if (lp)
+						lp->to_clear = 1;
+				}
+				np->istat_sem = SEM;
+				OUTB (nc_istat, SIGP|SEM);
+				break;
+
+			case UC_SETFLAG:
+				tp->usrflag = np->user.data;
+				break;
+			}
+		}
+		break;
 	}
 	np->user.cmd=0;
 }
@@ -6889,7 +7428,7 @@
 
 static void ncr_timeout (ncb_p np)
 {
-	u_long	thistime = jiffies;
+	u_long	thistime = ktime_get(0);
 
 	/*
 	**	If release process in progress, let's go
@@ -6902,7 +7441,11 @@
 		return;
 	}
 
-	np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL;
+#ifdef SCSI_NCR_PCIQ_BROKEN_INTR
+	np->timer.expires = ktime_get((HZ+9)/10);
+#else
+	np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
+#endif
 	add_timer(&np->timer);
 
 	/*
@@ -6926,7 +7469,19 @@
 		np->lasttime = thistime;
 	}
 
-#ifdef SCSI_NCR_BROKEN_INTR
+#ifdef SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+	/*
+	**	Some way-broken PCI bridges may lead to 
+	**	completions being lost when the clearing 
+	**	of the INTFLY flag by the CPU occurs 
+	**	concurrently with the chip raising this flag.
+	**	If this ever happen, lost completions will 
+	**	be reaped here.
+	*/
+	ncr_wakeup_done(np);
+#endif
+
+#ifdef SCSI_NCR_PCIQ_BROKEN_INTR
 	if (INB(nc_istat) & (INTF|SIP|DIP)) {
 
 		/*
@@ -6936,7 +7491,7 @@
 		ncr_exception (np);
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("}");
 	}
-#endif /* SCSI_NCR_BROKEN_INTR */
+#endif /* SCSI_NCR_PCIQ_BROKEN_INTR */
 }
 
 /*==========================================================
@@ -6963,7 +7518,7 @@
 **		dsp:	script adress (relative to start of script).
 **		dbc:	first word of script command.
 **
-**	First 16 register of the chip:
+**	First 24 register of the chip:
 **		r0..rf
 **
 **==========================================================
@@ -7012,7 +7567,7 @@
 	}
 
         printk ("%s: regdump:", ncr_name(np));
-        for (i=0; i<16;i++)
+        for (i=0; i<24;i++)
             printk (" %02x", (unsigned)INB_OFF(i));
         printk (".\n");
 }
@@ -7119,7 +7674,7 @@
 	**	with my 895 that unfortunately suffers of the MA int.).
 	*/
 	if (driver_setup.optimize & 1) {
-		OUTB(nc_istat, (INTF | SIGP));
+		OUTB(nc_istat, (INTF | SIGP | np->istat_sem));
 		if (ncr_wakeup_done (np)) {
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 			++np->profile.num_fly;
@@ -7131,10 +7686,17 @@
 
 	/*
 	**	interrupt on the fly ?
+	**
+	**	For bridges that donnot flush posted writes 
+	**	in the reverse direction on read, a dummy read 
+	**	may help not to miss completions.
 	*/
 	istat = INB (nc_istat);
 	if (istat & INTF) {
-		OUTB (nc_istat, (istat & SIGP) | INTF);
+		OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem);
+#ifdef SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+		istat = INB (nc_istat);		/* DUMMY READ */
+#endif
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
 		(void)ncr_wakeup_done (np);
 #ifdef SCSI_NCR_PROFILE_SUPPORT
@@ -7252,8 +7814,8 @@
 	**	Reset everything.
 	**=========================================================
 	*/
-	if (jiffies - np->regtime > 10*HZ) {
-		np->regtime = jiffies;
+	if (ktime_exp(np->regtime)) {
+		np->regtime = ktime_get(10*HZ);
 		for (i = 0; i<sizeof(np->regdump); i++)
 			((char*)&np->regdump)[i] = INB_OFF(i);
 		np->regdump.nc_dstat = dstat;
@@ -7315,17 +7877,9 @@
 {
 	u_int32	dsp	= INL (nc_dsp);
 	u_int32	dsa	= INL (nc_dsa);
-	u_char	scntl1	= INB (nc_scntl1);
 	ccb_p cp	= ncr_ccb_from_dsa(np, dsa);
 
 	/*
-	**	If we are connected to the SCSI BUS, we only 
-	**	can reset the BUS.
-	*/
-	if (scntl1 & ISCON)
-		goto reset_all;
-
-	/*
 	**	If we haven't been interrupted inside the SCRIPTS 
 	**	critical pathes, we can safely restart the SCRIPTS 
 	**	and trust the DSA value if it matches a CCB.
@@ -7334,6 +7888,8 @@
 	       dsp < NCB_SCRIPT_PHYS (np, getjob_end) + 1)) &&
 	    (!(dsp > NCB_SCRIPT_PHYS (np, ungetjob) &&
 	       dsp < NCB_SCRIPT_PHYS (np, reselect) + 1)) &&
+	    (!(dsp > NCB_SCRIPTH_PHYS (np, sel_for_abort) &&
+	       dsp < NCB_SCRIPTH_PHYS (np, sel_for_abort_1) + 1)) &&
 	    (!(dsp > NCB_SCRIPT_PHYS (np, done) &&
 	       dsp < NCB_SCRIPT_PHYS (np, done_end) + 1))) {
 		if (cp) {
@@ -7377,7 +7933,6 @@
 	if (DEBUG_FLAGS & DEBUG_TINY) printk ("T");
 
 	if (dsp == NCB_SCRIPT_PHYS (np, wf_sel_done) + 8 ||
-	    dsp == NCB_SCRIPTH_PHYS (np, wf_sel_done_no_atn) + 8 ||
 	    !(driver_setup.recovery & 1))
 		ncr_recover_scsi_int(np, HS_SEL_TIMEOUT);
 	else
@@ -7429,7 +7984,7 @@
 	**	Suspend command processing for 1 second and 
 	**	reinitialize all except the chip.
 	*/
-	np->settle_time	= jiffies + HZ;
+	np->settle_time	= ktime_get(1*HZ);
 	ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
 }
 
@@ -7455,8 +8010,8 @@
 **	  The chip will then interrupt with both PAR and MA 
 **	  conditions set.
 **
-**	- A phase mismatch occurs before the MOV finished 
-**	  and phase errors are to be handled by SCRIPTS (896).
+**	- A phase mismatch occurs before the MOV finished and 
+**	  phase errors are to be handled by SCRIPTS (895A or 896).
 **	  The chip will load the DSP with the phase mismatch 
 **	  JUMP address and interrupt the host processor.
 **
@@ -7472,6 +8027,7 @@
 	u_char	sbcl	= INB (nc_sbcl);
 	u_char	cmd	= dbc >> 24;
 	int phase	= cmd & 7;
+	ccb_p	cp	= ncr_ccb_from_dsa(np, dsa);
 
 	printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
 		ncr_name(np), hsts, dbc, sbcl);
@@ -7491,7 +8047,7 @@
 	**	If the nexus is not clearly identified, reset the bus.
 	**	We will try to do better later.
 	*/
-	if (!ncr_ccb_from_dsa(np, dsa))
+	if (!cp)
 		goto reset_all;
 
 	/*
@@ -7504,7 +8060,7 @@
 	/*
 	**	Keep track of the parity error.
 	*/
-	OUTONB (HF_PRT, HF_PAR_ERR);
+	cp->xerr_status |= XE_PARITY_ERR;
 
 	/*
 	**	Prepare the message to send to the device.
@@ -7528,7 +8084,7 @@
 		/* No phase mismatch occurred */
 		else {
 			OUTL (nc_temp, dsp);
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak));
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
 		}
 	}
 	else 
@@ -7590,8 +8146,9 @@
 
 	/*
 	**	Donnot take into account dma fifo and various buffers in 
-	**	DATA IN phase since the chip flushes everything before 
+	**	INPUT phase since the chip flushes everything before 
 	**	raising the MA interrupt for interrupted INPUT phases.
+	**	For DATA IN phase, we will check for the SWIDE later.
 	*/
 	if ((cmd & 7) != 1) {
 		u_int32 dfifo;
@@ -7633,7 +8190,7 @@
 		*/
 		OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* dma fifo  */
 		OUTB (nc_stest3, TE|CSF);		/* scsi fifo */
-	};
+	}
 
 	/*
 	**	log the information
@@ -7732,8 +8289,8 @@
 	**
 	**	Look at the PM_SAVE SCRIPT if you want to understand 
 	**	this stuff. The equivalent code is implemented in 
-	**	SCRIPTS for the 896 that is able to handle PM from 
-	**	the SCRIPTS processor.
+	**	SCRIPTS for the 895A and 896 that are able to handle 
+	**	PM from the SCRIPTS processor.
 	*/
 
 	hflags0 = INB (HF_PRT);
@@ -7770,6 +8327,53 @@
 	pm->sg.size = cpu_to_scr(rest);
 	pm->ret     = cpu_to_scr(nxtdsp);
 
+	/*
+	**	If we have a SWIDE,
+	**	- prepare the address to write the SWIDE from SCRIPTS,
+	**	- compute the SCRIPTS address to restart from,
+	**	- move current data pointer context by one byte.
+	*/
+	nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
+	if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) &&
+	    (INB (nc_scntl2) & WSR)) {
+		/*
+		**	Hmmm... The device may want to also ignore 
+		**	this residue but it must send immediately the
+		**	appropriate message. We snoop the SCSI BUS 
+		**	and will just throw away this message from 
+		**	SCRIPTS if the SWIDE is to be ignored.
+		*/
+		if ((INB (nc_sbcl) & 7) == 7 && 
+		    INB (nc_sbdl) == M_IGN_RESIDUE) {
+			nxtdsp = NCB_SCRIPT_PHYS (np, ign_i_w_r_msg);
+		}
+		/*
+		**	We must grab the SWIDE.
+		**	We will use some complex SCRIPTS for that.
+		*/
+		else {
+			OUTL (nc_scratcha, pm->sg.addr);
+			nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_32);
+			if (np->features & FE_64BIT) {
+				OUTB (nc_sbr, (pm->sg.size >> 24));
+				nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_64);
+			}
+			/*
+			**	Adjust our data pointer context.
+			*/
+			++pm->sg.addr;
+			--pm->sg.size;
+			/*
+			**	Hmmm... Could it be possible that a SWIDE that 
+			**	is followed by a 1 byte CHMOV would lead to 
+			**	a CHMOV(0). Anyway, we handle it by just 
+			**	skipping context that would attempt a CHMOV(0).
+			*/
+			if (!pm->sg.size)
+				newcmd = pm->ret;
+		}
+	}
+
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		PRINT_ADDR(cp->cmd);
 		printk ("PM %x %x %x / %x %x %x.\n",
@@ -7780,12 +8384,11 @@
 	}
 
 	/*
-	**	fake the return address (to the patch).
-	**	and restart script processor at dispatcher.
+	**	Restart the SCRIPTS processor.
 	*/
 
 	OUTL (nc_temp, newcmd);
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak));
+	OUTL (nc_dsp,  nxtdsp);
 	return;
 
 	/*
@@ -7889,6 +8492,10 @@
 **	requeue the CCB that failed in front of the LUN queue.
 **	I just hope this not to be performed too often. :)
 **
+**	If we are using IMMEDIATE ARBITRATION, we clear the 
+**	IARB hint for every commands we encounter in order not 
+**	to be stuck with a won arbitration and no job to queue 
+**	to a device.
 **----------------------------------------------------------
 */
 
@@ -7896,11 +8503,12 @@
 {
 	Scsi_Cmnd *cmd	= cp->cmd;
 	tcb_p tp	= &np->target[cp->target];
-	lcb_p lp	= tp->lp[cp->lun];
+	lcb_p lp	= ncr_lp(np, tp, cp->lun);
 	ccb_p		cp2;
 	int		busyccbs = 1;
 	u_int32		startp;
 	u_char		s_status = INB (SS_PRT);
+	int		msglen;
 
 	/*
 	**	Remove all CCBs queued to the chip for that LUN and put 
@@ -7923,6 +8531,11 @@
 				continue;
 			if (cp2->target != cp->target || cp2->lun != cp->lun)
 				continue;
+#ifdef SCSI_NCR_IARB_SUPPORT
+			cp2->host_flags &= ~HF_HINT_IARB;
+			if (cp2 == np->last_cp)
+				np->last_cp = 0;
+#endif
 			xpt_remque(&cp2->link_ccbq);
 			xpt_insque_head(&cp2->link_ccbq, &lp->wait_ccbq);
 			--lp->queuedccbs;
@@ -7935,11 +8548,21 @@
 		**	Requeue the interrupted CCB in front of 
 		**	the LUN CCB wait queue.
 		*/
+#ifdef SCSI_NCR_IARB_SUPPORT
+		cp->host_flags &= ~HF_HINT_IARB;
+		if (cp == np->last_cp)
+			np->last_cp = 0;
+#endif
 		xpt_remque(&cp->link_ccbq);
 		xpt_insque_head(&cp->link_ccbq, &lp->wait_ccbq);
 		--lp->queuedccbs;
 		cp->queued = 0;
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+		if (np->last_cp)
+			np->last_cp->host_flags &= ~HF_HINT_IARB;
+#endif
+
 		/*
 		**	Repair the startqueue if necessary.
 		*/
@@ -7992,10 +8615,13 @@
 		/*
 		**	Repair the offending CCB.
 		*/
-		cp->phys.header.savep = cp->startp;
-		cp->host_status = HS_BUSY;
-		cp->scsi_status = S_ILLEGAL;
-		cp->host_flags	&= HF_PM_TO_C;
+		cp->phys.header.savep	= cp->startp;
+		cp->phys.header.lastp	= cp->lastp0;
+		cp->host_status 	= HS_BUSY;
+		cp->scsi_status 	= S_ILLEGAL;
+		cp->xerr_status		= 0;
+		cp->phys.extra_bytes	= 0;
+		cp->host_flags		&= HF_PM_TO_C;
 
 		break;
 
@@ -8004,12 +8630,20 @@
 		/*
 		**	If we were requesting sense, give up.
 		*/
-		if (cp->auto_sense) {
+		if (cp->host_flags & HF_AUTO_SENSE) {
 			ncr_complete(np, cp);
 			break;
 		}
 
 		/*
+		**	Save SCSI status and extended error.
+		**	Compute the data residual now.
+		*/
+		cp->sv_scsi_status = cp->scsi_status;
+		cp->sv_xerr_status = cp->xerr_status;
+		cp->resid = ncr_compute_residual(np, cp);
+
+		/*
 		**	Device returned CHECK CONDITION status.
 		**	Prepare all needed data strutures for getting 
 		**	sense data.
@@ -8019,8 +8653,29 @@
 		**	identify message
 		*/
 		cp->scsi_smsg2[0]	= M_IDENTIFY | cp->lun;
+		msglen = 1;
+
+		/*
+		**	If we are currently using anything different from 
+		**	async. 8 bit data transfers with that target,
+		**	start a negotiation, since the device may want 
+		**	to report us a UNIT ATTENTION condition due to 
+		**	a cause we currently ignore, and we donnot want 
+		**	to be stuck with WIDE and/or SYNC data transfer.
+		**
+		**	cp->nego_status is filled by ncr_prepare_nego().
+		*/
+		ncr_negotiate(np, tp);
+		cp->nego_status = 0;
+		if ((tp->wval & EWS) || (tp->sval & 0x1f))
+			msglen +=
+			    ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]);
+
+		/*
+		**	Message table indirect structure.
+		*/
 		cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
-		cp->phys.smsg.size	= cpu_to_scr(1);
+		cp->phys.smsg.size	= cpu_to_scr(msglen);
 
 		/*
 		**	sense command
@@ -8038,6 +8693,7 @@
 		/*
 		**	sense data
 		*/
+		bzero(cmd->sense_buffer, sizeof(cmd->sense_buffer));
 		cp->phys.sense.addr	=
 				cpu_to_scr(vtobus (&cmd->sense_buffer[0]));
 		cp->phys.sense.size	=
@@ -8046,30 +8702,22 @@
 		/*
 		**	requeue the command.
 		*/
-		startp = cpu_to_scr(NCB_SCRIPTH_PHYS (np, sdata_in));
+		startp = NCB_SCRIPTH_PHYS (np, sdata_in);
 
-		cp->phys.header.savep	= startp;
-		cp->phys.header.goalp	= startp + 24;
-		cp->phys.header.lastp	= startp;
-		cp->phys.header.wgoalp	= startp + 24;
-		cp->phys.header.wlastp	= startp;
+		cp->phys.header.savep	= cpu_to_scr(startp);
+		cp->phys.header.goalp	= cpu_to_scr(startp + 16);
+		cp->phys.header.lastp	= cpu_to_scr(startp);
+		cp->phys.header.wgoalp	= cpu_to_scr(startp + 16);
+		cp->phys.header.wlastp	= cpu_to_scr(startp);
 
-		cp->host_status = HS_BUSY;
+		cp->host_status	= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
 		cp->scsi_status = S_ILLEGAL;
-		cp->host_flags	= 0;
-		cp->auto_sense	= s_status;
+		cp->host_flags	= HF_AUTO_SENSE;
 
 		cp->phys.header.go.start =
 			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
 
 		/*
-		**	Select without ATN for quirky devices.
-		*/
-		if (tp->quirks & QUIRK_NOMSG)
-			cp->phys.header.go.start =
-			cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn));
-
-		/*
 		**	If lp not yet allocated, requeue the command.
 		*/
 		if (!lp)
@@ -8086,107 +8734,755 @@
 	return;
 }
 
-
-/*==========================================================
-**
-**
-**      ncr chip exception handler for programmed interrupts.
-**
+/*----------------------------------------------------------
 **
-**==========================================================
+**	After a device has accepted some management message 
+**	as BUS DEVICE RESET, ABORT TASK, etc ..., or when 
+**	a device signals a UNIT ATTENTION condition, some 
+**	tasks are thrown away by the device. We are required 
+**	to reflect that on our tasks list since the device 
+**	will never complete these tasks.
+**
+**	This function completes all disconnected CCBs for a 
+**	given target that matches the following criteria:
+**	- lun=-1  means any logical UNIT otherwise a given one.
+**	- task=-1 means any task, otherwise a given one.
+**----------------------------------------------------------
 */
-
-static int ncr_show_msg (u_char * msg)
+static int ncr_clear_tasks(ncb_p np, u_char hsts, 
+			   int target, int lun, int task)
 {
-	u_char i;
-	printk ("%x",*msg);
-	if (*msg==M_EXTENDED) {
-		for (i=1;i<8;i++) {
-			if (i-1>msg[1]) break;
-			printk ("-%x",msg[i]);
-		};
-		return (i+1);
-	} else if ((*msg & 0xf0) == 0x20) {
-		printk ("-%x",msg[1]);
-		return (2);
-	};
-	return (1);
-}
+	int i = 0;
+	ccb_p cp;
 
+	for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+		if (cp->host_status != HS_DISCONNECT)
+			continue;
+		if (cp->target != target)
+			continue;
+		if (lun != -1 && cp->lun != lun)
+			continue;
+		if (task != -1 && cp->tag != NO_TAG && cp->scsi_smsg[2] != task)
+			continue;
+		cp->host_status = hsts;
+		cp->scsi_status = S_ILLEGAL;
+		ncr_complete(np, cp);
+		++i;
+	}
+	return i;
+}
 
-void ncr_int_sir (ncb_p np)
+/*==========================================================
+**
+**	ncr chip handler for TASKS recovery.
+**
+**==========================================================
+**
+**	We cannot safely abort a command, while the SCRIPTS 
+**	processor is running, since we just would be in race 
+**	with it.
+**
+**	As long as we have tasks to abort, we keep the SEM 
+**	bit set in the ISTAT. When this bit is set, the 
+**	SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED) 
+**	each time it enters the scheduler.
+**
+**	If we have to reset a target, clear tasks of a unit,
+**	or to perform the abort of a disconnected job, we 
+**	restart the SCRIPTS for selecting the target. Once 
+**	selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED).
+**	If it loses arbitration, the SCRIPTS will interrupt again 
+**	the next time it will enter its scheduler, and so on ...
+**
+**	On SIR_TARGET_SELECTED, we scan for the more 
+**	appropriate thing to do:
+**
+**	- If nothing, we just sent a M_ABORT message to the 
+**	  target to get rid of the useless SCSI bus ownership.
+**	  According to the specs, no tasks shall be affected.
+**	- If the target is to be reset, we send it a M_RESET 
+**	  message.
+**	- If a logical UNIT is to be cleared , we send the 
+**	  IDENTIFY(lun) + M_ABORT.
+**	- If an untagged task is to be aborted, we send the 
+**	  IDENTIFY(lun) + M_ABORT.
+**	- If a tagged task is to be aborted, we send the 
+**	  IDENTIFY(lun) + task attributes + M_ABORT_TAG.
+**
+**	Once our 'kiss of death' :) message has been accepted 
+**	by the target, the SCRIPTS interrupts again 
+**	(SIR_ABORT_SENT). On this interrupt, we complete 
+**	all the CCBs that should have been aborted by the 
+**	target according to our message.
+**	
+**----------------------------------------------------------
+*/
+static void ncr_sir_task_recovery(ncb_p np, int num)
 {
-	u_char scntl3;
-	u_char chg, ofs, per, fak, wide;
-	u_char num = INB (nc_dsps);
-	ccb_p	cp=0;
-	u_long	dsa    = INL (nc_dsa);
-	u_char	target = INB (nc_sdid) & 0x0f;
-	tcb_p	tp     = &np->target[target];
+	ccb_p cp;
+	tcb_p tp;
+	int target=-1, lun=-1, task;
+	int i, k;
+	u_char *p;
 
-	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
+	switch(num) {
+	/*
+	**	The SCRIPTS processor stopped before starting
+	**	the next command in order to allow us to perform 
+	**	some task recovery.
+	*/
+	case SIR_SCRIPT_STOPPED:
 
-	switch (num) {
-	case SIR_SEL_ATN_NO_MSG_OUT:
 		/*
-		**	The device didn't go to MSG OUT phase after having 
-		**	been selected with ATN. We donnot want to handle 
-		**	that.
+		**	Do we have any target to reset or unit to clear ?
 		*/
-		printk ("%s:%d: No MSG OUT phase after selection with ATN.\n",
-			ncr_name (np), target);
-		goto out_stuck;
-	case SIR_RESEL_NO_MSG_IN:
-	case SIR_RESEL_NO_IDENTIFY:
+		for (i = 0 ; i < MAX_TARGET ; i++) {
+			tp = &np->target[i];
+			if (tp->to_reset || (tp->l0p && tp->l0p->to_clear)) {
+				target = i;
+				break;
+			}
+			if (!tp->lmp)
+				continue;
+			for (k = 1 ; k < MAX_LUN ; k++) {
+				if (tp->lmp[k] && tp->lmp[k]->to_clear) {
+					target	= i;
+					break;
+				}
+			}
+			if (target != -1)
+				break;
+		}
+
 		/*
-		**	If devices reselecting without sending an IDENTIFY 
-		**	message still exist, this should help.
-		**	We just assume lun=0, 1 CCB, no tag.
+		**	If not, look at the CCB list for any 
+		**	disconnected CCB to be aborted.
 		*/
-		if (tp->lp[0]) { 
-			OUTL (nc_dsa, scr_to_cpu(tp->lp[0]->tasktbl[0]));
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go));
+		if (target == -1) {
+			for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+				if (cp->host_status != HS_DISCONNECT)
+					continue;
+				if (cp->to_abort) {
+					target = cp->target;
+					break;
+				}
+			}
+		}
+
+		/*
+		**	If some target is to be selected, 
+		**	prepare and start the selection.
+		*/
+		if (target != -1) {
+			tp = &np->target[target];
+			np->abrt_sel.sel_id	= target;
+			np->abrt_sel.sel_scntl3 = tp->wval;
+			np->abrt_sel.sel_sxfer  = tp->sval;
+			OUTL(nc_dsa, vtobus(np));
+			OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort));
 			return;
 		}
-	case SIR_RESEL_BAD_LUN:
-		np->msgout[0] = M_RESET;
-		goto out;
-	case SIR_RESEL_BAD_I_T_L:
-		np->msgout[0] = M_ABORT;
-		goto out;
-	case SIR_RESEL_BAD_I_T_L_Q:
-		np->msgout[0] = M_ABORT_TAG;
-		goto out;
-	case SIR_RESEL_ABORTED:
-		np->lastmsg = np->msgout[0];
-		np->msgout[0] = M_NOOP;
-		printk ("%s:%d: message %d sent on bad reselection.\n",
-			ncr_name (np), target, np->lastmsg);
-		goto out;
-	case SIR_MSG_OUT_DONE:
-		np->lastmsg = np->msgout[0];
-		np->msgout[0] = M_NOOP;
-		/* Should we really care of that */
-		if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR)
-			OUTOFFB (HF_PRT, HF_PAR_ERR);
-		goto out;
-	case SIR_BAD_STATUS:
-		cp = ncr_ccb_from_dsa(np, dsa);
-		if (!cp)
-			goto out;
-		ncr_sir_to_redo(np, num, cp);
-		return;
-	default:
+
 		/*
-		**	lookup the ccb
+		**	Nothing is to be selected, so we donnot need 
+		**	to synchronize with the SCRIPTS anymore.
+		**	Remove the SEM flag from the ISTAT.
+		*/
+		np->istat_sem = 0;
+		OUTB (nc_istat, SIGP);
+
+		/*
+		**	Now look at CCBs to abort that haven't started yet.
+		**	Remove all those CCBs from the start queue and 
+		**	complete them with appropriate status.
+		**	Btw, the SCRIPTS processor is still stopped, so 
+		**	we are not in race.
+		*/
+		for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+			if (cp->host_status != HS_BUSY &&
+			    cp->host_status != HS_NEGOTIATE)
+				continue;
+			if (!cp->to_abort)
+				continue;
+#ifdef SCSI_NCR_IARB_SUPPORT
+			/*
+			**    If we are using IMMEDIATE ARBITRATION, we donnot 
+			**    want to cancel the last queued CCB, since the 
+			**    SCRIPTS may have anticipated the selection.
+			*/
+			if (cp == np->last_cp) {
+				cp->to_abort = 0;
+				continue;
+			}
+#endif
+			/*
+			**	Compute index of next position in the start 
+			**	queue the SCRIPTS will schedule.
+			*/
+			i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
+
+			/*
+			**	Remove the job from the start queue.
+			*/
+			k = -1;
+			while (1) {
+				if (i == np->squeueput)
+					break;
+				if (k == -1) {		/* Not found yet */
+					if (cp == ncr_ccb_from_dsa(np,
+						     scr_to_cpu(np->squeue[i])))
+						k = i;	/* Found */
+				}
+				else {
+					/*
+					**    Once found, we have to move 
+					**    back all jobs by 1 position.
+					*/
+					np->squeue[k] = np->squeue[i];
+					k += 2;
+					if (k >= MAX_START*2)
+						k = 0;
+				}
+
+				i += 2;
+				if (i >= MAX_START*2)
+					i = 0;
+			}
+			assert(k != -1);
+			if (k != 1) {
+				np->squeue[k] = np->squeue[i]; /* Idle task */
+				cp->host_status = HS_ABORTED;
+				cp->scsi_status = S_ILLEGAL;
+				ncr_complete(np, cp);
+			}
+		}
+		break;
+	/*
+	**	The SCRIPTS processor has selected a target 
+	**	we may have some manual recovery to perform for.
+	*/
+	case SIR_TARGET_SELECTED:
+		target = (INB (nc_sdid) & 0xf);
+		tp = &np->target[target];
+
+		np->abrt_tbl.addr = vtobus(np->abrt_msg);
+
+		/*
+		**	If the target is to be reset, prepare a 
+		**	M_RESET message and clear the to_reset flag 
+		**	since we donnot expect this operation to fail.
 		*/
-		cp = ncr_ccb_from_dsa(np, dsa);
-		if (!cp)
-			goto out;
+		if (tp->to_reset) {
+			np->abrt_msg[0] = M_RESET;
+			np->abrt_tbl.size = 1;
+			tp->to_reset = 0;
+			break;
+		}
+
+		/*
+		**	Otherwise, look for some logical unit to be cleared.
+		*/
+		if (tp->l0p && tp->l0p->to_clear)
+			lun = 0;
+		else if (tp->lmp) {
+			for (k = 1 ; k < MAX_LUN ; k++) {
+				if (tp->lmp[k] && tp->lmp[k]->to_clear) {
+					lun = k;
+					break;
+				}
+			}
+		}
+
+		/*
+		**	If a logical unit is to be cleared, prepare 
+		**	an IDENTIFY(lun) + ABORT MESSAGE.
+		*/
+		if (lun != -1) {
+			lcb_p lp = ncr_lp(np, tp, lun);
+			lp->to_clear = 0; /* We donnot expect to fail here */
+			np->abrt_msg[0] = M_IDENTIFY | lun;
+			np->abrt_msg[1] = M_ABORT;
+			np->abrt_tbl.size = 2;
+			break;
+		}
+
+		/*
+		**	Otherwise, look for some disconnected job to 
+		**	abort for this target.
+		*/
+		for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+			if (cp->host_status != HS_DISCONNECT)
+				continue;
+			if (cp->target != target)
+				continue;
+			if (cp->to_abort)
+				break;
+		}
+
+		/*
+		**	If we have none, probably since the device has 
+		**	completed the command before we won abitration,
+		**	send a M_ABORT message without IDENTIFY.
+		**	According to the specs, the device must just 
+		**	disconnect the BUS and not abort any task.
+		*/
+		if (!cp) {
+			np->abrt_msg[0] = M_ABORT;
+			np->abrt_tbl.size = 1;
+			break;
+		}
+
+		/*
+		**	We have some task to abort.
+		**	Set the IDENTIFY(lun)
+		*/
+		np->abrt_msg[0] = M_IDENTIFY | cp->lun;
+
+		/*
+		**	If we want to abort an untagged command, we 
+		**	will send a IDENTIFY + M_ABORT.
+		**	Otherwise (tagged command), we will send 
+		**	a IDENTITFY + task attributes + ABORT TAG.
+		*/
+		if (cp->tag == NO_TAG) {
+			np->abrt_msg[1] = M_ABORT;
+			np->abrt_tbl.size = 2;
+		}
+		else {
+			np->abrt_msg[1] = cp->scsi_smsg[1];
+			np->abrt_msg[2] = cp->scsi_smsg[2];
+			np->abrt_msg[3] = M_ABORT_TAG;
+			np->abrt_tbl.size = 4;
+		}
+		cp->to_abort = 0; /* We donnot expect to fail here */
+		break;
+
+	/*
+	**	The target has accepted our message and switched 
+	**	to BUS FREE phase as we expected.
+	*/
+	case SIR_ABORT_SENT:
+		target = (INB (nc_sdid) & 0xf);
+		tp = &np->target[target];
+		
+		/*
+		**	If we didn't abort anything, leave here.
+		*/
+		if (np->abrt_msg[0] == M_ABORT)
+			break;
+
+		/*
+		**	If we sent a M_RESET, then a hardware reset has 
+		**	been performed by the target.
+		**	- Reset everything to async 8 bit
+		**	- Tell ourself to negotiate next time :-)
+		**	- Prepare to clear all disconnected CCBs for 
+		**	  this target from our task list (lun=task=-1)
+		*/
+		lun = -1;
+		task = -1;
+		if (np->abrt_msg[0] == M_RESET) {
+			tp->sval = 0;
+			tp->wval = np->rv_scntl3;
+			ncr_set_sync_wide_status(np, target);
+			ncr_negotiate(np, tp);
+		}
+
+		/*
+		**	Otherwise, check for the LUN and TASK(s) 
+		**	concerned by the cancelation.
+		**	If it is not ABORT_TAG then it is CLEAR_QUEUE 
+		**	or an ABORT message :-)
+		*/
+		else {
+			lun = np->abrt_msg[0] & 0x3f;
+			if (np->abrt_msg[1] == M_ABORT_TAG)
+				task = np->abrt_msg[2];
+		}
+
+		/*
+		**	Complete all the CCBs the device should have 
+		**	aborted due to our 'kiss of death' message.
+		*/
+		(void) ncr_clear_tasks(np, HS_ABORTED, target, lun, task);
+		break;
+
+	/*
+	**	We have performed a auto-sense that succeeded.
+	**	If the device reports a UNIT ATTENTION condition 
+	**	due to a RESET condition, we must complete all 
+	**	disconnect CCBs for this unit since the device 
+	**	shall have thrown them away.
+	**	Since I haven't time to guess what the specs are 
+	**	expecting for other UNIT ATTENTION conditions, I 
+	**	decided to only care about RESET conditions. :)
+	*/
+	case SIR_AUTO_SENSE_DONE:
+		cp = ncr_ccb_from_dsa(np, INL (nc_dsa));
+		p  = &cp->cmd->sense_buffer[0];
+
+		if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29)
+			break;
+		(void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1);
+		break;
+	}
+
+	/*
+	**	Print to the log the message we intend to send.
+	*/
+	if (num == SIR_TARGET_SELECTED) {
+		PRINT_TARGET(np, target);
+		ncr_printl_hex("control msgout:", np->abrt_msg,
+			      np->abrt_tbl.size);
+		np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size);
+	}
+
+	/*
+	**	Let the SCRIPTS processor continue.
+	*/
+	OUTONB (nc_dcntl, (STD|NOCOM));
+}
+
+
+/*==========================================================
+**
+**	Gérard's alchemy:) that deals with with the data 
+**	pointer for both MDP and the residual calculation.
+**
+**==========================================================
+**
+**	I didn't want to bloat the code by more than 200 
+**	lignes for the handling of both MDP and the residual.
+**	This has been achieved by using a data pointer 
+**	representation consisting in an index in the data 
+**	array (dp_sg) and a negative offset (dp_ofs) that 
+**	have the following meaning:
+**
+**	- dp_sg = MAX_SCATTER
+**	  we are at the end of the data script.
+**	- dp_sg < MAX_SCATTER
+**	  dp_sg points to the next entry of the scatter array 
+**	  we want to transfer.
+**	- dp_ofs < 0
+**	  dp_ofs represents the residual of bytes of the 
+**	  previous entry scatter entry we will send first.
+**	- dp_ofs = 0
+**	  no residual to send first.
+**
+**	The function ncr_evaluate_dp() accepts an arbitray 
+**	offset (basically from the MDP message) and returns 
+**	the corresponding values of dp_sg and dp_ofs.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_evaluate_dp(ncb_p np, ccb_p cp, u_int32 scr, int *ofs)
+{
+	u_int32	dp_scr;
+	int	dp_ofs, dp_sg, dp_sgmin;
+	int	tmp;
+	struct pm_ctx *pm;
+
+	/*
+	**	Compute the resulted data pointer in term of a script 
+	**	address within some DATA script and a signed byte offset.
+	*/
+	dp_scr = scr;
+	dp_ofs = *ofs;
+	if	(dp_scr == NCB_SCRIPT_PHYS (np, pm0_data))
+		pm = &cp->phys.pm0;
+	else if (dp_scr == NCB_SCRIPT_PHYS (np, pm1_data))
+		pm = &cp->phys.pm1;
+	else
+		pm = 0;
+
+	if (pm) {
+		dp_scr  = pm->ret;
+		dp_ofs -= pm->sg.size;
+	}
+
+	/*
+	**	Deduce the index of the sg entry.
+	**	Keep track of the index of the first valid entry.
+	**	If result is dp_sg = MAX_SCATTER, then we are at the 
+	**	end of the data.
+	*/
+	tmp = scr_to_cpu(cp->phys.header.goalp);
+	dp_sg = MAX_SCATTER - (tmp - 8 - (int)dp_scr) / (SCR_SG_SIZE*4);
+	dp_sgmin = MAX_SCATTER - cp->segments;
+
+	/*
+	**	Move to the sg entry the data pointer belongs to.
+	**
+	**	If we are inside the data area, we expect result to be:
+	**
+	**	Either,
+	**	    dp_ofs = 0 and dp_sg is the index of the sg entry
+	**	    the data pointer belongs to (or the end of the data)
+	**	Or,
+	**	    dp_ofs < 0 and dp_sg is the index of the sg entry 
+	**	    the data pointer belongs to + 1.
+	*/
+	if (dp_ofs < 0) {
+		int n;
+		while (dp_sg > dp_sgmin) {
+			--dp_sg;
+			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+			n = dp_ofs + (tmp & 0xffffff);
+			if (n > 0) {
+				++dp_sg;
+				break;
+			}
+			dp_ofs = n;
+		}
+	}
+	else if (dp_ofs > 0) {
+		while (dp_sg < MAX_SCATTER) {
+			++dp_sg;
+			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+			dp_ofs -= (tmp & 0xffffff);
+			if (dp_ofs <= 0)
+				break;
+		}
+	}
+
+	/*
+	**	Make sure the data pointer is inside the data area.
+	**	If not, return some error.
+	*/
+	if	(dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0))
+		goto out_err;
+	else if	(dp_sg > MAX_SCATTER || (dp_sg == MAX_SCATTER && dp_ofs > 0))
+		goto out_err;
+
+	/*
+	**	Save the extreme pointer if needed.
+	*/
+	if (dp_sg > cp->ext_sg ||
+            (dp_sg == cp->ext_sg && dp_ofs < cp->ext_ofs)) {
+		cp->ext_sg  = dp_sg;
+		cp->ext_ofs = dp_ofs;
+	}
+
+	/*
+	**	Return data.
+	*/
+	*ofs = dp_ofs;
+	return dp_sg;
+
+out_err:
+	return -1;
+}
+
+/*==========================================================
+**
+**	ncr chip handler for MODIFY DATA POINTER MESSAGE
+**
+**==========================================================
+**
+**	We also call this function on IGNORE WIDE RESIDUE 
+**	messages that do not match a SWIDE full condition.
+**	Btw, we assume in that situation that such a message 
+**	is equivalent to a MODIFY DATA POINTER (offset=-1).
+**
+**----------------------------------------------------------
+*/
+
+static void ncr_modify_dp(ncb_p np, tcb_p tp, ccb_p cp, int ofs)
+{
+	int dp_ofs	= ofs;
+	u_int32 dp_scr	= INL (nc_temp);
+	u_int32	dp_ret;
+	u_char	hflags;
+	int	dp_sg;
+	struct pm_ctx *pm;
+
+	/*
+	**	Not supported for auto_sense;
+	*/
+	if (cp->host_flags & HF_AUTO_SENSE)
+		goto out_reject;
+
+	/*
+	**	Apply our alchemy:) (see comments in ncr_evaluate_dp()), 
+	**	to the resulted data pointer.
+	*/
+	dp_sg = ncr_evaluate_dp(np, cp, dp_scr, &dp_ofs);
+	if (dp_sg < 0)
+		goto out_reject;
+
+	/*
+	**	And our alchemy:) allows to easily calculate the data 
+	**	script address we want to return for the next data phase.
+	*/
+	dp_ret = cpu_to_scr(cp->phys.header.goalp);
+	dp_ret = dp_ret - 8 - (MAX_SCATTER - dp_sg) * (SCR_SG_SIZE*4);
+
+	/*
+	**	If offset / scatter entry is zero we donnot need 
+	**	a context for the new current data pointer.
+	*/
+	if (dp_ofs == 0) {
+		dp_scr = dp_ret;
+		goto out_ok;
+	}
+
+	/*
+	**	Get a context for the new current data pointer.
+	*/
+	hflags = INB (HF_PRT);
+
+	if (hflags & HF_DP_SAVED)
+		hflags ^= HF_ACT_PM;
+
+	if (!(hflags & HF_ACT_PM)) {
+		pm  = &cp->phys.pm0;
+		dp_scr = NCB_SCRIPT_PHYS (np, pm0_data);
+	}
+	else {
+		pm = &cp->phys.pm1;
+		dp_scr = NCB_SCRIPT_PHYS (np, pm1_data);
+	}
+
+	hflags &= ~(HF_DP_SAVED);
+
+	OUTB (HF_PRT, hflags);
+
+	/*
+	**	Set up the new current data pointer.
+	**	ofs < 0 there, and for the next data phase, we 
+	**	want to transfer part of the data of the sg entry 
+	**	corresponding to index dp_sg-1 prior to returning 
+	**	to the main data script.
+	*/
+	pm->ret = cpu_to_scr(dp_ret);
+	pm->sg.addr = cp->phys.data[dp_sg-1].addr + dp_ofs;
+	pm->sg.size = cp->phys.data[dp_sg-1].size - dp_ofs;
+
+out_ok:
+	OUTL (nc_temp, dp_scr);
+	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+	return;
+
+out_reject:
+	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+}
+
+
+/*==========================================================
+**
+**	ncr chip calculation of the data residual.
+**
+**==========================================================
+**
+**	As I used to say, the requirement of data residual 
+**	in SCSI is broken, useless and cannot be achieved 
+**	without huge complexity.
+**	But most OSes and even the official CAM require it.
+**	When stupidity happens to be so widely spread inside 
+**	a community, it gets hard to convince.
+**
+**	Anyway, I don't care, since I am not going to use 
+**	any software that considers this data residual as 
+**	a relevant information. :)
+**	
+**----------------------------------------------------------
+*/
+
+static int ncr_compute_residual(ncb_p np, ccb_p cp)
+{
+	int dp_sg, dp_sgmin, resid, tmp;
+	int dp_ofs = 0;
+
+	/*
+	**	Should have been checked by the caller.
+	*/
+	if (cp->phys.header.lastp == cp->phys.header.goalp)
+		return 0;
+
+	/*
+	**	If the last data pointer is data_io (direction 
+	**	unknown), then no data transfer should have 
+	**	taken place.
+	*/
+	if (cp->phys.header.lastp == NCB_SCRIPTH_PHYS (np, data_io))
+		return -cp->data_len;
+
+	/*
+	**	If the device asked for more data than available, 
+	**	return a positive residual value.
+	*/
+	if (cp->phys.extra_bytes)
+		return scr_to_cpu(cp->phys.extra_bytes);
+
+	/*
+	**	Evaluate the pointer saved on message COMPLETE.
+	**	According to our alchemy:), the extreme data 
+	**	pointer will also be updated if needed.
+	**	On error, assume no data transferred (this may 
+	**	happen if the data direction is unknown).
+	*/
+	tmp = cpu_to_scr(cp->phys.header.lastp);
+	if (ncr_evaluate_dp(np, cp, tmp, &dp_ofs) < 0)
+		return -cp->data_len;
+
+	/*
+	**	We are now full comfortable in the computation 
+	**	of the data residual (2's complement).
+	*/
+	dp_sgmin = MAX_SCATTER - cp->segments;
+	resid = cp->ext_ofs;
+	for (dp_sg = cp->ext_sg; dp_sg < MAX_SCATTER; ++dp_sg) {
+		tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+		resid -= (tmp & 0xffffff);
 	}
 
-	switch (num) {
-/*-----------------------------------------------------------------------------
+	/*
+	**	Hopefully, the result is not too wrong.
+	*/
+	return resid;
+}
+
+/*==========================================================
+**
+**	Print out the containt of a SCSI message.
+**
+**==========================================================
+*/
+
+static int ncr_show_msg (u_char * msg)
+{
+	u_char i;
+	printk ("%x",*msg);
+	if (*msg==M_EXTENDED) {
+		for (i=1;i<8;i++) {
+			if (i-1>msg[1]) break;
+			printk ("-%x",msg[i]);
+		};
+		return (i+1);
+	} else if ((*msg & 0xf0) == 0x20) {
+		printk ("-%x",msg[1]);
+		return (2);
+	};
+	return (1);
+}
+
+static void ncr_print_msg (ccb_p cp, char *label, u_char *msg)
+{
+	if (cp)
+		PRINT_ADDR(cp->cmd);
+	if (label)
+		printk ("%s: ", label);
+
+	(void) ncr_show_msg (msg);
+	printk (".\n");
+}
+
+/*===================================================================
+**
+**	Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER.
+**
+**===================================================================
 **
 **	Was Sie schon immer ueber transfermode negotiation wissen wollten ...
 **
@@ -8199,8 +9495,8 @@
 **	The host status field is set to HS_NEGOTIATE to mark this
 **	situation.
 **
-**	If the target doesn't answer this message immidiately
-**	(as required by the standard), the SIR_NEGO_FAIL interrupt
+**	If the target doesn't answer this message immediately
+**	(as required by the standard), the SIR_NEGO_FAILED interrupt
 **	will be raised eventually.
 **	The handler removes the HS_NEGOTIATE status, and sets the
 **	negotiated value to the default (async / nowide).
@@ -8218,375 +9514,532 @@
 **
 **	If the target doesn't fetch the answer (no message out phase),
 **	we assume the negotiation has failed, and fall back to default
-**	settings.
+**	settings (SIR_NEGO_PROTO interrupt).
 **
 **	When we set the values, we adjust them in all ccbs belonging 
 **	to this target, in the controller's register, and in the "phys"
 **	field of the controller's struct ncb.
 **
-**	Possible cases:		   hs  sir   msg_in value  send   goto
-**	We try to negotiate:
-**	-> target doesnt't msgin   NEG FAIL  noop   defa.  -      dispatch
-**	-> target rejected our msg NEG FAIL  reject defa.  -      dispatch
-**	-> target answered  (ok)   NEG SYNC  sdtr   set    -      clrack
-**	-> target answered (!ok)   NEG SYNC  sdtr   defa.  REJ--->msg_bad
-**	-> target answered  (ok)   NEG WIDE  wdtr   set    -      clrack
-**	-> target answered (!ok)   NEG WIDE  wdtr   defa.  REJ--->msg_bad
-**	-> any other msgin	   NEG FAIL  noop   defa.  -      dispatch
-**
-**	Target tries to negotiate:
-**	-> incoming message	   --- SYNC  sdtr   set    SDTR   -
-**	-> incoming message	   --- WIDE  wdtr   set    WDTR   -
-**      We sent our answer:
-**	-> target doesn't msgout   --- PROTO ?      defa.  -      dispatch
-**
-**-----------------------------------------------------------------------------
+**---------------------------------------------------------------------
 */
 
-	case SIR_NEGO_FAILED:
-		/*-------------------------------------------------------
-		**
-		**	Negotiation failed.
-		**	Target doesn't send an answer message,
-		**	or target rejected our message.
-		**
-		**      Remove negotiation request.
-		**
-		**-------------------------------------------------------
-		*/
-		OUTB (HS_PRT, HS_BUSY);
-
-		/* fall through */
-
-	case SIR_NEGO_PROTO:
-		/*-------------------------------------------------------
-		**
-		**	Negotiation failed.
-		**	Target doesn't fetch the answer message.
-		**
-		**-------------------------------------------------------
-		*/
-
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("negotiation failed sir=%x status=%x.\n",
-				num, cp->nego_status);
-		};
-
-		/*
-		**	any error in negotiation:
-		**	fall back to default mode.
-		*/
-		switch (cp->nego_status) {
-
-		case NS_SYNC:
-			ncr_setsync (np, cp, 0, 0xe0);
-			break;
-
-		case NS_WIDE:
-			ncr_setwide (np, cp, 0, 0);
-			break;
-
-		};
-		np->msgin [0] = M_NOOP;
-		np->msgout[0] = M_NOOP;
-		cp->nego_status = 0;
-		break;
+/*==========================================================
+**
+**	ncr chip handler for SYNCHRONOUS DATA TRANSFER 
+**	REQUEST (SDTR) message.
+**
+**==========================================================
+**
+**	Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_sync_nego(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	u_char	scntl3;
+	u_char	chg, ofs, per, fak;
 
-	case SIR_NEGO_SYNC:
-		/*
-		**	Synchronous request message received.
-		*/
+	/*
+	**	Synchronous request message received.
+	*/
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgin: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		};
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "sync msg in", np->msgin);
+	};
 
-		/*
-		**	get requested values.
-		*/
+	/*
+	**	get requested values.
+	*/
 
-		chg = 0;
-		per = np->msgin[3];
-		ofs = np->msgin[4];
-		if (ofs==0) per=255;
+	chg = 0;
+	per = np->msgin[3];
+	ofs = np->msgin[4];
+	if (ofs==0) per=255;
 
-		/*
-		**      if target sends SDTR message,
-		**	      it CAN transfer synch.
-		*/
+	/*
+	**      if target sends SDTR message,
+	**	      it CAN transfer synch.
+	*/
 
-		if (ofs)
-			tp->inq_byte7 |= INQ7_SYNC;
+	if (ofs)
+		tp->inq_byte7 |= INQ7_SYNC;
 
-		/*
-		**	check values against driver limits.
-		*/
+	/*
+	**	check values against driver limits.
+	*/
 
-		if (per < np->minsync)
-			{chg = 1; per = np->minsync;}
-		if (per < tp->minsync)
-			{chg = 1; per = tp->minsync;}
-		if (ofs > tp->maxoffs)
-			{chg = 1; ofs = tp->maxoffs;}
+	if (per < np->minsync)
+		{chg = 1; per = np->minsync;}
+	if (per < tp->minsync)
+		{chg = 1; per = tp->minsync;}
+	if (ofs > tp->maxoffs)
+		{chg = 1; ofs = tp->maxoffs;}
 
-		/*
-		**	Check against controller limits.
-		*/
+	/*
+	**	Check against controller limits.
+	*/
+	fak	= 7;
+	scntl3	= 0;
+	if (ofs != 0) {
+		ncr_getsync(np, per, &fak, &scntl3);
+		if (fak > 7) {
+			chg = 1;
+			ofs = 0;
+		}
+	}
+	if (ofs == 0) {
 		fak	= 7;
+		per	= 0;
 		scntl3	= 0;
-		if (ofs != 0) {
-			ncr_getsync(np, per, &fak, &scntl3);
-			if (fak > 7) {
-				chg = 1;
-				ofs = 0;
-			}
-		}
-		if (ofs == 0) {
-			fak	= 7;
-			per	= 0;
-			scntl3	= 0;
-			tp->minsync = 0;
-		}
-
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
-				per, scntl3, ofs, fak, chg);
-		}
+		tp->minsync = 0;
+	}
 
-		if (INB (HS_PRT) == HS_NEGOTIATE) {
-			OUTB (HS_PRT, HS_BUSY);
-			switch (cp->nego_status) {
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		PRINT_ADDR(cp->cmd);
+		printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
+			per, scntl3, ofs, fak, chg);
+	}
 
-			case NS_SYNC:
+	if (INB (HS_PRT) == HS_NEGOTIATE) {
+		OUTB (HS_PRT, HS_BUSY);
+		switch (cp->nego_status) {
+		case NS_SYNC:
+			/*
+			**      This was an answer message
+			*/
+			if (chg) {
 				/*
-				**      This was an answer message
+				**	Answer wasn't acceptable.
 				*/
-				if (chg) {
-					/*
-					**	Answer wasn't acceptable.
-					*/
-					ncr_setsync (np, cp, 0, 0xe0);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
-				} else {
-					/*
-					**	Answer is ok.
-					*/
-					ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
-				};
-				return;
-
-			case NS_WIDE:
-				ncr_setwide (np, cp, 0, 0);
-				break;
+				ncr_setsync (np, cp, 0, 0xe0);
+				OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+			} else {
+				/*
+				**	Answer is ok.
+				*/
+				ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+				OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
 			};
+			return;
+
+		case NS_WIDE:
+			ncr_setwide (np, cp, 0, 0);
+			break;
 		};
+	};
 
-		/*
-		**	It was a request. Set value and
-		**      prepare an answer message
-		*/
+	/*
+	**	It was a request. Set value and
+	**      prepare an answer message
+	*/
 
-		ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+	ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
 
-		np->msgout[0] = M_EXTENDED;
-		np->msgout[1] = 3;
-		np->msgout[2] = M_X_SYNC_REQ;
-		np->msgout[3] = per;
-		np->msgout[4] = ofs;
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 3;
+	np->msgout[2] = M_X_SYNC_REQ;
+	np->msgout[3] = per;
+	np->msgout[4] = ofs;
 
-		cp->nego_status = NS_SYNC;
+	cp->nego_status = NS_SYNC;
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgout: ");
-			(void) ncr_show_msg (np->msgout);
-			printk (".\n");
-		}
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "sync msgout", np->msgout);
+	}
 
-		if (!ofs) {
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
-			return;
-		}
-		np->msgin [0] = M_NOOP;
+	np->msgin [0] = M_NOOP;
 
-		break;
+	if (!ofs)
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+	else
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sdtr_resp));
+}
 
-	case SIR_NEGO_WIDE:
-		/*
-		**	Wide request message received.
-		*/
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgin: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		};
+/*==========================================================
+**
+**	ncr chip handler for WIDE DATA TRANSFER REQUEST 
+**	(WDTR) message.
+**
+**==========================================================
+**
+**	Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_wide_nego(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	u_char	chg, wide;
 
-		/*
-		**	get requested values.
-		*/
+	/*
+	**	Wide request message received.
+	*/
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "wide msgin", np->msgin);
+	};
 
-		chg  = 0;
-		wide = np->msgin[3];
+	/*
+	**	get requested values.
+	*/
 
-		/*
-		**      if target sends WDTR message,
-		**	      it CAN transfer wide.
-		*/
+	chg  = 0;
+	wide = np->msgin[3];
 
-		if (wide)
-			tp->inq_byte7 |= INQ7_WIDE16;
+	/*
+	**      if target sends WDTR message,
+	**	      it CAN transfer wide.
+	*/
 
-		/*
-		**	check values against driver limits.
-		*/
+	if (wide)
+		tp->inq_byte7 |= INQ7_WIDE16;
 
-		if (wide > tp->usrwide)
-			{chg = 1; wide = tp->usrwide;}
+	/*
+	**	check values against driver limits.
+	*/
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide: wide=%d chg=%d.\n", wide, chg);
-		}
+	if (wide > tp->usrwide)
+		{chg = 1; wide = tp->usrwide;}
 
-		if (INB (HS_PRT) == HS_NEGOTIATE) {
-			OUTB (HS_PRT, HS_BUSY);
-			switch (cp->nego_status) {
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		PRINT_ADDR(cp->cmd);
+		printk ("wide: wide=%d chg=%d.\n", wide, chg);
+	}
 
-			case NS_WIDE:
+	if (INB (HS_PRT) == HS_NEGOTIATE) {
+		OUTB (HS_PRT, HS_BUSY);
+		switch (cp->nego_status) {
+		case NS_WIDE:
+			/*
+			**      This was an answer message
+			*/
+			if (chg) {
 				/*
-				**      This was an answer message
+				**	Answer wasn't acceptable.
 				*/
-				if (chg) {
-					/*
-					**	Answer wasn't acceptable.
-					*/
-					ncr_setwide (np, cp, 0, 1);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
-				} else {
-					/*
-					**	Answer is ok.
-					*/
-					ncr_setwide (np, cp, wide, 1);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
-				};
-				return;
-
-			case NS_SYNC:
-				ncr_setsync (np, cp, 0, 0xe0);
-				break;
+				ncr_setwide (np, cp, 0, 1);
+				OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+			} else {
+				/*
+				**	Answer is ok.
+				*/
+				ncr_setwide (np, cp, wide, 1);
+				OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
 			};
+			return;
+
+		case NS_SYNC:
+			ncr_setsync (np, cp, 0, 0xe0);
+			break;
 		};
+	};
 
-		/*
-		**	It was a request, set value and
-		**      prepare an answer message
-		*/
+	/*
+	**	It was a request, set value and
+	**      prepare an answer message
+	*/
 
-		ncr_setwide (np, cp, wide, 1);
+	ncr_setwide (np, cp, wide, 1);
 
-		np->msgout[0] = M_EXTENDED;
-		np->msgout[1] = 2;
-		np->msgout[2] = M_X_WIDE_REQ;
-		np->msgout[3] = wide;
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 2;
+	np->msgout[2] = M_X_WIDE_REQ;
+	np->msgout[3] = wide;
 
-		np->msgin [0] = M_NOOP;
+	np->msgin [0] = M_NOOP;
 
-		cp->nego_status = NS_WIDE;
+	cp->nego_status = NS_WIDE;
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgout: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		}
-		break;
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "wide msgout", np->msgout);
+	}
 
-/*--------------------------------------------------------------------
-**
-**	Processing of special messages
-**
-**--------------------------------------------------------------------
+	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, wdtr_resp));
+}
+
+/*
+**	Reset SYNC or WIDE to default settings.
+**	Called when a negotiation does not succeed either 
+**	on rejection or on protocol error.
 */
+static void ncr_nego_default(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	/*
+	**	any error in negotiation:
+	**	fall back to default mode.
+	*/
+	switch (cp->nego_status) {
 
-	case SIR_REJECT_RECEIVED:
-		/*-----------------------------------------------
-		**
-		**	We received a M_REJECT message.
-		**
-		**-----------------------------------------------
-		*/
+	case NS_SYNC:
+		ncr_setsync (np, cp, 0, 0xe0);
+		break;
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_REJECT received (%x:%x).\n",
-			(unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
+	case NS_WIDE:
+		ncr_setwide (np, cp, 0, 0);
 		break;
 
-	case SIR_REJECT_TO_SEND:
-		/*-----------------------------------------------
-		**
-		**	We received an unknown message
-		**
-		**-----------------------------------------------
-		*/
+	};
+	np->msgin [0] = M_NOOP;
+	np->msgout[0] = M_NOOP;
+	cp->nego_status = 0;
+}
+
+/*==========================================================
+**
+**	ncr chip handler for MESSAGE REJECT received for 
+**	a WIDE or SYNCHRONOUS negotiation.
+**
+**==========================================================
+**
+**	Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_nego_rejected(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	ncr_nego_default(np, tp, cp);
+	OUTB (HS_PRT, HS_BUSY);
+}
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_REJECT to send for ");
-		(void) ncr_show_msg (np->msgin);
-		printk (".\n");
-		np->msgout[0] = M_REJECT;
-		break;
 
-/*--------------------------------------------------------------------
+/*==========================================================
+**
+**
+**      ncr chip exception handler for programmed interrupts.
 **
-**	Processing of special messages
 **
-**--------------------------------------------------------------------
+**==========================================================
 */
 
-	case SIR_IGN_RESIDUE:
-		/*-----------------------------------------------
-		**
-		**	We received an IGNORE RESIDUE message,
-		**	which couldn't be handled by the script.
-		**
-		**-----------------------------------------------
-		*/
+void ncr_int_sir (ncb_p np)
+{
+	u_char	num	= INB (nc_dsps);
+	u_long	dsa	= INL (nc_dsa);
+	ccb_p	cp	= ncr_ccb_from_dsa(np, dsa);
+	u_char	target	= INB (nc_sdid) & 0x0f;
+	tcb_p	tp	= &np->target[target];
+	int	tmp;
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_IGN_RESIDUE received, but not yet implemented.\n");
-		break;
-#if 0
-	case SIR_MISSING_SAVE:
-		/*-----------------------------------------------
-		**
-		**	We received an DISCONNECT message,
-		**	but the datapointer wasn't saved before.
-		**
-		**-----------------------------------------------
-		*/
+	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_DISCONNECT received, but datapointer not saved: "
-			"data=%x save=%x goal=%x.\n",
-			(unsigned) INL (nc_temp),
-			(unsigned) scr_to_cpu(np->header.savep),
-			(unsigned) scr_to_cpu(np->header.goalp));
-		break;
+	switch (num) {
+	/*
+	**	See comments in the SCRIPTS code.
+	*/
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+	case SIR_DUMMY_INTERRUPT:
+		goto out;
 #endif
+	/*
+	**	The C code is currently trying to recover from something.
+	**	Typically, user want to abort some command.
+	*/
+	case SIR_SCRIPT_STOPPED:
+	case SIR_TARGET_SELECTED:
+	case SIR_ABORT_SENT:
+		ncr_sir_task_recovery(np, num);
+		return;
+	/*
+	**	The device didn't go to MSG OUT phase after having 
+	**	been selected with ATN. We donnot want to handle 
+	**	that.
+	*/
+	case SIR_SEL_ATN_NO_MSG_OUT:
+		printk ("%s:%d: No MSG OUT phase after selection with ATN.\n",
+			ncr_name (np), target);
+		goto out_stuck;
+	/*
+	**	The device didn't switch to MSG IN phase after 
+	**	having reseleted the initiator.
+	*/
+	case SIR_RESEL_NO_MSG_IN:
+	/*
+	**	After reselection, the device sent a message that wasn't 
+	**	an IDENTIFY.
+	*/
+	case SIR_RESEL_NO_IDENTIFY:
+		/*
+		**	If devices reselecting without sending an IDENTIFY 
+		**	message still exist, this should help.
+		**	We just assume lun=0, 1 CCB, no tag.
+		*/
+		if (tp->l0p) { 
+			OUTL (nc_dsa, scr_to_cpu(tp->l0p->tasktbl[0]));
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go));
+			return;
+		}
+	/*
+	**	The device reselected a LUN we donnot know of.
+	*/
+	case SIR_RESEL_BAD_LUN:
+		np->msgout[0] = M_RESET;
+		goto out;
+	/*
+	**	The device reselected for an untagged nexus and we 
+	**	haven't any.
+	*/
+	case SIR_RESEL_BAD_I_T_L:
+		np->msgout[0] = M_ABORT;
+		goto out;
+	/*
+	**	The device reselected for a tagged nexus that we donnot 
+	**	have.
+	*/
+	case SIR_RESEL_BAD_I_T_L_Q:
+		np->msgout[0] = M_ABORT_TAG;
+		goto out;
+	/*
+	**	The SCRIPTS let us know that the device has grabbed 
+	**	our message and will abort the job.
+	*/
+	case SIR_RESEL_ABORTED:
+		np->lastmsg = np->msgout[0];
+		np->msgout[0] = M_NOOP;
+		printk ("%s:%d: message %x sent on bad reselection.\n",
+			ncr_name (np), target, np->lastmsg);
+		goto out;
+	/*
+	**	The SCRIPTS let us know that a message has been 
+	**	successfully sent to the device.
+	*/
+	case SIR_MSG_OUT_DONE:
+		np->lastmsg = np->msgout[0];
+		np->msgout[0] = M_NOOP;
+		/* Should we really care of that */
+		if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) {
+			if (cp)
+				cp->xerr_status &= ~XE_PARITY_ERR;
+		}
+		goto out;
+	/*
+	**	The device didn't send a GOOD SCSI status.
+	**	We may have some work to do prior to allow 
+	**	the SCRIPTS processor to continue.
+	*/
+	case SIR_BAD_STATUS:
+		if (!cp)
+			goto out;
+		ncr_sir_to_redo(np, num, cp);
+		return;
+	/*
+	**	We are asked by the SCRIPTS to prepare a 
+	**	REJECT message.
+	*/
+	case SIR_REJECT_TO_SEND:
+		ncr_print_msg(cp, "M_REJECT to send for ", np->msgin);
+		np->msgout[0] = M_REJECT;
+		goto out;
+	/*
+	**	We have been ODD at the end of a DATA IN 
+	**	transfer and the device didn't send a 
+	**	IGNORE WIDE RESIDUE message.
+	**	It is a data overrun condition.
+	*/
+	case SIR_SWIDE_OVERRUN:
+		if (cp)
+			cp->xerr_status |= XE_EXTRA_DATA;
+		goto out;
+	/*
+	**	We have been ODD at the end of a DATA OUT 
+	**	transfer.
+	**	It is a data underrun condition.
+	*/
+	case SIR_SODL_UNDERRUN:
+		if (cp)
+			cp->xerr_status |= XE_EXTRA_DATA;
+		goto out;
+	/*
+	**	We received a message.
+	*/
+	case SIR_MSG_RECEIVED:
+		if (!cp)
+			goto out_stuck;
+		switch (np->msgin [0]) {
+		/*
+		**	We received an extended message.
+		**	We handle MODIFY DATA POINTER, SDTR, WDTR 
+		**	and reject all other extended messages.
+		*/
+		case M_EXTENDED:
+			switch (np->msgin [2]) {
+			case M_X_MODIFY_DP:
+				if (DEBUG_FLAGS & DEBUG_POINTER)
+					ncr_print_msg(cp,"modify DP",np->msgin);
+				tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + 
+				      (np->msgin[5]<<8)  + (np->msgin[6]);
+				ncr_modify_dp(np, tp, cp, tmp);
+				return;
+			case M_X_SYNC_REQ:
+				ncr_sync_nego(np, tp, cp);
+				return;
+			case M_X_WIDE_REQ:
+				ncr_wide_nego(np, tp, cp);
+				return;
+			default:
+				goto out_reject;
+			}
+			break;
+		/*
+		**	We received a 1/2 byte message not handled from SCRIPTS.
+		**	We are only expecting MESSAGE REJECT and IGNORE WIDE 
+		**	RESIDUE messages that haven't been anticipated by 
+		**	SCRIPTS on SWIDE full condition. Unanticipated IGNORE 
+		**	WIDE RESIDUE messages are aliased as MODIFY DP (-1).
+		*/
+		case M_IGN_RESIDUE:
+			if (DEBUG_FLAGS & DEBUG_POINTER)
+				ncr_print_msg(cp,"ign wide residue", np->msgin);
+			ncr_modify_dp(np, tp, cp, -1);
+			return;
+		case M_REJECT:
+			if (INB (HS_PRT) == HS_NEGOTIATE)
+				ncr_nego_rejected(np, tp, cp);
+			else {
+				PRINT_ADDR(cp->cmd);
+				printk ("M_REJECT received (%x:%x).\n",
+					scr_to_cpu(np->lastmsg), np->msgout[0]);
+			}
+			goto out_clrack;
+			break;
+		default:
+			goto out_reject;
+		}
+		break;
+	/*
+	**	We received an unknown message.
+	**	Ignore all MSG IN phases and reject it.
+	*/
+	case SIR_MSG_WEIRD:
+		ncr_print_msg(cp, "WEIRD message received", np->msgin);
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_weird));
+		return;
+	/*
+	**	Negotiation failed.
+	**	Target does not send us the reply.
+	**	Remove the HS_NEGOTIATE status.
+	*/
+	case SIR_NEGO_FAILED:
+		OUTB (HS_PRT, HS_BUSY);
+	/*
+	**	Negotiation failed.
+	**	Target does not want answer message.
+	*/
+	case SIR_NEGO_PROTO:
+		ncr_nego_default(np, tp, cp);
+		goto out;
 	};
 
 out:
 	OUTONB (nc_dcntl, (STD|NOCOM));
+	return;
+out_reject:
+	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+	return;
+out_clrack:
+	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+	return;
 out_stuck:
 }
 
+
 /*==========================================================
 **
 **
@@ -8599,8 +10052,8 @@
 static	ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln)
 {
 	tcb_p tp = &np->target[tn];
-	lcb_p lp = tp->lp[ln];
-	u_char tag = NO_TAG;
+	lcb_p lp = ncr_lp(np, tp, ln);
+	u_short tag = NO_TAG;
 	XPT_QUEHEAD *qp;
 	ccb_p cp = (ccb_p) 0;
 
@@ -8644,9 +10097,10 @@
 			if (lp->busyccbs < lp->maxnxs) {
 				tag = lp->cb_tags[lp->ia_tag];
 				++lp->ia_tag;
-				if (lp->ia_tag == SCSI_NCR_MAX_TAGS)
+				if (lp->ia_tag == MAX_TAGS)
 					lp->ia_tag = 0;
-				lp->tags_umap |= (((tagmap_t) 1) << tag);
+				cp->tags_si = lp->tags_si;
+				++lp->tags_sum[cp->tags_si];
 			}
 			else
 				goto out_free;
@@ -8663,6 +10117,7 @@
 	/*
 	**	Remember all informations needed to free this CCB.
 	*/
+	cp->to_abort = 0;
 	cp->tag	   = tag;
 	cp->target = tn;
 	cp->lun    = ln;
@@ -8691,7 +10146,7 @@
 static void ncr_free_ccb (ncb_p np, ccb_p cp)
 {
 	tcb_p tp = &np->target[cp->target];
-	lcb_p lp = tp->lp[cp->lun];
+	lcb_p lp = ncr_lp(np, tp, cp->lun);
 
 	if (DEBUG_FLAGS & DEBUG_TAGS) {
 		PRINT_LUN(np, cp->target, cp->lun);
@@ -8706,10 +10161,9 @@
 	if (lp) {
 		if (cp->tag != NO_TAG) {
 			lp->cb_tags[lp->if_tag++] = cp->tag;
-			if (lp->if_tag == SCSI_NCR_MAX_TAGS)
+			if (lp->if_tag == MAX_TAGS)
 				lp->if_tag = 0;
-			lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag);
-			lp->tags_smap &= lp->tags_umap;
+			--lp->tags_sum[cp->tags_si];
 			lp->tasktbl[cp->tag] = cpu_to_scr(np->p_bad_i_t_l_q);
 		} else {
 			lp->tasktbl[0] = cpu_to_scr(np->p_bad_i_t_l);
@@ -8770,6 +10224,11 @@
 	cp->phys.header.go.restart = cpu_to_scr(NCB_SCRIPTH_PHYS(np,bad_i_t_l));
 
 	/*
+	**	Initilialyze some other fields.
+	*/
+	cp->phys.smsg_ext.addr = cpu_to_scr(vtobus(&np->msgin[2]));
+
+	/*
 	**	Chain into wakeup list and free ccb queue.
 	*/
 	cp->link_ccb	= np->ccbc;
@@ -8820,25 +10279,6 @@
 */
 static void ncr_init_tcb (ncb_p np, u_char tn)
 {
-	tcb_p tp = &np->target[tn];
-
-	/*
-	**	Already bone.
-	*/
-	if (tp->luntbl)
-		return;
-	/*
-	**	Allocate the lcb bus address array.
-	*/
-	tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN);
-	if (!tp->luntbl)
-		return;
-
-	/*
-	**	Compute the bus address of this table.
-	*/
-	tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl));
-
 	/*
 	**	Check some alignments required by the chip.
 	*/	
@@ -8858,7 +10298,7 @@
 static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
 {
 	tcb_p tp = &np->target[tn];
-	lcb_p lp = tp->lp[ln];
+	lcb_p lp = ncr_lp(np, tp, ln);
 
 	/*
 	**	Already done, return.
@@ -8870,21 +10310,46 @@
 	**	Initialize the target control block if not yet.
 	*/
 	ncr_init_tcb(np, tn);
-	if (!tp->luntbl)
-		goto fail;
 
 	/*
-	**	Allocate the lcb.
+	**	Allocate the lcb bus address array.
+	**	Compute the bus address of this table.
 	*/
-	lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN);
-	if (!lp)
-		goto fail;
-	tp->lp[ln] = lp;
+	if (ln && !tp->luntbl) {
+		int i;
+
+		tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN);
+		if (!tp->luntbl)
+			goto fail;
+		for (i = 0 ; i < 64 ; i++)
+			tp->luntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun));
+		tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl));
+	}
+
+	/*
+	**	Allocate the table of pointers for LUN(s) > 0, if needed.
+	*/
+	if (ln && !tp->lmp) {
+		tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP", MEMO_WARN);
+		if (!tp->lmp)
+			goto fail;
+	}
 
 	/*
+	**	Allocate the lcb.
 	**	Make it available to the chip.
 	*/
-	tp->luntbl[ln] = cpu_to_scr(vtobus(lp));
+	lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN);
+	if (!lp)
+		goto fail;
+	if (ln) {
+		tp->lmp[ln] = lp;
+		tp->luntbl[ln] = cpu_to_scr(vtobus(lp));
+	}
+	else {
+		tp->l0p = lp;
+		tp->b_lun0 = cpu_to_scr(vtobus(lp));
+	}
 
 	/*
 	**	Initialize the CCB queue headers.
@@ -8924,7 +10389,7 @@
 static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data)
 {
 	tcb_p tp = &np->target[tn];
-	lcb_p lp = tp->lp[ln];
+	lcb_p lp = ncr_lp(np, tp, ln);
 	u_char inq_byte7;
 	int i;
 
@@ -8934,14 +10399,16 @@
 	if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln)))
 		goto fail;
 
+#if 0	/* No more used. Left here as provision */
 	/*
-	**	Get device quirks from a speciality table.
+	**	Get device quirks.
 	*/
-	tp->quirks = ncr_lookup (inq_data);
+	tp->quirks = 0;
 	if (tp->quirks && bootverbose) {
 		PRINT_LUN(np, tn, ln);
 		printk ("quirks=%x.\n", tp->quirks);
 	}
+#endif
 
 	/*
 	**	Evaluate trustable target/unit capabilities.
@@ -8984,18 +10451,23 @@
 	**	initialyze the task table if not yet.
 	*/
 	if ((inq_byte7 & INQ7_QUEUE) && lp->tasktbl == &lp->tasktbl_0) {
-		lp->tasktbl = m_calloc(256, "TASKTBL", MEMO_WARN);
+		lp->tasktbl = m_calloc(MAX_TASKS*4, "TASKTBL", MEMO_WARN);
 		if (!lp->tasktbl) {
 			lp->tasktbl = &lp->tasktbl_0;
 			goto fail;
 		}
 		lp->b_tasktbl = cpu_to_scr(vtobus(lp->tasktbl));
-		for (i = 0 ; i < 64 ; i++)
+		for (i = 0 ; i < MAX_TASKS ; i++)
 			lp->tasktbl[i] = cpu_to_scr(np->p_notask);
-		for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++)
+
+		lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS", MEMO_WARN);
+		if (!lp->cb_tags)
+			goto fail;
+		for (i = 0 ; i < MAX_TAGS ; i++)
 			lp->cb_tags[i] = i;
-		lp->maxnxs = SCSI_NCR_MAX_TAGS;
-		lp->tags_stime = jiffies;
+
+		lp->maxnxs = MAX_TAGS;
+		lp->tags_stime = ktime_get(3*HZ);
 	}
 
 	/*
@@ -9043,7 +10515,7 @@
 /*
 **	For 64 bit systems, we use the 8 upper bits of the size field 
 **	to provide bus address bits 32-39 to the SCRIPTS processor.
-**	This allows the 896 to access up to 1 tera-bytes of memory.
+**	This allows the 895A and 896 to address up to 1 TB of memory.
 **	For 32 bit chips on 64 bit systems, we must be provided with 
 **	memory addresses that fit into the first 32 bit bus address 
 **	range and so, this does not matter and we expect an error from 
@@ -9325,62 +10797,6 @@
 
 /*==========================================================
 **
-**
-**	Device lookup.
-**
-**	@GENSCSI@ should be integrated to scsiconf.c
-**
-**
-**==========================================================
-*/
-
-struct table_entry {
-	char *	manufacturer;
-	char *	model;
-	char *	version;
-	u_long	info;
-};
-
-static struct table_entry device_tab[] =
-{
-#if 0
-	{"", "", "", QUIRK_NOMSG},
-#endif
-	{"SONY", "SDT-5000", "3.17", QUIRK_NOMSG},
-	{"WangDAT", "Model 2600", "01.7", QUIRK_NOMSG},
-	{"WangDAT", "Model 3200", "02.2", QUIRK_NOMSG},
-	{"WangDAT", "Model 1300", "02.4", QUIRK_NOMSG},
-	{"", "", "", 0} /* catch all: must be last entry. */
-};
-
-static u_long ncr_lookup(char * id)
-{
-	struct table_entry * p = device_tab;
-	char *d, *r, c;
-
-	for (;;p++) {
-
-		d = id+8;
-		r = p->manufacturer;
-		while ((c=*r++)) if (c!=*d++) break;
-		if (c) continue;
-
-		d = id+16;
-		r = p->model;
-		while ((c=*r++)) if (c!=*d++) break;
-		if (c) continue;
-
-		d = id+32;
-		r = p->version;
-		while ((c=*r++)) if (c!=*d++) break;
-		if (c) continue;
-
-		return (p->info);
-	}
-}
-
-/*==========================================================
-**
 **	Determine the ncr's clock frequency.
 **	This is essential for the negotiation
 **	of the synchronous transfer rate.
@@ -9395,7 +10811,7 @@
 **	do not have a clock doubler and so are provided with a 
 **	80 MHz clock. All other fast20 boards incorporate a doubler 
 **	and so should be delivered with a 40 MHz clock.
-**	The recent fast40 chips (895/896) use a 40 Mhz base clock 
+**	The recent fast40 chips (895/896/895A) use a 40 Mhz base clock 
 **	and provide a clock quadrupler (160 Mhz). The code below 
 **	tries to deal as cleverly as possible with all this stuff.
 **
@@ -9436,7 +10852,8 @@
  */
 static unsigned __init ncrgetfreq (ncb_p np, int gen)
 {
-	unsigned ms = 0;
+	unsigned int ms = 0;
+	unsigned int f;
 
 	/*
 	 * Measure GEN timer delay in order 
@@ -9453,7 +10870,6 @@
 	 * performed trust the higher delay 
 	 * (lower frequency returned).
 	 */
-	OUTB (nc_stest1, 0);	/* make sure clock doubler is OFF */
 	OUTW (nc_sien , 0);	/* mask all scsi interrupts */
 	(void) INW (nc_sist);	/* clear pending scsi interrupt */
 	OUTB (nc_dien , 0);	/* mask all dma interrupts */
@@ -9471,12 +10887,28 @@
  	 */
  	OUTB (nc_scntl3, 0);
 
-	if (bootverbose >= 2)
-		printk ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms);
   	/*
  	 * adjust for prescaler, and convert into KHz 
   	 */
-	return ms ? ((1 << gen) * 4340) / ms : 0;
+	f = ms ? ((1 << gen) * 4340) / ms : 0;
+
+	if (bootverbose >= 2)
+		printk ("%s: Delay (GEN=%d): %u msec, %u KHz\n",
+			ncr_name(np), gen, ms, f);
+
+	return f;
+}
+
+static unsigned __init ncr_getfreq (ncb_p np)
+{
+	u_int f1, f2;
+	int gen = 11;
+
+	(void) ncrgetfreq (np, gen);	/* throw away first result */
+	f1 = ncrgetfreq (np, gen);
+	f2 = ncrgetfreq (np, gen);
+	if (f1 > f2) f1 = f2;		/* trust lower result	*/
+	return f1;
 }
 
 /*
@@ -9492,7 +10924,7 @@
 	f1 = 40000;
 
 	/*
-	**	True with 875/895/896 with clock multiplier selected
+	**	True with 875/895/896/895A with clock multiplier selected
 	*/
 	if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
 		if (bootverbose >= 2)
@@ -9506,16 +10938,11 @@
 	**	Otherwise trust scntl3 BIOS setting.
 	*/
 	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
-		unsigned f2;
-
-		(void) ncrgetfreq (np, 11);	/* throw away first result */
-		f1 = ncrgetfreq (np, 11);
-		f2 = ncrgetfreq (np, 11);
+		OUTB (nc_stest1, 0);		/* make sure doubler is OFF */
+		f1 = ncr_getfreq (np);
 
 		if (bootverbose)
-			printk ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
-
-		if (f1 > f2) f1 = f2;		/* trust lower result	*/
+			printk ("%s: NCR clock is %uKHz\n", ncr_name(np), f1);
 
 		if	(f1 <	45000)		f1 =  40000;
 		else if (f1 <	55000)		f1 =  50000;
@@ -9541,6 +10968,21 @@
 	np->clock_khz	= f1;
 }
 
+/*
+ *	Get/probe PCI clock frequency
+ */
+static u_int __init ncr_getpciclock (ncb_p np)
+{
+	static u_int f = 0;
+
+	if (!f) {
+		OUTB (nc_stest1, SCLK);	/* Use the PCI clock as SCSI clock */
+		f = ncr_getfreq (np);
+		OUTB (nc_stest1, 0);
+	}
+	return f;
+}
+
 /*===================== LINUX ENTRY POINTS SECTION ==========================*/
 
 #ifndef uchar
@@ -9592,6 +11034,11 @@
 #define OPT_SAFE_SETUP		22
 #define OPT_USE_NVRAM		23
 #define OPT_EXCLUDE		24
+#define OPT_HOST_ID		25
+
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define OPT_IARB		26
+#endif
 
 static char setup_token[] __initdata = 
 	"tags:"   "mpar:"
@@ -9606,7 +11053,11 @@
 	"buschk:" "optim:"
 	"recovery:"
 	"safe:"   "nvram:"
-	"excl:";
+	"excl:"   "hostid:"
+#ifdef SCSI_NCR_IARB_SUPPORT
+	"iarb:"
+#endif
+	;	/* DONNOT REMOVE THIS ';' */
 
 #ifdef MODULE
 #define	ARG_SEP	' '
@@ -9631,7 +11082,7 @@
 }
 
 
-void __init sym53c8xx_setup(char *str, int *ints)
+int __init sym53c8xx_setup(char *str)
 {
 #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
 	char *cur = str;
@@ -9736,6 +11187,14 @@
 			if (xi < SCSI_NCR_MAX_EXCLUDES)
 				driver_setup.excludes[xi++] = val;
 			break;
+		case OPT_HOST_ID:
+			driver_setup.host_id = val;
+			break;
+#ifdef SCSI_NCR_IARB_SUPPORT
+		case OPT_IARB:
+			driver_setup.iarb = val;
+			break;
+#endif
 		default:
 			printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 			break;
@@ -9745,8 +11204,15 @@
 			++cur;
 	}
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+	return 0;
 }
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("sym53c8xx=", sym53c8xx_setup);
+#endif
+#endif
+
 static int sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
 	     uchar bus, uchar device_fn, ncr_device *device);
 
@@ -9893,7 +11359,7 @@
 
 #if	defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
 if (sym53c8xx)
-	sym53c8xx_setup(sym53c8xx, (int *) 0);
+	sym53c8xx_setup(sym53c8xx);
 #endif
 #ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 	ncr_debug = driver_setup.debug;
@@ -9945,8 +11411,16 @@
 			continue;
 		}
 		++index;
+		/* Some HW as the HP LH4 may report twice PCI devices */
+		for (i = 0; i < count ; i++) {
+			if (devtbl[i].slot.bus	     == bus && 
+			    devtbl[i].slot.device_fn == device_fn)
+				break;
+		}
+		if (i != count)	/* Ignore this device if we already have it */
+			continue;
 		devp = &devtbl[count];
-		devp->host_id = 255;
+		devp->host_id = driver_setup.host_id;
 		devp->attach_done = 0;
 		if (sym53c8xx_pci_init(tpnt, bus, device_fn, devp)) {
 			continue;
@@ -10050,7 +11524,7 @@
 **===================================================================
 */
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
-static int  __init
+static int __init 
 pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base)
 {
 	u_int32 tmp;
@@ -10067,18 +11541,27 @@
 	}
 	return offset;
 }
-#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) */
-static int __init
+#elif	LINUX_VERSION_CODE <= LinuxVersionCode(2,3,12)
+static int __init 
 pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
 {
-	/* FIXME! This is just unbelieably horrible backwards compatibility code */
-	struct resource *res = pdev->resource + index;
-
-	*base = res->start | (res->flags & 0xf);
-	if ((res->flags & 0x7) == 0x4) {
+	*base = pdev->base_address[index++];
+	if ((*base & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+		*base |= (((u_long)pdev->base_address[index]) << 32);
+#endif
 		++index;
 	}
-	return index+1;
+	return index;
+}
+#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) */
+static int __init 
+pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+{
+	*base = pdev->resource[index].start;
+	if ((pdev->resource[index].flags & 0x7) == 0x4)
+		++index;
+	return ++index;
 }
 #endif
 
@@ -10094,6 +11577,7 @@
 	u_short vendor_id, device_id, command;
 	u_char cache_line_size, latency_timer;
 	u_char suggested_cache_line_size = 0;
+	u_char pci_fix_up;
 	u_char revision;
 #if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
 	struct pci_dev *pdev;
@@ -10173,18 +11657,18 @@
 		if (revision > ncr_chip_table[i].revision_id)
 			continue;
 		if (!(ncr_chip_table[i].features & FE_LDSTR))
-			continue;
+			break;
 		chip = &device->chip;
 		memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
 		chip->revision_id = revision;
 		break;
 	}
 
-#if defined(__i386__)
 	/*
 	**	Ignore Symbios chips controlled by SISL RAID controller.
 	**	This controller sets value 0x52414944 at RAM end - 16.
 	*/
+#if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
 	if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) {
 		unsigned int ram_size, ram_val;
 		u_long ram_ptr;
@@ -10206,7 +11690,7 @@
 			}
 		}
 	}
-#endif
+#endif /* i386 and PCI MEMORY accessible */
 
 	if (!chip) {
 		printk(NAME53C8XX ": not initializing, device not supported\n");
@@ -10267,6 +11751,9 @@
 	**    coherent with hardware and software resource identifications.
 	**    This is fairly simple, but seems still too complex for Sparc.
 	*/
+	base = __pa(base);
+	base_2 = __pa(base_2);
+
 	if (!cache_line_size)
 		suggested_cache_line_size = 16;
 
@@ -10290,9 +11777,16 @@
 	/*
 	**    Check availability of IO space, memory space.
 	**    Enable master capability if not yet.
+	**
+	**    We shouldn't have to care about the IO region when 
+	**    we are using MMIO. But calling check_region() from 
+	**    both the ncr53c8xx and the sym53c8xx drivers prevents 
+	**    from attaching devices from the both drivers.
+	**    If you have a better idea, let me know.
 	*/
-#ifdef NCR_IOMAPPED
-	if (!(command & PCI_COMMAND_IO) || !(io_port & 1)) { 
+/* #ifdef NCR_IOMAPPED */
+#if 1
+	if (!(command & PCI_COMMAND_IO)) { 
 		printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n",
 			(long) io_port);
 		io_port = 0;
@@ -10307,7 +11801,8 @@
 	base	&= PCI_BASE_ADDRESS_MEM_MASK;
 	base_2	&= PCI_BASE_ADDRESS_MEM_MASK;
 
-#ifdef NCR_IOMAPPED
+/* #ifdef NCR_IOMAPPED */
+#if 1
 	if (io_port && check_region (io_port, 128)) {
 		printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n",
 			(long) io_port);
@@ -10315,7 +11810,8 @@
 	}
 	if (!io_port)
 		return -1;
-#else
+#endif
+#ifndef NCR_IOMAPPED
 	if (!base) {
 		printk(NAME53C8XX ": MMIO base address disabled.\n");
 		return -1;
@@ -10354,11 +11850,24 @@
 	if (!driver_setup.max_wide)
 		chip->features &= ~FE_WIDE;
 
+	/*
+	**	Some features are required to be enabled in order to 
+	**	work around some chip problems. :) ;)
+	**	(ITEM 12 of a DEL about the 896 I haven't yet).
+	**	We must ensure the chip will use WRITE AND INVALIDATE.
+	**	The revision number limit is for now arbitrary.
+	*/
+	pci_fix_up = driver_setup.pci_fix_up;
+	if (device_id == PCI_DEVICE_ID_NCR_53C896 && revision <= 0x10) {
+		chip->features	|= (FE_WRIE | FE_CLSE);
+		pci_fix_up	|=  3;	/* Force appropriate PCI fix-up */
+	}
+
 #ifdef	SCSI_NCR_PCI_FIX_UP_SUPPORT
 	/*
 	**    Try to fix up PCI config according to wished features.
 	*/
-	if ((driver_setup.pci_fix_up & 1) && (chip->features & FE_CLSE) && 
+	if ((pci_fix_up & 1) && (chip->features & FE_CLSE) && 
 	    !cache_line_size && suggested_cache_line_size) {
 		cache_line_size = suggested_cache_line_size;
 		pcibios_write_config_byte(bus, device_fn,
@@ -10367,7 +11876,7 @@
 			cache_line_size);
 	}
 
-	if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
+	if ((pci_fix_up & 2) && cache_line_size &&
 	    (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
 		printk(NAME53C8XX": setting PCI_COMMAND_INVALIDATE (fix-up)\n");
 		command |= PCI_COMMAND_INVALIDATE;
@@ -10379,7 +11888,7 @@
 	**    (latency timer >= burst length + 6, we add 10 to be quite sure)
 	*/
 
-	if ((driver_setup.pci_fix_up & 4) && chip->burst_max) {
+	if ((pci_fix_up & 4) && chip->burst_max) {
 		uchar lt = (1 << chip->burst_max) + 6 + 10;
 		if (latency_timer < lt) {
 			latency_timer = lt;
@@ -10532,7 +12041,7 @@
 
 		np = ((struct host_data *) host->hostdata)->ncb;
 		tp = &np->target[device->id];
-		lp = tp->lp[device->lun];
+		lp = ncr_lp(np, tp, device->lun);
 
 		/*
 		**	Select queue depth from driver setup.
@@ -10548,8 +12057,8 @@
 		device->queue_depth = numtags;
 		if (device->queue_depth < 2)
 			device->queue_depth = 2;
-		if (device->queue_depth > SCSI_NCR_MAX_TAGS)
-			device->queue_depth = SCSI_NCR_MAX_TAGS;
+		if (device->queue_depth > MAX_TAGS)
+			device->queue_depth = MAX_TAGS;
 
 		/*
 		**	Since the queue depth is not tunable under Linux,
@@ -10973,8 +12482,14 @@
 		uc->cmd = UC_SETDEBUG;
 	else if	((arg_len = is_keyword(ptr, len, "setflag")) != 0)
 		uc->cmd = UC_SETFLAG;
+	else if	((arg_len = is_keyword(ptr, len, "resetdev")) != 0)
+		uc->cmd = UC_RESETDEV;
+	else if	((arg_len = is_keyword(ptr, len, "cleardev")) != 0)
+		uc->cmd = UC_CLEARDEV;
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	else if	((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
 		uc->cmd = UC_CLEARPROF;
+#endif
 	else
 		arg_len = 0;
 
@@ -10991,6 +12506,8 @@
 	case UC_SETTAGS:
 	case UC_SETWIDE:
 	case UC_SETFLAG:
+	case UC_RESETDEV:
+	case UC_CLEARDEV:
 		SKIP_SPACES(1);
 		if ((arg_len = is_keyword(ptr, len, "all")) != 0) {
 			ptr += arg_len; len -= arg_len;
@@ -11034,14 +12551,12 @@
 				uc->data |= DEBUG_ALLOC;
 			else if	((arg_len = is_keyword(ptr, len, "phase")))
 				uc->data |= DEBUG_PHASE;
-			else if	((arg_len = is_keyword(ptr, len, "poll")))
-				uc->data |= DEBUG_POLL;
 			else if	((arg_len = is_keyword(ptr, len, "queue")))
 				uc->data |= DEBUG_QUEUE;
 			else if	((arg_len = is_keyword(ptr, len, "result")))
 				uc->data |= DEBUG_RESULT;
-			else if	((arg_len = is_keyword(ptr, len, "scatter")))
-				uc->data |= DEBUG_SCATTER;
+			else if	((arg_len = is_keyword(ptr, len, "pointer")))
+				uc->data |= DEBUG_POINTER;
 			else if	((arg_len = is_keyword(ptr, len, "script")))
 				uc->data |= DEBUG_SCRIPT;
 			else if	((arg_len = is_keyword(ptr, len, "tiny")))
@@ -11052,10 +12567,6 @@
 				uc->data |= DEBUG_NEGO;
 			else if	((arg_len = is_keyword(ptr, len, "tags")))
 				uc->data |= DEBUG_TAGS;
-			else if	((arg_len = is_keyword(ptr, len, "freeze")))
-				uc->data |= DEBUG_FREEZE;
-			else if	((arg_len = is_keyword(ptr, len, "restart")))
-				uc->data |= DEBUG_RESTART;
 			else
 				return -EINVAL;
 			ptr += arg_len; len -= arg_len;
@@ -11167,7 +12678,7 @@
 		                  (u_long) np->reg);
 #endif
 	copy_info(&info, "  Synchronous period factor %d, ", (int) np->minsync);
-	copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS);
+	copy_info(&info, "max commands per lun %d\n", MAX_TAGS);
 
 	if (driver_setup.debug || driver_setup.verbose > 1) {
 		copy_info(&info, "  Debug flags 0x%x, ", driver_setup.debug);
@@ -11350,8 +12861,8 @@
 	nvram_stop(np, &gpreg);
 	
 #ifdef SCSI_NCR_DEBUG_NVRAM
-printk("sym53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
-	nvram->start_marker,
+printk("sym53c8xx: NvRAM type=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
+	nvram->type,
 	nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
 	nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
 	nvram->byte_count, sizeof(*nvram) - 12,
@@ -11375,7 +12886,8 @@
 /*
  * Read Symbios NvRAM data and compute checksum.
  */
-static u_short __init nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
+static u_short __init 
+nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
 {
 	int	x;
 	u_short	csum;
@@ -11404,7 +12916,8 @@
  * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
  * GPIO0 must already be set as an output
  */
-static void __init nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
+static void __init 
+nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
 {
 	int x;
 	
@@ -11418,7 +12931,8 @@
  * READ a byte from the NVRAM and then send an ACK to say we have got it,
  * GPIO0 must already be set as an input
  */
-static void __init nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
+static void __init 
+nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
 {
 	int x;
 	u_char read_bit;
@@ -11436,7 +12950,8 @@
  * Output an ACK to the NVRAM after reading,
  * change GPIO0 to output and when done back to an input
  */
-static void __init nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
+static void __init 
+nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
 {
 	OUTB (nc_gpcntl, *gpcntl & 0xfe);
 	nvram_doBit(np, 0, write_bit, gpreg);
@@ -11447,7 +12962,8 @@
  * Input an ACK from NVRAM after writing,
  * change GPIO0 to input and when done back to an output
  */
-static void __init nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
+static void __init 
+nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
 {
 	OUTB (nc_gpcntl, *gpcntl | 0x01);
 	nvram_doBit(np, read_bit, 1, gpreg);
@@ -11458,7 +12974,8 @@
  * Read or write a bit to the NVRAM,
  * read if GPIO0 input else write if GPIO0 output
  */
-static void __init nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
+static void __init 
+nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
 {
 	nvram_setBit(np, write_bit, gpreg, SET_BIT);
 	nvram_setBit(np, 0, gpreg, SET_CLK);
@@ -11480,7 +12997,8 @@
 /*
  * Set/clear data/clock bit in GPIO0
  */
-static void __init nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
+static void __init 
+nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
 {
 	UDELAY (5);
 	switch (bit_mode){
@@ -11566,7 +13084,8 @@
 /*
  * Read Tekram NvRAM data and compute checksum.
  */
-static u_short __init Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
+static u_short __init 
+Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
 {
 	u_char	read_bit;
 	u_short	csum;
@@ -11591,7 +13110,8 @@
 /*
  * Send read command and address to NVRAM
  */
-static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
+static void __init 
+Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
 {
 	int x;
 
@@ -11605,7 +13125,8 @@
 /*
  * READ a byte from the NVRAM
  */
-static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
+static void __init 
+Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
 {
 	int x;
 	u_char read_bit;
@@ -11624,7 +13145,8 @@
 /* 
  * Read bit from NVRAM
  */
-static void __init Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
+static void __init 
+Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
 {
 	UDELAY (2);
 	Tnvram_Clk(np, gpreg);
@@ -11634,7 +13156,8 @@
 /*
  * Write bit to GPIO0
  */
-static void __init Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
+static void __init 
+Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
 {
 	if (write_bit & 0x01)
 		*gpreg |= 0x02;
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/sym53c8xx.h linux/drivers/scsi/sym53c8xx.h
--- v2.3.19/linux/drivers/scsi/sym53c8xx.h	Wed Aug 18 16:44:49 1999
+++ linux/drivers/scsi/sym53c8xx.h	Fri Oct  8 10:27:11 1999
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-1999  Gerard Roudier <groudier@club-internet.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h
--- v2.3.19/linux/drivers/scsi/sym53c8xx_defs.h	Wed Aug 18 16:44:21 1999
+++ linux/drivers/scsi/sym53c8xx_defs.h	Fri Oct  8 10:26:51 1999
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-1999  Gerard Roudier <groudier@club-internet.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
@@ -137,13 +137,13 @@
 #define SCSI_NCR_MAX_SYNC			(40)
 
 /*
- * Allow tags from 2 to 64, default 8
+ * Allow tags from 2 to 256, default 8
  */
 #ifdef	CONFIG_SCSI_NCR53C8XX_MAX_TAGS
 #if	CONFIG_SCSI_NCR53C8XX_MAX_TAGS < 2
 #define SCSI_NCR_MAX_TAGS	(2)
-#elif	CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 64
-#define SCSI_NCR_MAX_TAGS	(64)
+#elif	CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 256
+#define SCSI_NCR_MAX_TAGS	(256)
 #else
 #define	SCSI_NCR_MAX_TAGS	CONFIG_SCSI_NCR53C8XX_MAX_TAGS
 #endif
@@ -175,6 +175,13 @@
 #endif
 
 /*
+ * Immediate arbitration
+ */
+#if defined(CONFIG_SCSI_NCR53C8XX_IARB)
+#define SCSI_NCR_IARB_SUPPORT
+#endif
+
+/*
  * Sync transfer frequency at startup.
  * Allow from 5Mhz to 40Mhz default 20 Mhz.
  */
@@ -238,7 +245,7 @@
  */
 #ifdef CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
 #define SCSI_NCR_SETUP_LED_PIN		(1)
-#define SCSI_NCR_SETUP_DIFF_SUPPORT	(3)
+#define SCSI_NCR_SETUP_DIFF_SUPPORT	(4)
 #else
 #define SCSI_NCR_SETUP_LED_PIN		(0)
 #define SCSI_NCR_SETUP_DIFF_SUPPORT	(0)
@@ -250,6 +257,57 @@
 #define SCSI_NCR_SETUP_SETTLE_TIME	(2)
 
 /*
+**	Bridge quirks work-around option defaulted to 1.
+*/
+#ifndef	SCSI_NCR_PCIQ_WORK_AROUND_OPT
+#define	SCSI_NCR_PCIQ_WORK_AROUND_OPT	1
+#endif
+
+/*
+**	Work-around common bridge misbehaviour.
+**
+**	- Do not flush posted writes in the opposite 
+**	  direction on read.
+**	- May reorder DMA writes to memory.
+**
+**	This option should not affect performances 
+**	significantly, so it is the default.
+*/
+#if	SCSI_NCR_PCIQ_WORK_AROUND_OPT == 1
+#define	SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+#define	SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+#define	SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+
+/*
+**	Same as option 1, but also deal with 
+**	misconfigured interrupts.
+**
+**	- Edge triggerred instead of level sensitive.
+**	- No interrupt line connected.
+**	- IRQ number misconfigured.
+**	
+**	If no interrupt is delivered, the driver will 
+**	catch the interrupt conditions 10 times per 
+**	second. No need to say that this option is 
+**	not recommended.
+*/
+#elif	SCSI_NCR_PCIQ_WORK_AROUND_OPT == 2
+#define	SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+#define	SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+#define	SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+#define	SCSI_NCR_PCIQ_BROKEN_INTR
+
+/*
+**	Some bridge designers decided to flush 
+**	everything prior to deliver the interrupt.
+**	This option tries to deal with such a 
+**	behaviour.
+*/
+#elif	SCSI_NCR_PCIQ_WORK_AROUND_OPT == 3
+#define	SCSI_NCR_PCIQ_SYNC_ON_INTR
+#endif
+
+/*
 **	Other parameters not configurable with "make config"
 **	Avoid to change these constants, unless you know what you are doing.
 */
@@ -258,20 +316,20 @@
 #define SCSI_NCR_MAX_SCATTER	(127)
 #define SCSI_NCR_MAX_TARGET	(16)
 
-/* No need to use a too large adapter queue */
-#if SCSI_NCR_MAX_TAGS <= 32
-#define SCSI_NCR_CAN_QUEUE	(7*SCSI_NCR_MAX_TAGS)
-#else
-#define SCSI_NCR_CAN_QUEUE	(250)
-#endif
-
+/*
+**   Compute some desirable value for CAN_QUEUE 
+**   and CMD_PER_LUN.
+**   The driver will use lower values if these 
+**   ones appear to be too large.
+*/
+#define SCSI_NCR_CAN_QUEUE	(8*SCSI_NCR_MAX_TAGS + 2*SCSI_NCR_MAX_TARGET)
 #define SCSI_NCR_CMD_PER_LUN	(SCSI_NCR_MAX_TAGS)
-#define SCSI_NCR_SG_TABLESIZE	(SCSI_NCR_MAX_SCATTER)
 
+#define SCSI_NCR_SG_TABLESIZE	(SCSI_NCR_MAX_SCATTER)
 #define SCSI_NCR_TIMER_INTERVAL	(HZ)
 
 #if 1 /* defined CONFIG_SCSI_MULTI_LUN */
-#define SCSI_NCR_MAX_LUN	(8)
+#define SCSI_NCR_MAX_LUN	(16)
 #else
 #define SCSI_NCR_MAX_LUN	(1)
 #endif
@@ -279,6 +337,18 @@
 #ifndef HOSTS_C
 
 /*
+**	These simple macros limit expression involving 
+**	kernel time values (jiffies) to some that have 
+**	chance not to be too much incorrect. :-)
+*/
+#define ktime_get(o)		(jiffies + (u_long) o)
+#define ktime_exp(b)		((long)(jiffies) - (long)(b) >= 0)
+#define ktime_dif(a, b)		((long)(a) - (long)(b))
+/* These ones are not used in this driver */
+#define ktime_add(a, o)		((a) + (u_long)(o))
+#define ktime_sub(a, o)		((a) - (u_long)(o))
+
+/*
 **	IO functions definition for big/little endian support.
 **	For now, the NCR is only supported in little endian addressing mode, 
 **	and big endian byte ordering is only supported for the PPC.
@@ -384,6 +454,10 @@
 #define PCI_DEVICE_ID_NCR_53C896 0xb
 #endif
 
+#ifndef PCI_DEVICE_ID_NCR_53C895A
+#define PCI_DEVICE_ID_NCR_53C895A 0x12
+#endif
+
 /*
 **   NCR53C8XX devices features table.
 */
@@ -391,31 +465,33 @@
 	unsigned short	device_id;
 	unsigned short	revision_id;
 	char	*name;
-	unsigned char	burst_max;
+	unsigned char	burst_max;	/* log-base-2 of max burst */
 	unsigned char	offset_max;
 	unsigned char	nr_divisor;
 	unsigned int	features;
 #define FE_LED0		(1<<0)
-#define FE_WIDE		(1<<1)
-#define FE_ULTRA	(1<<2)
-#define FE_ULTRA2	(1<<3)
-#define FE_DBLR		(1<<4)
-#define FE_QUAD		(1<<5)
-#define FE_ERL		(1<<6)
-#define FE_CLSE		(1<<7)
-#define FE_WRIE		(1<<8)
-#define FE_ERMP		(1<<9)
-#define FE_BOF		(1<<10)
-#define FE_DFS		(1<<11)
-#define FE_PFEN		(1<<12)
-#define FE_LDSTR	(1<<13)
-#define FE_RAM		(1<<14)
-#define FE_CLK80	(1<<15)
-#define FE_RAM8K	(1<<16)
-#define FE_64BIT	(1<<17)
-#define FE_IO256	(1<<18)
-#define FE_NOPM		(1<<19)
-#define FE_LEDC		(1<<20)
+#define FE_WIDE		(1<<1)    /* Wide data transfers */
+#define FE_ULTRA	(1<<2)	  /* Ultra speed 20Mtrans/sec */
+#define FE_ULTRA2	(1<<3)	  /* Ultra 2 - 40 Mtrans/sec */
+#define FE_DBLR		(1<<4)	  /* Clock doubler present */
+#define FE_QUAD		(1<<5)	  /* Clock quadrupler present */
+#define FE_ERL		(1<<6)    /* Enable read line */
+#define FE_CLSE		(1<<7)    /* Cache line size enable */
+#define FE_WRIE		(1<<8)    /* Write & Invalidate enable */
+#define FE_ERMP		(1<<9)    /* Enable read multiple */
+#define FE_BOF		(1<<10)   /* Burst opcode fetch */
+#define FE_DFS		(1<<11)   /* DMA fifo size */
+#define FE_PFEN		(1<<12)   /* Prefetch enable */
+#define FE_LDSTR	(1<<13)   /* Load/Store supported */
+#define FE_RAM		(1<<14)   /* On chip RAM present */
+#define FE_CLK80	(1<<15)   /* Board clock is 80 MHz */
+#define FE_RAM8K	(1<<16)   /* On chip RAM sized 8Kb */
+#define FE_64BIT	(1<<17)   /* Supports 64-bit addressing */
+#define FE_IO256	(1<<18)   /* Requires full 256 bytes in PCI space */
+#define FE_NOPM		(1<<19)   /* Scripts handles phase mismatch */
+#define FE_LEDC		(1<<20)   /* Hardware control of LED */
+#define FE_DIFF		(1<<21)   /* Support Differential SCSI */
+
 #define FE_CACHE_SET	(FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
 #define FE_SCSI_SET	(FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80)
 #define FE_SPECIAL_SET	(FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM)
@@ -449,35 +525,53 @@
  FE_WIDE|FE_ERL}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825",  4,  8, 4,			\
- FE_WIDE|FE_ERL|FE_BOF}							\
+ FE_WIDE|FE_ERL|FE_BOF|FE_DIFF}						\
  ,									\
  {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 6,  8, 4,			\
- FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}		\
+ FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF}	\
  ,									\
  {PCI_DEVICE_ID_NCR_53C860, 0xff, "860",  4,  8, 5,			\
  FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN}		\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875, 0x01, "875",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|\
+ FE_RAM|FE_DIFF}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875, 0x0f, "875",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DIFF}							\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C875, 0x1f, "876",  6, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DIFF}							\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C875, 0x2f, "875E",  6, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DIFF}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875, 0xff, "876",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DIFF}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM}								\
  ,									\
  {PCI_DEVICE_ID_NCR_53C885, 0xff, "885",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DIFF}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C895, 0xff, "895",  6, 31, 7,			\
- FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM}								\
  ,									\
- {PCI_DEVICE_ID_NCR_53C896, 0xff, "896",  7, 31, 7,			\
- FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|\
- FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}\
+ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896",  6, 31, 7,			\
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}			\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C895A, 0xff, "895a",  6, 31, 7,			\
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}			\
 }
 
 /*
@@ -494,10 +588,47 @@
 	PCI_DEVICE_ID_NCR_53C875J,	\
 	PCI_DEVICE_ID_NCR_53C885,	\
 	PCI_DEVICE_ID_NCR_53C895,	\
-	PCI_DEVICE_ID_NCR_53C896	\
+	PCI_DEVICE_ID_NCR_53C896,	\
+	PCI_DEVICE_ID_NCR_53C895A	\
 }
 
 /*
+**	Driver setup structure.
+**
+**	This structure is initialized from linux config options.
+**	It can be overridden at boot-up by the boot command line.
+*/
+#define SCSI_NCR_MAX_EXCLUDES 8
+struct ncr_driver_setup {
+	u_char	master_parity;
+	u_char	scsi_parity;
+	u_char	disconnection;
+	u_char	special_features;
+	u_char	ultra_scsi;
+	u_char	force_sync_nego;
+	u_char	reverse_probe;
+	u_char	pci_fix_up;
+	u_char	use_nvram;
+	u_char	verbose;
+	u_char	default_tags;
+	u_short	default_sync;
+	u_short	debug;
+	u_char	burst_max;
+	u_char	led_pin;
+	u_char	max_wide;
+	u_char	settle_delay;
+	u_char	diff_support;
+	u_char	irqm;
+	u_char	bus_check;
+	u_char	optimize;
+	u_char	recovery;
+	u_char	host_id;
+	u_short	iarb;
+	u_int	excludes[SCSI_NCR_MAX_EXCLUDES];
+	char	tag_ctrl[100];
+};
+
+/*
 **	Initial setup.
 **	Can be overriden at startup by a command line.
 */
@@ -524,7 +655,9 @@
 	0,					\
 	1,					\
 	0,					\
-	0					\
+	0,					\
+	255,					\
+	0x00					\
 }
 
 /*
@@ -555,9 +688,139 @@
 	1,					\
 	1,					\
 	0,					\
-	0					\
+	0,					\
+	255					\
 }
 
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+/*
+**	Symbios NvRAM data format
+*/
+#define SYMBIOS_NVRAM_SIZE 368
+#define SYMBIOS_NVRAM_ADDRESS 0x100
+
+struct Symbios_nvram {
+/* Header 6 bytes */
+	u_short type;		/* 0x0000 */
+	u_short byte_count;	/* excluding header/trailer */
+	u_short checksum;
+
+/* Controller set up 20 bytes */
+	u_char	v_major;	/* 0x00 */
+	u_char	v_minor;	/* 0x30 */
+	u_int32	boot_crc;
+	u_short	flags;
+#define SYMBIOS_SCAM_ENABLE	(1)
+#define SYMBIOS_PARITY_ENABLE	(1<<1)
+#define SYMBIOS_VERBOSE_MSGS	(1<<2)
+#define SYMBIOS_CHS_MAPPING	(1<<3)
+#define SYMBIOS_NO_NVRAM	(1<<3)	/* ??? */
+	u_short	flags1;
+#define SYMBIOS_SCAN_HI_LO	(1)
+	u_short	term_state;
+#define SYMBIOS_TERM_CANT_PROGRAM	(0)
+#define SYMBIOS_TERM_ENABLED		(1)
+#define SYMBIOS_TERM_DISABLED		(2)
+	u_short	rmvbl_flags;
+#define SYMBIOS_RMVBL_NO_SUPPORT	(0)
+#define SYMBIOS_RMVBL_BOOT_DEVICE	(1)
+#define SYMBIOS_RMVBL_MEDIA_INSTALLED	(2)
+	u_char	host_id;
+	u_char	num_hba;	/* 0x04 */
+	u_char	num_devices;	/* 0x10 */
+	u_char	max_scam_devices;	/* 0x04 */
+	u_char	num_valid_scam_devives;	/* 0x00 */
+	u_char	rsvd;
+
+/* Boot order 14 bytes * 4 */
+	struct Symbios_host{
+		u_short	type;		/* 4:8xx / 0:nok */
+		u_short	device_id;	/* PCI device id */
+		u_short	vendor_id;	/* PCI vendor id */
+		u_char	bus_nr;		/* PCI bus number */
+		u_char	device_fn;	/* PCI device/function number << 3*/
+		u_short	word8;
+		u_short	flags;
+#define	SYMBIOS_INIT_SCAN_AT_BOOT	(1)
+		u_short	io_port;	/* PCI io_port address */
+	} host[4];
+
+/* Targets 8 bytes * 16 */
+	struct Symbios_target {
+		u_char	flags;
+#define SYMBIOS_DISCONNECT_ENABLE	(1)
+#define SYMBIOS_SCAN_AT_BOOT_TIME	(1<<1)
+#define SYMBIOS_SCAN_LUNS		(1<<2)
+#define SYMBIOS_QUEUE_TAGS_ENABLED	(1<<3)
+		u_char	rsvd;
+		u_char	bus_width;	/* 0x08/0x10 */
+		u_char	sync_offset;
+		u_short	sync_period;	/* 4*period factor */
+		u_short	timeout;
+	} target[16];
+/* Scam table 8 bytes * 4 */
+	struct Symbios_scam {
+		u_short	id;
+		u_short	method;
+#define SYMBIOS_SCAM_DEFAULT_METHOD	(0)
+#define SYMBIOS_SCAM_DONT_ASSIGN	(1)
+#define SYMBIOS_SCAM_SET_SPECIFIC_ID	(2)
+#define SYMBIOS_SCAM_USE_ORDER_GIVEN	(3)
+		u_short status;
+#define SYMBIOS_SCAM_UNKNOWN		(0)
+#define SYMBIOS_SCAM_DEVICE_NOT_FOUND	(1)
+#define SYMBIOS_SCAM_ID_NOT_SET		(2)
+#define SYMBIOS_SCAM_ID_VALID		(3)
+		u_char	target_id;
+		u_char	rsvd;
+	} scam[4];
+
+	u_char	spare_devices[15*8];
+	u_char	trailer[6];		/* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
+};
+typedef struct Symbios_nvram	Symbios_nvram;
+typedef struct Symbios_host	Symbios_host;
+typedef struct Symbios_target	Symbios_target;
+typedef struct Symbios_scam	Symbios_scam;
+
+/*
+**	Tekram NvRAM data format.
+*/
+#define TEKRAM_NVRAM_SIZE 64
+#define TEKRAM_NVRAM_ADDRESS 0
+
+struct Tekram_nvram {
+	struct Tekram_target {
+		u_char	flags;
+#define	TEKRAM_PARITY_CHECK		(1)
+#define TEKRAM_SYNC_NEGO		(1<<1)
+#define TEKRAM_DISCONNECT_ENABLE	(1<<2)
+#define	TEKRAM_START_CMD		(1<<3)
+#define TEKRAM_TAGGED_COMMANDS		(1<<4)
+#define TEKRAM_WIDE_NEGO		(1<<5)
+		u_char	sync_index;
+		u_short	word2;
+	} target[16];
+	u_char	host_id;
+	u_char	flags;
+#define TEKRAM_MORE_THAN_2_DRIVES	(1)
+#define TEKRAM_DRIVES_SUP_1GB		(1<<1)
+#define	TEKRAM_RESET_ON_POWER_ON	(1<<2)
+#define TEKRAM_ACTIVE_NEGATION		(1<<3)
+#define TEKRAM_IMMEDIATE_SEEK		(1<<4)
+#define	TEKRAM_SCAN_LUNS		(1<<5)
+#define	TEKRAM_REMOVABLE_FLAGS		(3<<6)	/* 0: disable; 1: boot device; 2:all */
+	u_char	boot_delay_index;
+	u_char	max_tags_index;
+	u_short	flags1;
+#define TEKRAM_F2_F6_ENABLED		(1)
+	u_short	spare[29];
+};
+typedef struct Tekram_nvram	Tekram_nvram;
+typedef struct Tekram_target	Tekram_target;
+
+#endif /* SCSI_NCR_NVRAM_SUPPORT */
+
 /**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/
 
 /*-----------------------------------------------------------------
@@ -573,6 +836,7 @@
 /*01*/  u_char    nc_scntl1;    /* no reset                         */
         #define   ISCON   0x10  /* connected to scsi		    */
         #define   CRST    0x08  /* force reset                      */
+        #define   IARB    0x02  /* immediate arbitration            */
 
 /*02*/  u_char    nc_scntl2;    /* no disconnect expected           */
 	#define   SDU     0x80  /* cmd: disconnect will raise error */
@@ -639,7 +903,10 @@
         #define   DM      0x04  /* sta: DIFFSENS mismatch (895/6 only) */
         #define   LDSC    0x02  /* sta: disconnect & reconnect      */
 
-/*10*/  u_int32    nc_dsa;	/* --> Base page                    */
+/*10*/  u_char    nc_dsa;	/* --> Base page                    */
+/*11*/  u_char    nc_dsa1;
+/*12*/  u_char    nc_dsa2;
+/*13*/  u_char    nc_dsa3;
 
 /*14*/  u_char    nc_istat;	/* --> Main Command and status      */
         #define   CABRT   0x80  /* cmd: abort current operation     */
@@ -696,7 +963,7 @@
 	#define   BOF     0x02  /* mod: burst op code fetch         */
 
 /*39*/  u_char    nc_dien;
-/*3a*/  u_char    nc_dwt;
+/*3a*/  u_char    nc_sbr;
 
 /*3b*/  u_char    nc_dcntl;	/* --> Script execution control     */
 	#define   CLSE    0x80  /* mod: cache line size enable      */
@@ -736,6 +1003,7 @@
 /*4c*/  u_char    nc_stest0;
 
 /*4d*/  u_char    nc_stest1;
+	#define   SCLK    0x80	/* Use the PCI clock as SCSI clock	*/
 	#define   DBLEN   0x08	/* clock doubler running		*/
 	#define   DBLSEL  0x04	/* clock doubler selected		*/
   
@@ -794,8 +1062,15 @@
 
 /*c0*/	u_int32   nc_pmjad1;	/* Phase Mismatch Jump Address 1    */
 /*c4*/	u_int32   nc_pmjad2;	/* Phase Mismatch Jump Address 2    */
-/*c8*/	u_int32   nc_rbc;	/* Remaining Byte Count             */
-/*cc*/	u_int32   nc_ua;	/* Updated Address                  */
+/*c8*/	u_char    nc_rbc;	/* Remaining Byte Count             */
+/*c9*/	u_char    nc_rbc1;	/*                                  */
+/*ca*/	u_char    nc_rbc2;	/*                                  */
+/*cb*/	u_char    nc_rbc3;	/*                                  */
+
+/*cc*/	u_char    nc_ua;	/* Updated Address                  */
+/*cd*/	u_char    nc_ua1;	/*                                  */
+/*ce*/	u_char    nc_ua2;	/*                                  */
+/*cf*/	u_char    nc_ua3;	/*                                  */
 /*d0*/	u_int32   nc_esa;	/* Entry Storage Address            */
 /*d4*/	u_char    nc_ia;	/* Instruction Address              */
 /*d5*/	u_char    nc_ia1;
@@ -815,10 +1090,6 @@
 #define REGJ(p,r) (offsetof(struct ncr_reg, p ## r))
 #define REG(r) REGJ (nc_, r)
 
-#ifndef TARGET_MODE
-#define TARGET_MODE 0
-#endif
-
 typedef u_int32 ncrcmd;
 
 /*-----------------------------------------------------------
@@ -855,9 +1126,15 @@
 **-----------------------------------------------------------
 */
 
-#define SCR_MOVE_ABS(l) ((0x08000000 ^ (TARGET_MODE << 1ul)) | (l))
-#define SCR_MOVE_IND(l) ((0x28000000 ^ (TARGET_MODE << 1ul)) | (l))
-#define SCR_MOVE_TBL     (0x18000000 ^ (TARGET_MODE << 1ul))
+#define OPC_MOVE          0x08000000
+
+#define SCR_MOVE_ABS(l) ((0x00000000 | OPC_MOVE) | (l))
+#define SCR_MOVE_IND(l) ((0x20000000 | OPC_MOVE) | (l))
+#define SCR_MOVE_TBL     (0x10000000 | OPC_MOVE)
+
+#define SCR_CHMOV_ABS(l) ((0x00000000) | (l))
+#define SCR_CHMOV_IND(l) ((0x20000000) | (l))
+#define SCR_CHMOV_TBL     (0x10000000)
 
 struct scr_tblmove {
         u_int32  size;
@@ -870,7 +1147,7 @@
 **
 **-----------------------------------------------------------
 **
-**	SEL_ABS | SCR_ID (0..7)     [ | REL_JMP]
+**	SEL_ABS | SCR_ID (0..15)    [ | REL_JMP]
 **	<<alternate_address>>
 **
 **	SEL_TBL | << dnad_offset>>  [ | REL_JMP]
@@ -1104,7 +1381,7 @@
 **	Conditions:
 **	     WHEN (phase)
 **	     IF   (phase)
-**	     CARRY
+**	     CARRYSET
 **	     DATA (data, mask)
 **
 **-----------------------------------------------------------
diff -u --recursive --new-file v2.3.19/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.3.19/linux/drivers/sound/esssolo1.c	Mon Oct  4 15:49:30 1999
+++ linux/drivers/sound/esssolo1.c	Thu Oct  7 14:10:15 1999
@@ -58,6 +58,8 @@
  *                     replaced current->state = x with set_current_state(x)
  *    03.09.99   0.8   change read semantics for MIDI to match
  *                     OSS more closely; remove possible wakeup race
+ *    07.10.99   0.9   Fix initialization; complain if sequencer writes time out
+ *                     Revised resource grabbing for the FM synthesizer
  *
  */
 
@@ -108,6 +110,7 @@
 #define MPUBASE_EXTENT            4
 #define GPBASE_EXTENT             4
 
+#define FMSYNTH_EXTENT            4
 
 /* MIDI buffer sizes */
 
@@ -207,7 +210,7 @@
 {
         int i;
 	unsigned long flags;
-        
+
 	/* the __cli stunt is to send the data within the command window */
         for (i = 0; i < 0xffff; i++) {
 		__save_flags(flags);
@@ -219,6 +222,8 @@
                 }
 		__restore_flags(flags);
 	}
+	printk(KERN_ERR "esssolo1: write_seq timeout\n");
+	outb(data, s->sbbase+0xc);
 }
 
 extern inline int read_seq(struct solo1_state *s, unsigned char *data)
@@ -232,6 +237,7 @@
                         *data = inb(s->sbbase+0xa);
                         return 1;
                 }
+	printk(KERN_ERR "esssolo1: read_seq timeout\n");
         return 0;
 }
 
@@ -1993,6 +1999,12 @@
 			return -ERESTARTSYS;
 		down(&s->open_sem);
 	}
+	if (check_region(s->sbbase, FMSYNTH_EXTENT)) {
+		up(&s->open_sem);
+		printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
+		return -EBUSY;
+	}
+	request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1");
 	/* init the stuff */
 	outb(1, s->sbbase);
 	outb(0x20, s->sbbase+1); /* enable waveforms */
@@ -2020,6 +2032,7 @@
 		outb(regb, s->sbbase+2);
 		outb(0, s->sbbase+3);
 	}
+	release_region(s->sbbase, FMSYNTH_EXTENT);
 	up(&s->open_sem);
 	wake_up(&s->open_wait);
 	MOD_DEC_USE_COUNT;
@@ -2113,14 +2126,14 @@
 		s->gpbase = RSRCADDRESS(pcidev, 4);
 		s->irq = pcidev->irq;
 		if (check_region(s->iobase, IOBASE_EXTENT) ||
-		    check_region(s->sbbase+4, SBBASE_EXTENT-4) ||
+		    check_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT) ||
 		    check_region(s->ddmabase, DDMABASE_EXTENT) ||
 		    check_region(s->mpubase, MPUBASE_EXTENT)) {
 			printk(KERN_ERR "solo1: io ports in use\n");
 			goto err_region;
 		}
 		request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1");
-		request_region(s->sbbase+4, SBBASE_EXTENT-4, "ESS Solo1");  /* allow OPL3 synth module */
+		request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1");
 		request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1");
 		request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1");
 		if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
@@ -2147,6 +2160,10 @@
 		if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0)
 			goto err_dev4;
 		/* initialize the chips */
+		if (!reset_ctrl(s)) {
+			printk(KERN_ERR "esssolo1: cannot reset controller\n");
+			goto err;
+		}
 		outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
 
 		/* initialize mixer regs */
@@ -2181,6 +2198,8 @@
 		index++;
 		continue;
 
+	err:
+		unregister_sound_dsp(s->dev_dmfm);
 	err_dev4:
 		unregister_sound_dsp(s->dev_midi);
 	err_dev3:
@@ -2192,7 +2211,7 @@
 		free_irq(s->irq, s);
 	err_irq:
 		release_region(s->iobase, IOBASE_EXTENT);
-		release_region(s->sbbase+4, SBBASE_EXTENT-4);
+		release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
 		release_region(s->ddmabase, DDMABASE_EXTENT);
 		release_region(s->mpubase, MPUBASE_EXTENT);
 	err_region:
@@ -2222,7 +2241,7 @@
 		pci_write_config_word(s->pcidev, 0x60, 0); /* turn off DDMA controller address space */
 		free_irq(s->irq, s);
 		release_region(s->iobase, IOBASE_EXTENT);
-		release_region(s->sbbase+4, SBBASE_EXTENT-4);
+		release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
 		release_region(s->ddmabase, DDMABASE_EXTENT);
 		release_region(s->mpubase, MPUBASE_EXTENT);
 		unregister_sound_dsp(s->dev_audio);
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.19/linux/drivers/usb/Config.in	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/Config.in	Fri Oct  8 15:47:08 1999
@@ -10,39 +10,43 @@
 
 tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB
 if [ ! "$CONFIG_USB" = "n" ]; then
-  dep_tristate 'UHCI (intel PIIX4 and others) support' CONFIG_USB_UHCI \
+comment 'USB Controllers'
+   dep_tristate '  UHCI (Intel PIIX4 and others) support' CONFIG_USB_UHCI \
 	$CONFIG_USB
-    dep_tristate 'OHCI (compaq and some others) support' CONFIG_USB_OHCI \
+   dep_tristate '  OHCI (Compaq and some others) support' CONFIG_USB_OHCI \
 	$CONFIG_USB
 
-  if [ "$CONFIG_USB_OHCI" != "n" ]; then
-     bool '  Enable tons of OHCI debugging output' CONFIG_USB_OHCI_DEBUG
-  fi
-  dep_tristate 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support' \
+   if [ "$CONFIG_USB_OHCI" != "n" ]; then
+      bool '    Enable tons of OHCI debugging output' CONFIG_USB_OHCI_DEBUG
+   fi
+   dep_tristate '  OHCI-HCD (other OHCI opt. Virt. Root Hub) support' \
 		CONFIG_USB_OHCI_HCD $CONFIG_USB
-  if [ "$CONFIG_USB_OHCI_HCD" != "n" ]; then
-     	bool '  OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
-  fi
+   if [ "$CONFIG_USB_OHCI_HCD" != "n" ]; then
+      bool '    OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
+   fi
 
-  bool 'Enable lots of ISOC debugging output' CONFIG_USB_DEBUG_ISOC
+comment 'Miscellaneous USB options'
+   bool '  Enable lots of ISOC debugging output' CONFIG_USB_DEBUG_ISOC
+   if [ "$CONFIG_PROC_FS" != "n" ]; then
+      bool '  Preliminary /proc/bus/usb support' CONFIG_USB_PROC
+   fi
+   dep_tristate '  EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
 
-  dep_tristate 'USB hub support' CONFIG_USB_HUB $CONFIG_USB
-  dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB
-  dep_tristate 'USB HP scanner support' CONFIG_USB_HP_SCANNER $CONFIG_USB
-  dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
-  dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
-  dep_tristate 'USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
-  dep_tristate 'USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
-  dep_tristate 'USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
-  dep_tristate 'USB SCSI Support' CONFIG_USB_SCSI $CONFIG_USB
-  if [ "$CONFIG_USB_SCSI" != "n" ]; then
-	  dep_tristate '  USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI
-  fi
-  dep_tristate 'EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
-  dep_tristate 'USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
-  if [ "$CONFIG_PROC_FS" != "n" ]; then
-  	bool 'Preliminary /proc/bus/usb support' CONFIG_USB_PROC
-  fi
+comment 'USB Devices'
+   dep_tristate '  USB hub support (Required!)' CONFIG_USB_HUB $CONFIG_USB
+   dep_tristate '  USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB
+   dep_tristate '  USB HP scanner support' CONFIG_USB_HP_SCANNER $CONFIG_USB
+   dep_tristate '  USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
+   dep_tristate '  USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
+   dep_tristate '  USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
+   dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
+   dep_tristate '  USB Belkin and Peracom serial support' CONFIG_USB_SERIAL $CONFIG_USB
+   dep_tristate '  USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
+   dep_tristate '  USB SCSI Support' CONFIG_USB_SCSI $CONFIG_USB
+   if [ "$CONFIG_USB_SCSI" != "n" ]; then
+      bool '    USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG
+   fi
+   dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
 fi
 
 endmenu
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.19/linux/drivers/usb/Makefile	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/Makefile	Thu Oct  7 10:17:09 1999
@@ -97,6 +97,15 @@
   MIX_OBJS += printer.o  
 endif
 
+ifeq ($(CONFIG_USB_SERIAL),y)
+  L_OBJS += serial.o
+endif
+
+ifeq ($(CONFIG_USB_SERIAL),m)
+  M_OBJS += serial.o
+  MIX_OBJS += serial.o  
+endif
+
 ifeq ($(CONFIG_USB_KBD),y)
   L_OBJS += keyboard.o keymap.o
 endif
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/README.ohci linux/drivers/usb/README.ohci
--- v2.3.19/linux/drivers/usb/README.ohci	Fri Jun 25 14:30:28 1999
+++ linux/drivers/usb/README.ohci	Thu Oct  7 10:17:09 1999
@@ -1,5 +1,17 @@
 [This is the readme for ohci.c, ohci-debug.c and ohci.h]
 
+September 05, 1999 17:03:21
+
+I haven't updated this file in a while.  I have started merging good
+ideas from the ohci-hcd driver into this code as well as simplifying
+the code where I can.  Isochronous transfers still need to be ported
+over from ohci-hcd.  Large control and bulk transfers should be
+working much better now.
+
+A big thanks goes to 3Com and APC for donating me a modem and UPS to
+test with!  They aren't working with OHCI quite yet but we hope to
+change that soon.
+
 June 23, 1999 00:31:20 PST
 
 I now have bulk support in a reasonably working state.  The only
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/README.serial linux/drivers/usb/README.serial
--- v2.3.19/linux/drivers/usb/README.serial	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/README.serial	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,35 @@
+This serial driver currently only works with the Belkin and Peracom USB 
+Serial devices. It should also work for the Etek converter, but I do 
+not know the vendor id, and device id of that device (if anyone does, 
+please let me know.)
+
+The driver can handle enumerating the device, and sending and receiving
+data from the converter. However, since I do not have a spec for this
+device, and the raw dumps from the Win98 driver are confusing, no control
+signals are handled, and the data will most likely come through on a baud
+rate that you are not expecting.
+
+But I am working on figuring the control settings out. This release is to
+let others try it out, and give some feedback.
+
+The major number that the driver uses is 240 (in the local/experimental
+range.) It will stay there until some agreements are reached on how to
+handle the configuration problem that USB provides.
+
+To use the driver, create the following nodes:
+mknod /dev/ttyUSB0 c 240 0
+mknod /dev/ttyUSB1 c 240 1
+mknod /dev/ttyUSB2 c 240 2
+mknod /dev/ttyUSB3 c 240 3
+
+then plug in a device and use your friendly terminal program to see what
+happens.
+
+If anyone has any problems getting the device to enumerate, or data to 
+flow through it, please contact me.
+
+
+
+greg k-h
+greg@kroah.com
+
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.19/linux/drivers/usb/acm.c	Fri Sep 10 23:57:35 1999
+++ linux/drivers/usb/acm.c	Thu Oct  7 10:17:09 1999
@@ -1,7 +1,11 @@
 /*
  * USB Abstract Control Model based on Brad Keryan's USB busmouse driver 
  *
- * Armin Fuerst 5/8/1999
+ * Armin Fuerst 5/8/1999 <armin.please@put.your.email.here.!!!!>
+ *
+ * version 0.8: Fixed endianity bug, some cleanups. I really hate to have
+ * half of driver in form if (...) { info("x"); return y; }
+ * 						Pavel Machek <pavel@suse.de>
  *
  * version 0.7: Added usb flow control. Fixed bug in uhci.c (what idiot
  * wrote this code? ...Oops that was me). Fixed module cleanup. Did some
@@ -63,8 +67,8 @@
 #define NR_PORTS 3
 #define ACM_MAJOR 166
 
-#define info(message); printk(message);
-//#define info(message);
+//#define info(message...); printk(message);
+#define info(message...);
 
 #define CTRL_STAT_DTR	1
 #define CTRL_STAT_RTS	2
@@ -94,6 +98,7 @@
 	unsigned ctrlinterval;				//interval to poll from device
 };
 
+#define ACM_READY (acm->present && acm->active)
 
 //functions for various ACM requests
 
@@ -108,7 +113,7 @@
 	dr.value = status;
 	dr.index = 0;
 	dr.length = 0;
-	acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0);
+	acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0, HZ);
 
 	acm->ctrlstate=status;
 }
@@ -124,7 +129,7 @@
 	dr.value = coding;
 	dr.index = 0;
 	dr.length = 0;
-	acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0);
+	acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0, HZ);
 	
 	acm->linecoding=coding;
 }
@@ -139,20 +144,16 @@
 		
 	info("ACM_USB_IRQ\n");
 
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
+	if (!acm->present)
 		return 0;
-	}
-	if (!acm->active) {
-		info ("ACM DEVICE NOT OPEN\n");
+	if (!acm->active)
 		return 1;
-	}
        
         dr=__buffer;
 	data=__buffer;
 	data+=sizeof(dr);
  
-#if 1
+#if 0
         printk("reqtype: %02X\n",dr->requesttype);
         printk("request: %02X\n",dr->request);
 	printk("wValue: %02X\n",dr->value);
@@ -161,31 +162,26 @@
 #endif
 	
 	switch(dr->request) {
-	  //Network connection 
-	  case 0x00:
-	    printk("Network connection: ");
-	    if (dr->request==0) info("disconnected\n");
-	    if (dr->request==1) info("connected\n");
-	    break;
+	case 0x00: /* Network connection */
+		printk("Network connection: ");
+		if (dr->request==0) printk("disconnected\n");
+		if (dr->request==1) printk("connected\n");
+		break;
 	    
-    	  //Response available
-	  case 0x01:
-	    printk("Response available\n");
-	    break;
-	
-	  //Set serial line state
-	  case 0x20:
-	    printk("Set serial control line state\n");
-	    if ((dr->index==1)&&(dr->length==2)) {
-	      acm->ctrlstate=* ((unsigned short int *)data);
-	      printk("Serstate: %02X\n",acm->ctrlstate);
-	    }
-	    break;
-	}
-
-	//info("Done\n");
-	//Continue transfer
-	return 1;
+	case 0x01: /* Response available */
+		printk("Response available\n");
+		break;
+	
+	case 0x20: /* Set serial line state */
+		printk("acm.c: Set serial control line state\n");
+		if ((dr->index==1)&&(dr->length==2)) {
+			acm->ctrlstate= data[0] || (data[1] << 16);
+			printk("Serstate: %02X\n",acm->ctrlstate);
+		}
+		break;
+	}
+
+	return 1; /* Continue transfer */
 }
 
 static int acm_read_irq(int state, void *__buffer, int count, void *dev_id)
@@ -195,29 +191,20 @@
        	unsigned char* data=__buffer;
 	int i;
 
-	info("ACM_READ_IRQ\n");
-	
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
-		//Stop transfer
-		return 0;
-	}
-
-	if (!acm->active) {
-		info ("ACM DEVICE NOT OPEN\n");
-		//Stop transfer
-		return 0;
+	info("ACM_READ_IRQ: state %d, %d bytes\n", state, count);
+	if (state) {
+		printk( "acm_read_irq: strange state received: %x\n", state );
+		return 1;
 	}
+	
+	if (!ACM_READY)
+		return 0;	/* stop transfer */
 
-//	printk("%d %s\n",count,data);
-	for (i=0;i<count;i++) {
-		 tty_insert_flip_char(tty,data[i],0);
-  	}
+	for (i=0;i<count;i++)
+		tty_insert_flip_char(tty,data[i],0);
   	tty_flip_buffer_push(tty);
-  	
-	//info("Done\n");
-  	//Continue transfer
-	return 1;
+
+	return 1; /* continue transfer */
 }
 
 static int acm_write_irq(int state, void *__buffer, int count, void *dev_id)
@@ -227,16 +214,8 @@
 
 	info("ACM_WRITE_IRQ\n");
 
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
-		//Stop transfer
-		return 0;
-	}
-	if (!acm->active) {
-		info ("ACM DEVICE NOT OPEN\n");
-		//Stop transfer
-		return 0;
-	}
+	if (!ACM_READY)
+		return 0; /* stop transfer */
 
 	usb_terminate_bulk(acm->dev, acm->writetransfer);
 	acm->writing=0;
@@ -244,9 +223,7 @@
 		(tty->ldisc.write_wakeup)(tty);
 	wake_up_interruptible(&tty->write_wait);
 	
-	//info("Done\n");
-	//Stop transfer
-	return 0;
+	return 0; /* stop tranfer */
 }
 
 /*TTY STUFF*/
@@ -260,22 +237,16 @@
 	tty->driver_data=acm=&acm_state_table[MINOR(tty->device)-tty->driver.minor_start];
 	acm->tty=tty;
 	 
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
+	if (!acm->present)
 		return -EINVAL;
-	}
 
-	if (acm->active) {
-		info ("ACM DEVICE ALREADY OPEN\n");
-		return -EINVAL;
-	}
-	acm->active=1;
+	if (acm->active++)
+		return 0;
  
-	/*Start reading from the device*/
+	/* Start reading from the device */
 	ret = usb_request_irq(acm->dev,acm->ctrlpipe, acm_irq, acm->ctrlinterval, acm, &acm->ctrltransfer);
-	if (ret) {
+	if (ret)
 		printk (KERN_WARNING "usb-acm: usb_request_irq failed (0x%x)\n", ret);
-	}
 	acm->reading=1;
 	acm->readtransfer=usb_request_bulk(acm->dev,acm->readpipe, acm_read_irq, acm->readbuffer, acm->readsize, acm);
 	
@@ -289,15 +260,11 @@
 	struct acm_state *acm = (struct acm_state *) tty->driver_data; 
 	info("rs_close\n");
 	
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
+	if (!acm->present)
 		return;
-	}
 
-	if (!acm->active) {
-		info ("ACM DEVICE NOT OPEN\n");
+	if (--acm->active)
 		return;
-	}
 
 	Set_Control_Line_Status (0, acm);
 	
@@ -309,9 +276,7 @@
 		usb_terminate_bulk(acm->dev, acm->readtransfer);
 		acm->reading=0;
 	}
-//  usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
-	
-	acm->active=0;
+//	usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
 }
 
 static int rs_write(struct tty_struct * tty, int from_user,
@@ -322,15 +287,8 @@
 	
 	info("rs_write\n");
 
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
-		return -EINVAL;
-	}
-
-	if (!acm->active) {
-		info ("ACM DEVICE NOT OPEN\n");
+	if (!ACM_READY)
 		return -EINVAL;
-	}
 	
 	if (acm->writing) {
 		info ("already writing\n");
@@ -339,14 +297,8 @@
 
 	written=(count>acm->writesize) ? acm->writesize : count;
 	  
-	if (from_user) {
-		//info("fromuser\n");
-		copy_from_user(acm->writebuffer,buf,written);
-	}
-	else {
-		//info("notfromuser\n");
-		memcpy(acm->writebuffer,buf,written);
-	}  
+	if (from_user) copy_from_user(acm->writebuffer,buf,written);
+	else	       memcpy(acm->writebuffer,buf,written);
 
 	//start the transfer
 	acm->writing=1;
@@ -359,18 +311,8 @@
 {
 	struct acm_state *acm = (struct acm_state *) tty->driver_data; 
 	
-	info("rs_put_char\n");
-	
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
-		return;
-	}
-
-	if (!acm->active) {
-		info ("ACM DEVICE NOT OPEN\n");
-		return;
-	}
-//  printk("%c\n",ch);
+	printk( "acm: rs_put_char: Who called this unsupported routine?\n" );
+	BUG();
 }                   
 
 static int rs_write_room(struct tty_struct *tty) 
@@ -379,42 +321,22 @@
 
 	info("rs_write_room\n");
 	
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
+	if (!ACM_READY)
 		return -EINVAL;
-	}
-
-	if (!acm->active) {
-		info ("ACM DEVICE NOT OPEN\n");
-		return -EINVAL;
-	}
 	
-	if (acm->writing) {
-		return 0;
-	}
-	return acm->writesize;
+	return acm->writing ? 0 : acm->writesize;
 }
 
 static int rs_chars_in_buffer(struct tty_struct *tty) 
 {
 	struct acm_state *acm = (struct acm_state *) tty->driver_data; 
 
-	info("rs_chars_in_buffer\n");
+//	info("rs_chars_in_buffer\n");
 	
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
-		return -EINVAL;
-	}
-
-	if (!acm->active) {
-		info ("ACM DEVICE NOT OPEN\n");
+	if (!ACM_READY)
 		return -EINVAL;
-	}
 	
-	if (acm->writing) {
-		return acm->writesize;
-	}
-	return 0;
+	return acm->writing ? acm->writesize :  0;
 }
 
 static void rs_throttle(struct tty_struct * tty)
@@ -423,21 +345,12 @@
 	
 	info("rs_throttle\n");
 	
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
-		return;
-	}
-
-	if (!acm->active) {
-		info ("ACM DEVICE NOT OPEN\n");
+	if (!ACM_READY)
 		return;
-	}
-
 /*	
 	if (I_IXOFF(tty))
 		rs_send_xchar(tty, STOP_CHAR(tty));
 */    
-
 	if (tty->termios->c_cflag & CRTSCTS)
 		Set_Control_Line_Status (acm->ctrlstate & ~CTRL_STAT_RTS, acm);
 }
@@ -448,21 +361,12 @@
 	
 	info("rs_unthrottle\n");
 	
-	if (!acm->present) {
-		info("NO ACM DEVICE REGISTERED\n");
+	if (!ACM_READY)
 		return;
-	}
-
-	if (!acm->active) {
-		info ("ACM DEVICE NOT OPEN\n");
-		return;
-	}
-
 /*	
 	if (I_IXOFF(tty))
 		rs_send_xchar(tty, STOP_CHAR(tty));
 */    
-
 	if (tty->termios->c_cflag & CRTSCTS)
 		Set_Control_Line_Status (acm->ctrlstate | CTRL_STAT_RTS, acm);
 }
@@ -521,7 +425,8 @@
 		    interface->bNumEndpoints != 2)
 			continue;
 
-		if ((endpoint->bEndpointAddress & 0x80) == 0x80)
+		endpoint = &interface->endpoint[0];
+		if ((endpoint->bEndpointAddress & 0x80) != 0x80)
 			swapped = 1;
 
 		/*With a bulk input */
@@ -578,10 +483,8 @@
 
 	info("acm_disconnect\n");
 	
-	if (!acm->present) {
-		printk("device not present\n");
+	if (!acm->present)
 		return;
-	}
 
 	printk("disconnecting\n");
 	
@@ -593,7 +496,7 @@
 		usb_terminate_bulk(acm->dev, acm->readtransfer);
 		acm->reading=0;
 	}
-//  usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
+	usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
 	//BUG: What to do if a device is open?? Notify process or not allow cleanup?
 	acm->active=0;
 	acm->present=0;
@@ -643,9 +546,9 @@
 	acm_tty_driver.open = rs_open;
 	acm_tty_driver.close = rs_close;
 	acm_tty_driver.write = rs_write;
-	acm_tty_driver.put_char = rs_put_char; //FUCKIN BUG IN DOKU!!!
+	acm_tty_driver.put_char = rs_put_char;
 	acm_tty_driver.flush_chars = NULL; //rs_flush_chars;
-	acm_tty_driver.write_room = rs_write_room; //ANBOTHER FUCKIN BUG!!
+	acm_tty_driver.write_room = rs_write_room;
 	acm_tty_driver.ioctl = NULL; //rs_ioctl;
 	acm_tty_driver.set_termios = NULL; //rs_set_termios;
 	acm_tty_driver.set_ldisc = NULL; 
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.3.19/linux/drivers/usb/audio.c	Fri Sep 10 23:57:35 1999
+++ linux/drivers/usb/audio.c	Thu Oct  7 10:17:09 1999
@@ -1,25 +1,2495 @@
+/*****************************************************************************/
+
+/*
+ *      audio.c  --  USB Audio Class driver
+ *
+ *      Copyright (C) 1999
+ *          Alan Cox (alan@lxorguk.ukuu.org.uk)
+ *          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.
+ *
+ *
+ * 1999-09-07:  Alan Cox
+ *              Parsing Audio descriptor patch
+ * 1999-09-08:  Thomas Sailer
+ *              Added OSS compatible data io functions; both parts of the
+ *              driver remain to be glued together
+ * 1999-09-10:  Thomas Sailer
+ *              Beautified the driver. Added sample format conversions.
+ *              Still not properly glued with the parsing code.
+ *              The parsing code seems to have its problems btw,
+ *              Since it parses all available configs but doesn't
+ *              store which iface/altsetting belongs to which config.
+ * 1999-09-20:  Thomas Sailer
+ *              Threw out Alan's parsing code and implemented my own one.
+ *              You cannot reasonnably linearly parse audio descriptors,
+ *              especially the AudioClass descriptors have to be considered
+ *              pointer lists. Mixer parsing untested, due to lack of device.
+ *              First stab at synch pipe implementation, the Dallas USB DAC
+ *              wants to use an Asynch out pipe. usb_audio_state now basically
+ *              only contains lists of mixer and wave devices. We can therefore
+ *              now have multiple mixer/wave devices per USB device.
+ *
+ */
+
+/*
+ * Strategy:
+ *
+ * Alan Cox and Thomas Sailer are starting to dig at opposite ends and
+ * are hoping to meet in the middle, just like tunnel diggers :)
+ * Alan tackles the descriptor parsing, Thomas the actual data IO and the
+ * OSS compatible interface.
+ *
+ * Data IO implementation issues
+ *
+ * A mmap'able ring buffer per direction is implemented, because
+ * almost every OSS app expects it. It is however impractical to
+ * transmit/receive USB data directly into and out of the ring buffer,
+ * due to alignment and synchronisation issues. Instead, the ring buffer
+ * feeds a constant time delay line that handles the USB issues.
+ *
+ * Now we first try to find an alternate setting that exactly matches
+ * the sample format requested by the user. If we find one, we do not
+ * need to perform any sample rate conversions. If there is no matching
+ * altsetting, we choose the closest one and perform sample format
+ * conversions. We never do sample rate conversion; these are too
+ * expensive to be performed in the kernel.
+ *
+ * Current status:
+ * - The IO code seems to work a couple of frames, but then gets
+ *   UHCI into a "complaining" mode, i.e. uhci won't work again until
+ *   removed and reloaded, it will not even notice disconnect/reconnect
+ *   events.
+ *   It seems to work more stably on OHCI-HCD.
+ *
+ * Generally: Due to the brokenness of the Audio Class spec
+ * it seems generally impossible to write a generic Audio Class driver,
+ * so a reasonable driver should implement the features that are actually
+ * used.
+ *
+ * Parsing implementation issues
+ *
+ * One cannot reasonably parse the AudioClass descriptors linearly.
+ * Therefore the current implementation features routines to look
+ * for a specific descriptor in the descriptor list.
+ *
+ * How does the parsing work? First, all interfaces are searched
+ * for an AudioControl class interface. If found, the config descriptor
+ * that belongs to the current configuration is fetched from the device.
+ * Then the HEADER descriptor is fetched. It contains a list of
+ * all AudioStreaming and MIDIStreaming devices. This list is then walked,
+ * and all AudioStreaming interfaces are classified into input and output
+ * interfaces (according to the endpoint0 direction in altsetting1) (MIDIStreaming
+ * is currently not supported). The input & output list is then used
+ * to group inputs and outputs together and issued pairwise to the
+ * AudioStreaming class parser. Finally, all OUTPUT_TERMINAL descriptors
+ * are walked and issued to the mixer construction routine.
+ *
+ * The AudioStreaming parser simply enumerates all altsettings belonging
+ * to the specified interface. It looks for AS_GENERAL and FORMAT_TYPE
+ * class specific descriptors to extract the sample format/sample rate
+ * data. Only sample format types PCM and PCM8 are supported right now, and
+ * only FORMAT_TYPE_I is handled. The isochronous data endpoint needs to
+ * be the first endpoint of the interface, and the optional synchronisation
+ * isochronous endpoint the second one.
+ *
+ * Mixer construction works as follows: The various TERMINAL and UNIT
+ * descriptors span a tree from the root (OUTPUT_TERMINAL) through the
+ * intermediate nodes (UNITs) to the leaves (INPUT_TERMINAL). We walk
+ * that tree in a depth first manner. FEATURE_UNITs may contribute volume,
+ * bass and treble sliders to the mixer, MIXER_UNITs volume sliders.
+ * The terminal type encoded in the INPUT_TERMINALs feeds a heuristic
+ * to determine "meaningful" OSS slider numbers, however we will see
+ * how well this works in practice. Other features are not used at the
+ * moment, they seem less often used. Also, it seems difficult at least
+ * to construct recording source switches from SELECTOR_UNITs, but
+ * since there are not many USB ADC's available, we leave that for later.
+ */
+
+/*****************************************************************************/
+
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
 #include <linux/module.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/wrapper.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/spinlock.h>
+
+#include "usb.h"
+#include "audio.h"
+
+#define AUDIO_DEBUG 1
+
+#define SND_DEV_DSP16   5 
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Linked list of all audio devices...
+ */
+static struct list_head audiodevs = LIST_HEAD_INIT(audiodevs);
+static DECLARE_MUTEX(open_sem);
+
+/*
+ * wait queue for processes wanting to open an USB audio device
+ */
+static DECLARE_WAIT_QUEUE_HEAD(open_wait);
+
+
+#define MAXFORMATS        MAX_ALT
+#define DMABUFSHIFT       17  /* 128k worth of DMA buffer */
+#define NRSGBUF           (1U<<(DMABUFSHIFT-PAGE_SHIFT))
+
+/*
+ * This influences:
+ * - Latency
+ * - Interrupt rate
+ * - Synchronisation behaviour
+ * Don't touch this if you don't understand all of the above.
+ */
+#define DESCFRAMES  4
+
+#define MIXFLG_STEREOIN   1
+#define MIXFLG_STEREOOUT  2
+
+struct mixerchannel {
+	__u16 value;
+	__u16 osschannel;  /* number of the OSS channel */
+	__s16 minval, maxval;
+	__u8 unitid;
+	__u8 selector;
+	__u8 chnum;
+	__u8 flags;
+};
+
+struct audioformat {
+	unsigned int format;
+	unsigned int sratelo;
+	unsigned int sratehi;
+	unsigned char altsetting;
+};
+
+struct dmabuf {
+	/* buffer data format */
+	unsigned int format;
+	unsigned int srate;
+	/* physical buffer */
+	unsigned char *sgbuf[NRSGBUF];
+	unsigned bufsize;
+	unsigned numfrag;
+	unsigned fragshift;
+	unsigned wrptr, rdptr;
+	unsigned total_bytes;
+	int count;
+	unsigned error; /* over/underrun */
+	wait_queue_head_t wait;
+	/* redundant, but makes calculations easier */
+	unsigned fragsize;
+	unsigned dmasize;
+	/* OSS stuff */
+	unsigned mapped:1;
+	unsigned ready:1;
+	unsigned ossfragshift;
+	int ossmaxfrags;
+	unsigned subdivision;
+};
+
+struct usb_audio_state;
+
+#define FLG_NEXTID        1
+#define FLG_ID0RUNNING    2
+#define FLG_ID1RUNNING    4
+#define FLG_SYNCNEXTID    8
+#define FLG_SYNC0RUNNING 16
+#define FLG_SYNC1RUNNING 32
+#define FLG_RUNNING      64
+
+struct usb_audiodev {
+	struct list_head list;
+	struct usb_audio_state *state;
+
+        /* soundcore stuff */
+        int dev_audio;
+
+	/* wave stuff */
+        mode_t open_mode;
+	spinlock_t lock;         /* DMA buffer access spinlock */
+
+	struct usbin {
+		unsigned int interface;  /* Interface number */
+		unsigned int format;     /* USB data format */
+		unsigned int datapipe;   /* the data input pipe */
+		unsigned int syncpipe;   /* the synchronisation pipe - 0 for anything but adaptive IN mode */
+		unsigned int syncinterval;  /* P for adaptive IN mode, 0 otherwise */
+		unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+		unsigned int phase;      /* phase accumulator */
+		unsigned int flags;      /* see FLG_ defines */
+
+		struct usb_isoc_desc *dataiso[2];   /* ISO descriptors for the data endpoint */
+		unsigned char *data[2];             /* data pages associated with the ISO descriptors */
+
+		struct usb_isoc_desc *synciso[2];   /* ISO sync pipe descriptor if needed */
+		unsigned char *syncdata[2];         /* data page for sync data */
+
+		struct dmabuf dma;
+	} usbin;
+
+	struct usbout {
+		unsigned int interface;  /* Interface number */
+		unsigned int format;     /* USB data format */
+		unsigned int datapipe;   /* the data input pipe */
+		unsigned int syncpipe;   /* the synchronisation pipe - 0 for anything but asynchronous OUT mode */
+		unsigned int syncinterval;  /* P for asynchronous OUT mode, 0 otherwise */
+		unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+		unsigned int freqm;      /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+		unsigned int phase;      /* phase accumulator */
+		unsigned int flags;      /* see FLG_ defines */
+
+		struct usb_isoc_desc *dataiso[2];   /* ISO descriptors for the data endpoint */
+		unsigned char *data[2];             /* data pages associated with the ISO descriptors */
+
+		struct usb_isoc_desc *synciso[2];   /* ISO sync pipe descriptor if needed */
+		unsigned char *syncdata[2];         /* data page for sync data */
+
+		struct dmabuf dma;
+	} usbout;
+
+
+	unsigned int numfmtin, numfmtout;
+	struct audioformat fmtin[MAXFORMATS];
+	struct audioformat fmtout[MAXFORMATS];
+};  
+
+struct usb_mixerdev {
+	struct list_head list;
+	struct usb_audio_state *state;
+
+        /* soundcore stuff */
+        int dev_mixer;
+
+	unsigned char iface;  /* interface number of the AudioControl interface */
+
+	/* USB format descriptions */
+        unsigned int numch, modcnt;
+
+	/* mixch is last and gets allocated dynamically */
+	struct mixerchannel ch[0];
+};
+
+struct usb_audio_state {
+	struct list_head audiodev;
+
+	/* USB device */
+	struct usb_device *usbdev;
+
+	struct list_head audiolist;
+	struct list_head mixerlist;
+
+	unsigned count;  /* usage counter; NOTE: the usb stack is also considered a user */
+};
+
+/* private audio format extensions */
+#define AFMT_STEREO        0x80000000
+#define AFMT_ISSTEREO(x)   ((x) & AFMT_STEREO)
+#define AFMT_IS16BIT(x)    ((x) & (AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE))
+#define AFMT_ISUNSIGNED(x) ((x) & (AFMT_U8|AFMT_U16_LE|AFMT_U16_BE))
+#define AFMT_BYTESSHIFT(x) ((AFMT_ISSTEREO(x) ? 1 : 0) + (AFMT_IS16BIT(x) ? 1 : 0))
+#define AFMT_BYTES(x)      (1<<AFMT_BYTESSHFIT(x))
+
+/* --------------------------------------------------------------------- */
+
+extern inline unsigned ld2(unsigned int x)
+{
+        unsigned r = 0;
+        
+        if (x >= 0x10000) {
+                x >>= 16;
+                r += 16;
+        }
+        if (x >= 0x100) {
+                x >>= 8;
+                r += 8;
+        }
+        if (x >= 0x10) {
+                x >>= 4;
+                r += 4;
+        }
+        if (x >= 4) {
+                x >>= 2;
+                r += 2;
+        }
+        if (x >= 2)
+                r++;
+        return r;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * OSS compatible ring buffer management. The ring buffer may be mmap'ed into
+ * an application address space.
+ *
+ * I first used the rvmalloc stuff copied from bttv. Alan Cox did not like it, so
+ * we now use an array of pointers to a single page each. This saves us the
+ * kernel page table manipulations, but we have to do a page table alike mechanism
+ * (though only one indirection) in software.
+ */
+
+static void dmabuf_release(struct dmabuf *db)
+{
+	unsigned int nr;
+	void *p;
+
+	for(nr = 0; nr < NRSGBUF; nr++) {
+		if (!(p = db->sgbuf[nr]))
+			continue;
+		mem_map_unreserve(MAP_NR(p));
+		free_page((unsigned long)p);
+		db->sgbuf[nr] = NULL;
+	}
+        db->mapped = db->ready = 0;
+}
+
+static int dmabuf_init(struct dmabuf *db)
+{
+        unsigned int nr, bytepersec, bufs;
+	void *p;
+
+	/* initialize some fields */
+        db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0;
+	/* calculate required buffer size */
+	bytepersec = db->srate << AFMT_BYTESSHIFT(db->format);
+	bufs = 1U << DMABUFSHIFT;
+        if (db->ossfragshift) {
+                if ((1000 << db->ossfragshift) < bytepersec)
+                        db->fragshift = ld2(bytepersec/1000);
+                else
+                        db->fragshift = db->ossfragshift;
+        } else {
+                db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
+                if (db->fragshift < 3)
+                        db->fragshift = 3;
+        }
+        db->numfrag = bufs >> db->fragshift;
+        while (db->numfrag < 4 && db->fragshift > 3) {
+                db->fragshift--;
+                db->numfrag = bufs >> db->fragshift;
+        }
+        db->fragsize = 1 << db->fragshift;
+        if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+                db->numfrag = db->ossmaxfrags;
+        db->dmasize = db->numfrag << db->fragshift;
+	for(nr = 0; nr < NRSGBUF; nr++) {
+		if (!db->sgbuf[nr]) {
+			p = (void *)get_free_page(GFP_KERNEL);
+			if (!p)
+				return -ENOMEM;
+			db->sgbuf[nr] = p;
+			mem_map_reserve(MAP_NR(p));
+		}
+		memset(db->sgbuf[nr], AFMT_ISUNSIGNED(db->format) ? 0x80 : 0, PAGE_SIZE);
+		if ((nr << PAGE_SHIFT) >= db->dmasize)
+			break;
+	}
+	db->bufsize = nr << PAGE_SHIFT;
+        db->ready = 1;
+	printk(KERN_DEBUG "dmabuf_init: bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
+	       "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d\n",
+	       bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize,
+	       db->numfrag, db->dmasize, db->bufsize);
+        return 0;
+}
+
+static int dmabuf_mmap(struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot)
+{
+	unsigned int nr;
+
+	if (!db->ready || db->mapped || (start | size) & (PAGE_SIZE-1) || size > db->bufsize)
+		return -EINVAL;
+	size >>= PAGE_SHIFT;
+	for(nr = 0; nr < size; nr++)
+		if (!db->sgbuf[nr])
+			return -EINVAL;
+	db->mapped = 1;
+	for(nr = 0; nr < size; nr++) {
+		if (remap_page_range(start, virt_to_phys(db->sgbuf[nr]), PAGE_SIZE, prot))
+			return -EAGAIN;
+		start += PAGE_SIZE;
+	}
+	return 0;
+}
+
+static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int size)
+{
+	unsigned int pgrem, rem;
+
+	for (;;) {
+		if (size <= 0)
+			return;
+		pgrem = ((~db->wrptr) & (PAGE_SIZE-1)) + 1;
+		if (pgrem > size)
+			pgrem = size;
+		rem = db->dmasize - db->wrptr;
+		if (pgrem > rem)
+			pgrem = rem;
+		memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem);
+		size -= pgrem;
+		(char *)buffer += pgrem;
+		db->wrptr += pgrem;
+		if (db->wrptr >= db->dmasize)
+			db->wrptr = 0;
+	}
+}
+
+static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size)
+{
+	unsigned int pgrem, rem;
+
+	for (;;) {
+		if (size <= 0)
+			return;
+		pgrem = ((~db->rdptr) & (PAGE_SIZE-1)) + 1;
+		if (pgrem > size)
+			pgrem = size;
+		rem = db->dmasize - db->rdptr;
+		if (pgrem > rem)
+			pgrem = rem;
+		memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem);
+		size -= pgrem;
+		(char *)buffer += pgrem;
+		db->rdptr += pgrem;
+		if (db->rdptr >= db->dmasize)
+			db->rdptr = 0;
+	}
+}
+
+static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *buffer, unsigned int size)
+{
+	unsigned int pgrem, rem;
+
+	if (!db->ready || db->mapped)
+		return -EINVAL;
+	for (;;) {
+		if (size <= 0)
+			return 0;
+		pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
+		if (pgrem > size)
+			pgrem = size;
+		rem = db->dmasize - ptr;
+		if (pgrem > rem)
+			pgrem = rem;
+		copy_from_user_ret((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem, -EFAULT);
+		size -= pgrem;
+		(char *)buffer += pgrem;
+		ptr += pgrem;
+		if (ptr >= db->dmasize)
+			ptr = 0;
+	}
+}
+
+static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *buffer, unsigned int size)
+{
+	unsigned int pgrem, rem;
+
+	if (!db->ready || db->mapped)
+		return -EINVAL;
+	for (;;) {
+		if (size <= 0)
+			return 0;
+		pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
+		if (pgrem > size)
+			pgrem = size;
+		rem = db->dmasize - ptr;
+		if (pgrem > rem)
+			pgrem = rem;
+		copy_to_user_ret(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem, -EFAULT);
+		size -= pgrem;
+		(char *)buffer += pgrem;
+		ptr += pgrem;
+		if (ptr >= db->dmasize)
+			ptr = 0;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * USB I/O code. We do sample format conversion if necessary
+ */
+
+static void usbin_stop(struct usb_audiodev *as)
+{
+	struct usbin *u = &as->usbin;
+        unsigned long flags;
+	unsigned int i;
+
+        spin_lock_irqsave(&as->lock, flags);
+	u->flags &= ~FLG_RUNNING;
+	i = u->flags;
+        spin_unlock_irqrestore(&as->lock, flags);
+	while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
+		schedule_timeout(1);
+		spin_lock_irqsave(&as->lock, flags);
+		i = u->flags;
+		spin_unlock_irqrestore(&as->lock, flags);
+	}
+	if (u->dataiso[0])
+		usb_free_isoc(u->dataiso[0]);
+	if (u->dataiso[1])
+		usb_free_isoc(u->dataiso[1]);
+	if (u->synciso[0])
+		usb_free_isoc(u->synciso[0]);
+	if (u->synciso[1])
+		usb_free_isoc(u->synciso[1]);
+	u->dataiso[0] = u->dataiso[1] = u->synciso[0] = u->synciso[1] = NULL;
+}
+
+static void usbin_release(struct usb_audiodev *as)
+{
+	struct usbin *u = &as->usbin;
+
+	usbin_stop(as);
+	if (u->data[0])
+		free_page((unsigned long)u->data[0]);
+	if (u->data[1])
+		free_page((unsigned long)u->data[1]);
+	if (u->syncdata[0])
+		free_page((unsigned long)u->syncdata[0]);
+	if (u->syncdata[1])
+		free_page((unsigned long)u->syncdata[1]);
+	u->data[0] = u->data[1] = u->syncdata[0] = u->syncdata[1] = NULL;
+}
+
+static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
+{
+	union {
+		__s16 s[64];
+		unsigned char b[0];
+	} tmp;
+	unsigned int scnt, maxs, ufmtsh, dfmtsh, cnt, i;
+	__s16 *sp, *sp2, s;
+	unsigned char *bp;
+
+	ufmtsh = AFMT_BYTESSHIFT(u->format);
+	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
+	while (samples > 0) {
+		scnt = samples;
+		if (scnt > maxs)
+			scnt = maxs;
+		cnt = scnt;
+		if (AFMT_ISSTEREO(u->format))
+			cnt <<= 1;
+		sp = tmp.s + cnt;
+		switch (u->format & ~AFMT_STEREO) {
+		case AFMT_U8:
+			for (bp = buffer+cnt, i = 0; i < cnt; i++) {
+				bp--;
+				sp--;
+				*sp = (*bp ^ 0x80) << 8;
+			}
+			break;
+
+		case AFMT_S8:
+			for (bp = buffer+cnt, i = 0; i < cnt; i++) {
+				bp--;
+				sp--;
+				*sp = *bp << 8;
+			}
+			break;
+
+		case AFMT_U16_LE:
+			for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
+				bp -= 2;
+				sp--;
+				*sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
+			}
+			break;
+
+		case AFMT_U16_BE:
+			for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
+				bp -= 2;
+				sp--;
+				*sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
+			}
+			break;
+
+		case AFMT_S16_LE:
+			for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
+				bp -= 2;
+				sp--;
+				*sp = bp[0] | (bp[1] << 8);
+			}
+			break;
+
+		case AFMT_S16_BE:
+			for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
+				bp -= 2;
+				sp--;
+				*sp = bp[1] | (bp[0] << 8);
+			}
+			break;
+		}
+		if (!AFMT_ISSTEREO(u->format) && AFMT_ISSTEREO(u->dma.format)) {
+			/* expand from mono to stereo */
+			for (sp = tmp.s+scnt, sp2 = tmp.s+2*scnt, i = 0; i < scnt; i++) {
+				sp--;
+				sp2 -= 2;
+				sp2[0] = sp2[1] = sp[0];
+			}
+		}
+		if (AFMT_ISSTEREO(u->format) && !AFMT_ISSTEREO(u->dma.format)) {
+			/* contract from stereo to mono */
+			for (sp = sp2 = tmp.s, i = 0; i < scnt; i++, sp++, sp2 += 2)
+				sp[0] = (sp2[0] + sp2[1]) >> 1;
+		}
+		cnt = scnt;
+		if (AFMT_ISSTEREO(u->dma.format))
+			cnt <<= 1;
+		sp = tmp.s;
+		bp = tmp.b;
+		switch (u->dma.format & ~AFMT_STEREO) {
+		case AFMT_U8:
+			for (i = 0; i < cnt; i++, sp++, bp++)
+				*bp = (*sp >> 8) ^ 0x80;
+			break;
+
+		case AFMT_S8:
+			for (i = 0; i < cnt; i++, sp++, bp++)
+				*bp = *sp >> 8;
+			break;
+
+		case AFMT_U16_LE:
+			for (i = 0; i < cnt; i++, sp++, bp += 2) {
+				s = *sp;
+				bp[0] = s;
+				bp[1] = (s >> 8) ^ 0x80;
+			}
+			break;
+
+		case AFMT_U16_BE:
+			for (i = 0; i < cnt; i++, sp++, bp += 2) {
+				s = *sp;
+				bp[1] = s;
+				bp[0] = (s >> 8) ^ 0x80;
+			}
+			break;
+
+		case AFMT_S16_LE:
+			for (i = 0; i < cnt; i++, sp++, bp += 2) {
+				s = *sp;
+				bp[0] = s;
+				bp[1] = s >> 8;
+			}
+			break;
+
+		case AFMT_S16_BE:
+			for (i = 0; i < cnt; i++, sp++, bp += 2) {
+				s = *sp;
+				bp[1] = s;
+				bp[0] = s >> 8;
+			}
+			break;
+		}
+		dmabuf_copyin(&u->dma, tmp.b, scnt << dfmtsh);
+		buffer += scnt << ufmtsh;
+		samples -= scnt;
+	}
+}		
+
+static int usbin_prepare_desc(struct usbin *u, struct usb_isoc_desc *id)
+{
+	unsigned int i, maxsize;
+
+	maxsize = (u->freqn + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
+	printk(KERN_DEBUG "usbin_prepare_desc: maxsize %d freq 0x%x format 0x%x\n", maxsize, u->freqn, u->format);
+	for (i = 0; i < DESCFRAMES; i++)
+		id->frames[i].frame_length = maxsize;
+	return 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ * convert sample format on the fly if necessary
+ */
+static int usbin_retire_desc(struct usbin *u, struct usb_isoc_desc *id)
+{
+	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree, maxsize;
+	unsigned char *cp = id->data;
+
+	ufmtsh = AFMT_BYTESSHIFT(u->format);
+	maxsize = (u->freqn + 0x3fff) >> (14 - ufmtsh);
+	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+	for (i = 0; i < DESCFRAMES; i++, cp += maxsize) {
+		if (id->frames[i].frame_status) {
+			printk(KERN_DEBUG "usbin_retire_desc: frame %u status %d\n", i, id->frames[i].frame_status);
+			continue;
+		}
+		scnt = id->frames[i].frame_length >> ufmtsh;
+		if (!scnt)
+			continue;
+		cnt = scnt << dfmtsh;
+		if (!u->dma.mapped) {
+			dmafree = u->dma.dmasize - u->dma.count;
+			if (cnt > dmafree) {
+				scnt = dmafree >> dfmtsh;
+				cnt = scnt << dfmtsh;
+				err++;
+			}
+		}
+		u->dma.count += cnt;
+		if (u->format == u->dma.format) {
+			/* we do not need format conversion */
+			dmabuf_copyin(&u->dma, cp, cnt);
+		} else {
+			/* we need sampling format conversion */
+			usbin_convert(u, cp, scnt);
+		}
+	}
+	if (err)
+		u->dma.error++;
+	if (u->dma.count >= (signed)u->dma.fragsize)
+		wake_up(&u->dma.wait);
+	return err ? -1 : 0;
+}
+
+static int usbin_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 0
+        struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+        struct usb_audiodev *as = (struct usb_audiodev *)id->context;
+#else
+        struct usb_audiodev *as = (struct usb_audiodev *)dev_id;
+        struct usb_isoc_desc *id;
+#endif
+	struct usbin *u = &as->usbin;
+	unsigned int next, idmask;
+
+	printk(KERN_DEBUG "usbin_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
+	spin_lock(&as->lock);
+	next = !(u->flags & FLG_NEXTID);
+	idmask = FLG_ID1RUNNING >> next;
+	u->flags = (u->flags & ~(FLG_NEXTID | idmask)) | next;
+	id = u->dataiso[!next];
+	if (!usbin_retire_desc(u, id) &&
+	    u->flags & FLG_RUNNING &&
+	    !usbin_prepare_desc(u, id) && 
+	    !usb_run_isoc(id, u->dataiso[next])) {
+		u->flags |= idmask;
+	} else {
+		u->flags &= ~FLG_RUNNING;
+		printk(KERN_DEBUG "usbin_completed: descriptor not restarted\n");
+	}
+	spin_unlock(&as->lock);
+	return 0;
+}
+
+/*
+ * we output sync data
+ */
+static int usbin_sync_prepare_desc(struct usbin *u, struct usb_isoc_desc *id)
+{
+	unsigned char *cp = id->data;
+	unsigned int i;
+
+	for (i = 0; i < DESCFRAMES; i++, cp += 3) {
+		id->frames[i].frame_length = 3;
+		cp[0] = u->freqn;
+		cp[1] = u->freqn >> 8;
+		cp[2] = u->freqn >> 16;
+	}
+	return 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ */
+static int usbin_sync_retire_desc(struct usbin *u, struct usb_isoc_desc *id)
+{
+	unsigned int i;
+
+	for (i = 0; i < DESCFRAMES; i++) {
+		if (id->frames[i].frame_status) {
+			printk(KERN_DEBUG "usbin_sync_retire_desc: frame %u status %d\n", i, id->frames[i].frame_status);
+			continue;
+		}
+	}
+	return 0;
+}
+
+static int usbin_sync_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 0
+        struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+        struct usb_audiodev *as = (struct usb_audiodev *)id->context;
+#else
+        struct usb_audiodev *as = (struct usb_audiodev *)dev_id;
+        struct usb_isoc_desc *id;
+#endif
+	struct usbin *u = &as->usbin;
+	unsigned int next, idmask;
+
+	printk(KERN_DEBUG "usbin_sync_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
+	spin_lock(&as->lock);
+	next = !(u->flags & FLG_SYNCNEXTID);
+	idmask = FLG_SYNC1RUNNING >> next;
+	u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | (-next & FLG_SYNCNEXTID);
+	id = u->synciso[!next];
+	if (!usbin_sync_retire_desc(u, id) &&
+	    u->flags & FLG_RUNNING &&
+	    !usbin_sync_prepare_desc(u, id) && 
+	    !usb_run_isoc(id, u->synciso[next])) {
+		u->flags |= idmask;
+	} else {
+		u->flags &= ~FLG_RUNNING;
+		printk(KERN_DEBUG "usbin_sync_completed: descriptor not restarted\n");
+	}
+	spin_unlock(&as->lock);
+	return 0;
+}
+
+static void usbin_start(struct usb_audiodev *as)
+{
+	struct usb_device *dev = as->state->usbdev;
+	struct usbin *u = &as->usbin;
+        struct usb_isoc_desc *id;
+	unsigned long flags;
+	unsigned int which, i;
+
+	printk(KERN_DEBUG "usbin_start: device %d ufmt %d dfmt %d srate %d\n",
+	       dev->devnum, u->format, u->dma.format, u->dma.srate);
+	/* allocate USB storage if not already done */
+	/* UHCI wants the data to be page aligned - this is silly */
+	if (!u->data[0])
+		u->data[0] = (void *)get_free_page(GFP_KERNEL);
+	if (!u->data[1])
+		u->data[1] = (void *)get_free_page(GFP_KERNEL);
+	if (!u->dataiso[0] && usb_init_isoc(dev, u->datapipe, DESCFRAMES, as, u->dataiso+0)) {
+		printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", 
+		       dev->devnum, u->datapipe);
+		u->dataiso[0] = NULL;
+	}
+	if (!u->dataiso[1] && usb_init_isoc(dev, u->datapipe, DESCFRAMES, as, u->dataiso+1)) {
+		printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", 
+		       dev->devnum, u->datapipe);
+		u->dataiso[1] = NULL;
+	}
+	if (u->syncpipe) {
+		if (!u->syncdata[0])
+			u->syncdata[0] = (void *)get_free_page(GFP_KERNEL);
+		if (!u->syncdata[1])
+			u->syncdata[1] = (void *)get_free_page(GFP_KERNEL);
+		if (!u->synciso[0] && usb_init_isoc(dev, u->syncpipe, DESCFRAMES, as, u->synciso+0)) {
+			printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", 
+			       dev->devnum, u->syncpipe);
+			u->synciso[0] = NULL;
+		}
+		if (!u->synciso[1] && usb_init_isoc(dev, u->syncpipe, DESCFRAMES, as, u->synciso+1)) {
+			printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", 
+			       dev->devnum, u->syncpipe);
+			u->synciso[1] = NULL;
+		}
+	}
+	if (!u->data[0] || !u->data[1] || !u->dataiso[0] || !u->dataiso[1] ||
+	    (u->syncpipe && (!u->syncdata[0] || !u->syncdata[1] || !u->synciso[0] || !u->synciso[1]))) {
+		printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
+		return;
+	}
+	spin_lock_irqsave(&as->lock, flags);
+	if (!(u->flags & FLG_RUNNING)) {
+		u->freqn = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
+		u->phase = 0;
+	}
+       	u->flags |= FLG_RUNNING;
+	if (!(u->flags & (FLG_ID0RUNNING|FLG_ID1RUNNING))) {
+		id = u->dataiso[0];
+		id->start_type = START_ASAP;
+		id->start_frame = 0;
+		id->callback_frames = /*0*/DESCFRAMES;
+		id->callback_fn = usbin_completed;
+		id->data = u->data[0];
+		id->buf_size = PAGE_SIZE;
+		u->flags &= ~FLG_NEXTID;
+		if (!usbin_prepare_desc(u, id) && !usb_run_isoc(id, NULL))
+			u->flags |= FLG_ID0RUNNING;
+		else
+			u->flags &= ~FLG_RUNNING;
+	}
+	i = u->flags & (FLG_ID0RUNNING|FLG_ID1RUNNING);
+	if (u->flags & FLG_RUNNING && (i == FLG_ID0RUNNING || i == FLG_ID1RUNNING)) {
+		which = !(u->flags & FLG_ID1RUNNING);
+		id = u->dataiso[which];
+		id->callback_frames = /*0*/DESCFRAMES;
+		id->callback_fn = usbin_completed;
+		id->data = u->data[which];
+		id->buf_size = PAGE_SIZE;
+		if (!usbin_prepare_desc(u, id) && !usb_run_isoc(id, u->dataiso[!which]))
+			u->flags |= FLG_ID0RUNNING << which;
+		else
+			u->flags &= ~FLG_RUNNING;
+	}
+	if (u->syncpipe) {
+		if (!(u->flags & (FLG_SYNC0RUNNING|FLG_SYNC1RUNNING))) {
+			id = u->synciso[0];
+			id->start_type = START_ASAP;
+			id->start_frame = 0;
+			id->callback_frames = /*0*/DESCFRAMES;
+			id->callback_fn = usbin_sync_completed;
+			id->data = u->syncdata[0];
+			id->buf_size = PAGE_SIZE;
+			u->flags &= ~FLG_SYNCNEXTID;
+			if (!usbin_sync_prepare_desc(u, id) && !usb_run_isoc(id, NULL))
+				u->flags |= FLG_SYNC0RUNNING;
+			else
+				u->flags &= ~FLG_RUNNING;
+		}
+		i = u->flags & (FLG_SYNC0RUNNING|FLG_SYNC1RUNNING);
+		if (u->flags & FLG_RUNNING && (i == FLG_SYNC0RUNNING || i == FLG_SYNC1RUNNING)) {
+			which = !(u->flags & FLG_SYNC1RUNNING);
+			id = u->synciso[which];
+			id->callback_frames = /*0*/DESCFRAMES;
+			id->callback_fn = usbin_sync_completed;
+			id->data = u->syncdata[which];
+			id->buf_size = PAGE_SIZE;
+			if (!usbin_sync_prepare_desc(u, id) && !usb_run_isoc(id, u->synciso[!which]))
+				u->flags |= FLG_SYNC0RUNNING << which;
+			else
+				u->flags &= ~FLG_RUNNING;
+		}
+	}
+        spin_unlock_irqrestore(&as->lock, flags);
+}
+
+static void usbout_stop(struct usb_audiodev *as)
+{
+	struct usbout *u = &as->usbout;
+        unsigned long flags;
+	unsigned int i;
+
+        spin_lock_irqsave(&as->lock, flags);
+	u->flags &= ~FLG_RUNNING;
+	i = u->flags;
+        spin_unlock_irqrestore(&as->lock, flags);
+	while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
+		schedule_timeout(1);
+		spin_lock_irqsave(&as->lock, flags);
+		i = u->flags;
+		spin_unlock_irqrestore(&as->lock, flags);
+	}
+	if (u->dataiso[0])
+		usb_free_isoc(u->dataiso[0]);
+	if (u->dataiso[1])
+		usb_free_isoc(u->dataiso[1]);
+	if (u->synciso[0])
+		usb_free_isoc(u->synciso[0]);
+	if (u->synciso[1])
+		usb_free_isoc(u->synciso[1]);
+	u->dataiso[0] = u->dataiso[1] = u->synciso[0] = u->synciso[1] = NULL;
+}
+
+static void usbout_release(struct usb_audiodev *as)
+{
+	struct usbout *u = &as->usbout;
+
+	usbout_stop(as);
+	if (u->data[0])
+		free_page((unsigned long)u->data[0]);
+	if (u->data[1])
+		free_page((unsigned long)u->data[1]);
+	if (u->syncdata[0])
+		free_page((unsigned long)u->syncdata[0]);
+	if (u->syncdata[1])
+		free_page((unsigned long)u->syncdata[1]);
+	u->data[0] = u->data[1] = u->syncdata[0] = u->syncdata[1] = NULL;
+}
+
+static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int samples)
+{
+	union {
+		__s16 s[64];
+		unsigned char b[0];
+	} tmp;
+	unsigned int scnt, maxs, ufmtsh, dfmtsh, cnt, i;
+	__s16 *sp, *sp2, s;
+	unsigned char *bp;
+
+	ufmtsh = AFMT_BYTESSHIFT(u->format);
+	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
+	while (samples > 0) {
+		scnt = samples;
+		if (scnt > maxs)
+			scnt = maxs;
+		cnt = scnt;
+		if (AFMT_ISSTEREO(u->dma.format))
+			cnt <<= 1;
+		dmabuf_copyout(&u->dma, tmp.b, scnt << dfmtsh);
+		sp = tmp.s + cnt;
+		switch (u->dma.format & ~AFMT_STEREO) {
+		case AFMT_U8:
+			for (bp = tmp.b+cnt, i = 0; i < cnt; i++) {
+				bp--;
+				sp--;
+				*sp = (*bp ^ 0x80) << 8;
+			}
+			break;
+
+		case AFMT_S8:
+			for (bp = tmp.b+cnt, i = 0; i < cnt; i++) {
+				bp--;
+				sp--;
+				*sp = *bp << 8;
+			}
+			break;
+
+		case AFMT_U16_LE:
+			for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
+				bp -= 2;
+				sp--;
+				*sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
+			}
+			break;
+
+		case AFMT_U16_BE:
+			for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
+				bp -= 2;
+				sp--;
+				*sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
+			}
+			break;
+
+		case AFMT_S16_LE:
+			for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
+				bp -= 2;
+				sp--;
+				*sp = bp[0] | (bp[1] << 8);
+			}
+			break;
+
+		case AFMT_S16_BE:
+			for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
+				bp -= 2;
+				sp--;
+				*sp = bp[1] | (bp[0] << 8);
+			}
+			break;
+		}
+		if (!AFMT_ISSTEREO(u->dma.format) && AFMT_ISSTEREO(u->format)) {
+			/* expand from mono to stereo */
+			for (sp = tmp.s+scnt, sp2 = tmp.s+2*scnt, i = 0; i < scnt; i++) {
+				sp--;
+				sp2 -= 2;
+				sp2[0] = sp2[1] = sp[0];
+			}
+		}
+		if (AFMT_ISSTEREO(u->dma.format) && !AFMT_ISSTEREO(u->format)) {
+			/* contract from stereo to mono */
+			for (sp = sp2 = tmp.s, i = 0; i < scnt; i++, sp++, sp2 += 2)
+				sp[0] = (sp2[0] + sp2[1]) >> 1;
+		}
+		cnt = scnt;
+		if (AFMT_ISSTEREO(u->format))
+			cnt <<= 1;
+		sp = tmp.s;
+		bp = buffer;
+		switch (u->format & ~AFMT_STEREO) {
+		case AFMT_U8:
+			for (i = 0; i < cnt; i++, sp++, bp++)
+				*bp = (*sp >> 8) ^ 0x80;
+			break;
+
+		case AFMT_S8:
+			for (i = 0; i < cnt; i++, sp++, bp++)
+				*bp = *sp >> 8;
+			break;
+
+		case AFMT_U16_LE:
+			for (i = 0; i < cnt; i++, sp++, bp += 2) {
+				s = *sp;
+				bp[0] = s;
+				bp[1] = (s >> 8) ^ 0x80;
+			}
+			break;
+
+		case AFMT_U16_BE:
+			for (i = 0; i < cnt; i++, sp++, bp += 2) {
+				s = *sp;
+				bp[1] = s;
+				bp[0] = (s >> 8) ^ 0x80;
+			}
+			break;
+
+		case AFMT_S16_LE:
+			for (i = 0; i < cnt; i++, sp++, bp += 2) {
+				s = *sp;
+				bp[0] = s;
+				bp[1] = s >> 8;
+			}
+			break;
+
+		case AFMT_S16_BE:
+			for (i = 0; i < cnt; i++, sp++, bp += 2) {
+				s = *sp;
+				bp[1] = s;
+				bp[0] = s >> 8;
+			}
+			break;
+		}
+		buffer += scnt << ufmtsh;
+		samples -= scnt;
+	}
+}		
+
+static int usbout_prepare_desc(struct usbout *u, struct usb_isoc_desc *id)
+{
+	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt;
+	unsigned char *cp = id->data;
+
+	ufmtsh = AFMT_BYTESSHIFT(u->format);
+	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+	for (i = 0; i < DESCFRAMES; i++) {
+		u->phase = (u->phase & 0x3fff) + u->freqm;
+		scnt = u->phase >> 14;
+		if (!scnt) {
+			id->frames[i].frame_length = 0;
+			continue;
+		}
+		cnt = scnt << dfmtsh;
+		if (!u->dma.mapped) {
+			if (cnt > u->dma.count) {
+				scnt = u->dma.count >> dfmtsh;
+				cnt = scnt << dfmtsh;
+				err++;
+			}
+			u->dma.count -= cnt;
+		} else
+			u->dma.count += cnt;
+		if (u->format == u->dma.format) {
+			/* we do not need format conversion */
+			dmabuf_copyout(&u->dma, cp, cnt);
+		} else {
+			/* we need sampling format conversion */
+			usbout_convert(u, cp, scnt);
+		}
+		cnt = scnt << ufmtsh;
+		id->frames[i].frame_length = cnt;
+		cp += cnt;
+	}
+	if (err)
+		u->dma.error++;
+	if (u->dma.mapped) {
+		if (u->dma.count >= (signed)u->dma.fragsize)
+			wake_up(&u->dma.wait);
+	} else {
+		if ((signed)u->dma.dmasize >= u->dma.count + (signed)u->dma.fragsize)
+			wake_up(&u->dma.wait);
+	}
+	return err ? -1 : 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ */
+static int usbout_retire_desc(struct usbout *u, struct usb_isoc_desc *id)
+{
+	unsigned int i;
+
+	for (i = 0; i < DESCFRAMES; i++) {
+		if (id->frames[i].frame_status) {
+			printk(KERN_DEBUG "usbout_retire_desc: frame %u status %d\n", i, id->frames[i].frame_status);
+			continue;
+		}
+	}
+	return 0;
+}
+
+static int usbout_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 0
+        struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+        struct usb_audiodev *as = (struct usb_audiodev *)id->context;
+#else
+        struct usb_audiodev *as = (struct usb_audiodev *)dev_id;
+	struct usb_isoc_desc *id;
+#endif
+	struct usbout *u = &as->usbout;
+	unsigned int next, idmask;
+
+	printk(KERN_DEBUG "usbout_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
+	spin_lock(&as->lock);
+	next = !(u->flags & FLG_NEXTID);
+	idmask = FLG_ID1RUNNING >> next;
+	u->flags = (u->flags & ~(FLG_NEXTID | idmask)) | next;
+	id = u->dataiso[!next];
+	if (!usbout_retire_desc(u, id) &&
+	    u->flags & FLG_RUNNING &&
+	    !usbout_prepare_desc(u, id) && 
+	    !usb_run_isoc(id, u->dataiso[next])) {
+		u->flags |= idmask;
+	} else {
+		u->flags &= ~FLG_RUNNING;
+		printk(KERN_DEBUG "usbout_completed: descriptor not restarted\n");
+	}
+	spin_unlock(&as->lock);
+	return 0;
+}
+
+static int usbout_sync_prepare_desc(struct usbout *u, struct usb_isoc_desc *id)
+{
+	unsigned int i;
+
+	for (i = 0; i < DESCFRAMES; i++)
+		id->frames[i].frame_length = 3;
+	return 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ */
+static int usbout_sync_retire_desc(struct usbout *u, struct usb_isoc_desc *id)
+{
+	unsigned char *cp = id->data;
+	unsigned int i, f;
+
+	for (i = 0; i < DESCFRAMES; i++, cp += 3) {
+		if (id->frames[i].frame_status) {
+			printk(KERN_DEBUG "usbout_sync_retire_desc: frame %u status %d\n", i, id->frames[i].frame_status);
+			continue;
+		}
+		if (id->frames[i].frame_length < 3) {
+			printk(KERN_DEBUG "usbout_sync_retire_desc: frame %u length %d\n", i, id->frames[i].frame_length);
+			continue;
+		}
+		f = cp[0] | (cp[1] << 8) | (cp[2] << 16);
+		if (abs(f - u->freqn) > (u->freqn >> 3)) {
+			printk(KERN_WARNING "usbout_sync_retire_desc: requested frequency %u (nominal %u) out of range!\n", f, u->freqn);
+			continue;
+		}
+		u->freqm = f;
+	}
+	return 0;
+}
+
+static int usbout_sync_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 0
+        struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+        struct usb_audiodev *as = (struct usb_audiodev *)id->context;
+#else
+        struct usb_audiodev *as = (struct usb_audiodev *)dev_id;
+	struct usb_isoc_desc *id;
+#endif
+	struct usbout *u = &as->usbout;
+	unsigned int next, idmask;
+
+	printk(KERN_DEBUG "usbout_sync_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
+	spin_lock(&as->lock);
+	next = !(u->flags & FLG_SYNCNEXTID);
+	idmask = FLG_SYNC1RUNNING >> next;
+	u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | (-next & FLG_SYNCNEXTID);
+	id = u->synciso[!next];
+	if (!usbout_sync_retire_desc(u, id) &&
+	    u->flags & FLG_RUNNING &&
+	    !usbout_sync_prepare_desc(u, id) && 
+	    !usb_run_isoc(id, u->synciso[next])) {
+		u->flags |= idmask;
+	} else {
+		u->flags &= ~FLG_RUNNING;
+		printk(KERN_DEBUG "usbout_sync_completed: descriptor not restarted\n");
+	}
+	spin_unlock(&as->lock);
+	return 0;
+}
+
+static void usbout_start(struct usb_audiodev *as)
+{
+	struct usb_device *dev = as->state->usbdev;
+	struct usbout *u = &as->usbout;
+        struct usb_isoc_desc *id;
+	unsigned long flags;
+	unsigned int which, i;
+
+	printk(KERN_DEBUG "usbout_start: device %d ufmt %d dfmt %d srate %d\n",
+	       dev->devnum, u->format, u->dma.format, u->dma.srate);
+	/* allocate USB storage if not already done */
+	/* UHCI wants the data to be page aligned - this is silly */
+	if (!u->data[0])
+		u->data[0] = (void *)get_free_page(GFP_KERNEL);
+	if (!u->data[1])
+		u->data[1] = (void *)get_free_page(GFP_KERNEL);
+	if (!u->dataiso[0] && usb_init_isoc(dev, u->datapipe, DESCFRAMES, as, u->dataiso+0)) {
+		printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", 
+		       dev->devnum, u->datapipe);
+		u->dataiso[0] = NULL;
+	}
+	if (!u->dataiso[1] && usb_init_isoc(dev, u->datapipe, DESCFRAMES, as, u->dataiso+1)) {
+		printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", 
+		       dev->devnum, u->datapipe);
+		u->dataiso[1] = NULL;
+	}
+	if (u->syncpipe) {
+		if (!u->syncdata[0])
+			u->syncdata[0] = (void *)get_free_page(GFP_KERNEL);
+		if (!u->syncdata[1])
+			u->syncdata[1] = (void *)get_free_page(GFP_KERNEL);
+		if (!u->synciso[0] && usb_init_isoc(dev, u->syncpipe, DESCFRAMES, as, u->synciso+0)) {
+			printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", 
+			       dev->devnum, u->syncpipe);
+			u->synciso[0] = NULL;
+		}
+		if (!u->synciso[1] && usb_init_isoc(dev, u->syncpipe, DESCFRAMES, as, u->synciso+1)) {
+			printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", 
+			       dev->devnum, u->syncpipe);
+			u->synciso[1] = NULL;
+		}
+	}
+	if (!u->data[0] || !u->data[1] || !u->dataiso[0] || !u->dataiso[1] ||
+	    (u->syncpipe && (!u->syncdata[0] || !u->syncdata[1] || !u->synciso[0] || !u->synciso[1]))) {
+		printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
+		return;
+	}
+	spin_lock_irqsave(&as->lock, flags);
+	if (!(u->flags & FLG_RUNNING)) {
+		u->freqn = u->freqm = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
+		u->phase = 0;
+	}
+       	u->flags |= FLG_RUNNING;
+	if (!(u->flags & (FLG_ID0RUNNING|FLG_ID1RUNNING))) {
+		id = u->dataiso[0];
+		id->start_type = START_ASAP;
+		id->start_frame = 0;
+		id->callback_frames = /*0*/DESCFRAMES;
+		id->callback_fn = usbout_completed;
+		id->data = u->data[0];
+		id->buf_size = PAGE_SIZE;
+		u->flags &= ~FLG_NEXTID;
+		if (!usbout_prepare_desc(u, id) && !usb_run_isoc(id, NULL))
+			u->flags |= FLG_ID0RUNNING;
+		else
+			u->flags &= ~FLG_RUNNING;
+	}
+	i = u->flags & (FLG_ID0RUNNING|FLG_ID1RUNNING);
+	if (u->flags & FLG_RUNNING && (i == FLG_ID0RUNNING || i == FLG_ID1RUNNING)) {
+		which = !(u->flags & FLG_ID1RUNNING);
+		id = u->dataiso[which];
+		id->callback_frames = /*0*/DESCFRAMES;
+		id->callback_fn = usbout_completed;
+		id->data = u->data[which];
+		id->buf_size = PAGE_SIZE;
+		if (!usbout_prepare_desc(u, id) && !usb_run_isoc(id, u->dataiso[!which]))
+			u->flags |= FLG_ID0RUNNING << which;
+		else
+			u->flags &= ~FLG_RUNNING;
+	}
+	if (u->syncpipe) {
+		if (!(u->flags & (FLG_SYNC0RUNNING|FLG_SYNC1RUNNING))) {
+			id = u->synciso[0];
+			id->start_type = START_ASAP;
+			id->start_frame = 0;
+			id->callback_frames = /*0*/DESCFRAMES;
+			id->callback_fn = usbout_sync_completed;
+			id->data = u->syncdata[0];
+			id->buf_size = PAGE_SIZE;
+			u->flags &= ~FLG_NEXTID;
+			if (!usbout_sync_prepare_desc(u, id) && !usb_run_isoc(id, NULL))
+				u->flags |= FLG_SYNC0RUNNING;
+			else
+				u->flags &= ~FLG_RUNNING;
+		}
+		i = u->flags & (FLG_SYNC0RUNNING|FLG_SYNC1RUNNING);
+		if (u->flags & FLG_RUNNING && (i == FLG_SYNC0RUNNING || i == FLG_SYNC1RUNNING)) {
+			which = !(u->flags & FLG_SYNC1RUNNING);
+			id = u->synciso[which];
+			id->callback_frames = /*0*/DESCFRAMES;
+			id->callback_fn = usbout_sync_completed;
+			id->data = u->syncdata[which];
+			id->buf_size = PAGE_SIZE;
+			if (!usbout_sync_prepare_desc(u, id) && !usb_run_isoc(id, u->synciso[!which]))
+				u->flags |= FLG_SYNC0RUNNING << which;
+			else
+				u->flags &= ~FLG_RUNNING;
+		}
+	}
+        spin_unlock_irqrestore(&as->lock, flags);
+}
+
+/* --------------------------------------------------------------------- */
+
+static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt)
+{
+	unsigned int i;
+
+	/* first find an exact match */
+	for (i = 0; i < nr; i++)
+		if (afp[i].format == fmt)
+			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))
+			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))
+			return i;
+	/* return anything */
+	return 0;
+}
+
+static int set_format_in(struct usb_audiodev *as)
+{
+        struct usb_device *dev = as->state->usbdev;
+        struct usb_config_descriptor *config = dev->actconfig;
+        struct usb_interface_descriptor *alts;
+        struct usb_interface *iface;	
+	struct usbin *u = &as->usbin;
+	struct dmabuf *d = &u->dma;
+	struct audioformat *fmt;
+	unsigned int fmtnr;
+	unsigned char data[3];
+
+	if (u->interface < 0 || u->interface >= config->bNumInterfaces)
+		return 0;
+	iface = &config->interface[u->interface];
+	fmtnr = find_format(as->fmtin, as->numfmtin, d->format);
+	fmt = as->fmtin + fmtnr;
+	alts = &iface->altsetting[fmt->altsetting];
+	u->format = fmt->format;
+	u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].bEndpointAddress & 0xf);
+	u->syncpipe = u->syncinterval = 0;
+	if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x08) {
+		if (alts->bNumEndpoints < 2 ||
+		    alts->endpoint[1].bmAttributes != 0x01 ||
+		    alts->endpoint[1].bSynchAddress == 0 ||
+		    alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress & 0x7f)) {
+			printk(KERN_ERR "usb_audio: device %d interface %d altsetting %d invalid synch pipe\n",
+			       dev->devnum, u->interface, fmt->altsetting);
+			return -1;
+		}
+		u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf);
+		u->syncinterval = alts->endpoint[1].bRefresh;
+	}
+	if (d->srate < fmt->sratelo)
+		d->srate = fmt->sratelo;
+	if (d->srate > fmt->sratehi)
+		d->srate = fmt->sratehi;
+	if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
+		printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
+		       dev->devnum, u->interface, fmt->altsetting);
+		return -1;
+	}
+	if (fmt->sratelo == fmt->sratehi)
+		return 0;
+	data[0] = d->srate;
+	data[1] = d->srate >> 8;
+	data[2] = d->srate >> 16;
+	if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
+			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
+		printk(KERN_ERR "usbaudio: failure to set sampling frequency device %d endpoint %d\n",
+		       dev->devnum, usb_pipeendpoint(u->datapipe));
+		return -1;
+	}
+	if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
+			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
+		printk(KERN_ERR "usbaudio: failure to get sampling frequency device %d endpoint %d\n",
+		       dev->devnum, usb_pipeendpoint(u->datapipe));
+		return -1;
+	}
+	d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
+	return 0;
+}
+
+static int set_format_out(struct usb_audiodev *as)
+{
+        struct usb_device *dev = as->state->usbdev;
+        struct usb_config_descriptor *config = dev->actconfig;
+        struct usb_interface_descriptor *alts;
+        struct usb_interface *iface;	
+	struct usbout *u = &as->usbout;
+	struct dmabuf *d = &u->dma;
+	struct audioformat *fmt;
+	unsigned int fmtnr;
+	unsigned char data[3];
+
+	if (u->interface < 0 || u->interface >= config->bNumInterfaces)
+		return 0;
+	iface = &config->interface[u->interface];
+	fmtnr = find_format(as->fmtout, as->numfmtout, d->format);
+	fmt = as->fmtout + fmtnr;
+	u->format = fmt->format;
+	alts = &iface->altsetting[fmt->altsetting];
+	u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].bEndpointAddress & 0xf);
+	u->syncpipe = u->syncinterval = 0;
+	if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x04) {
+		if (alts->bNumEndpoints < 2 ||
+		    alts->endpoint[1].bmAttributes != 0x01 ||
+		    alts->endpoint[1].bSynchAddress == 0 ||
+		    alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress | 0x80)) {
+			printk(KERN_ERR "usb_audio: device %d interface %d altsetting %d invalid synch pipe\n",
+			       dev->devnum, u->interface, fmt->altsetting);
+			return -1;
+		}
+		u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf);
+		u->syncinterval = alts->endpoint[1].bRefresh;
+	}
+	if (d->srate < fmt->sratelo)
+		d->srate = fmt->sratelo;
+	if (d->srate > fmt->sratehi)
+		d->srate = fmt->sratehi;
+	if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
+		printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
+		       dev->devnum, u->interface, fmt->altsetting);
+		return -1;
+	}
+	if (fmt->sratelo == fmt->sratehi)
+		return 0;
+	data[0] = d->srate;
+	data[1] = d->srate >> 8;
+	data[2] = d->srate >> 16;
+	if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
+			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
+		printk(KERN_ERR "usbaudio: failure to set sampling frequency device %d endpoint %d\n",
+		       dev->devnum, usb_pipeendpoint(u->datapipe));
+		return -1;
+	}
+	if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
+			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
+		printk(KERN_ERR "usbaudio: failure to get sampling frequency device %d endpoint %d\n",
+		       dev->devnum, usb_pipeendpoint(u->datapipe));
+		return -1;
+	}
+	d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
+	return 0;
+}
+
+static int set_format(struct usb_audiodev *s, unsigned int fmode, unsigned int fmt, unsigned int srate)
+{
+	int ret1 = 0, ret2 = 0;
+
+	if (!(fmode & (FMODE_READ|FMODE_WRITE)))
+		return -EINVAL;
+	if (fmode & FMODE_READ) {
+		usbin_stop(s);
+		s->usbin.dma.ready = 0;
+		if (fmt == AFMT_QUERY)
+			fmt = s->usbin.dma.format;
+		else
+			s->usbin.dma.format = fmt;
+		if (!srate)
+			srate = s->usbin.dma.srate;
+		else
+			s->usbin.dma.srate = srate;
+	}
+	if (fmode & FMODE_WRITE) {
+		usbout_stop(s);
+		s->usbout.dma.ready = 0;
+		if (fmt == AFMT_QUERY)
+			fmt = s->usbout.dma.format;
+		else
+			s->usbout.dma.format = fmt;
+		if (!srate)
+			srate = s->usbout.dma.srate;
+		else
+			s->usbout.dma.srate = srate;
+	}
+	if (fmode & FMODE_READ)
+		ret1 = set_format_in(s);
+	if (fmode & FMODE_WRITE)
+		ret2 = set_format_out(s);
+	return ret1 ? ret1 : ret2;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
+{
+	struct usb_device *dev = ms->state->usbdev;
+	unsigned char data[2];
+	struct mixerchannel *ch;
+	int v1, v2, v3;
+
+	if (mixch >= ms->numch)
+		return -1;
+	ch = &ms->ch[mixch];
+	v3 = ch->maxval - ch->minval;
+	v1 = value & 0xff;
+	v2 = (value >> 8) & 0xff;
+	if (v1 > 100)
+		v1 = 100;
+	if (v2 > 100)
+		v2 = 100;
+	if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+		v2 = v1;
+	ch->value = v1 | (v2 << 8);
+	v1 = (v1 * v3) / 100 + ch->minval;
+	v2 = (v2 * v3) / 100 + ch->minval;
+        switch (ch->selector) {
+        case 0:  /* mixer unit request */
+		data[0] = v1;
+		data[1] = v1 >> 8;
+                if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+                                    (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+                        goto err;
+		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+			return 0;
+		data[0] = v2;
+		data[1] = v2 >> 8;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
+				    ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+                        goto err;
+		return 0;
+
+                /* various feature unit controls */
+        case VOLUME_CONTROL:
+		data[0] = v1;
+		data[1] = v1 >> 8;
+                if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+                                    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+                        goto err;
+		if (ch->chnum == 0)
+			return 0;
+		data[0] = v2;
+		data[1] = v2 >> 8;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+			goto err;
+		return 0;
+                
+        case BASS_CONTROL:
+        case MID_CONTROL:
+        case TREBLE_CONTROL:
+		data[0] = v1 >> 8;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+                                    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 1)
+                        goto err;
+		if (ch->chnum == 0)
+			return 0;
+		data[0] = v2 >> 8;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 1)
+			goto err;
+		return 0;
+               
+        default:
+                return -1;
+        }
+        return 0;
+
+ err:
+        printk(KERN_ERR "usb_audio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
+               dev->devnum, ms->iface, ch->unitid, ch->chnum, ch->selector);
+	return -1;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * should be called with open_sem hold, so that no new processes
+ * look at the audio device to be destroyed
+ */
+
+static void release(struct usb_audio_state *s)
+{
+	struct usb_audiodev *as;
+	struct usb_mixerdev *ms;
+
+	s->count--;
+	if (s->count) {
+		up(&open_sem);
+		return;
+	}
+	up(&open_sem);
+        wake_up(&open_wait);
+	while (!list_empty(&s->audiolist)) {
+		as = list_entry(s->audiolist.next, struct usb_audiodev, list);
+		list_del(&as->list);
+		usbin_release(as);
+		usbout_release(as);
+		dmabuf_release(&as->usbin.dma);
+		dmabuf_release(&as->usbout.dma);
+		kfree(as);
+	}
+	while (!list_empty(&s->mixerlist)) {
+		ms = list_entry(s->mixerlist.next, struct usb_mixerdev, list);
+		list_del(&ms->list);
+		kfree(ms);
+	}
+	kfree(s);
+        MOD_DEC_USE_COUNT;
+}
+
+extern inline int prog_dmabuf_in(struct usb_audiodev *as)
+{
+        usbin_stop(as);
+        return dmabuf_init(&as->usbin.dma);
+}
+
+extern inline int prog_dmabuf_out(struct usb_audiodev *as)
+{
+        usbout_stop(as);
+        return dmabuf_init(&as->usbout.dma);
+}
 
-#include "usb.h"
-#define AUDIO_DEBUG 1
+/* --------------------------------------------------------------------- */
 
-static int usb_audio_probe(struct usb_device *dev);
-static void usb_audio_disconnect(struct usb_device *dev);
-static LIST_HEAD(usb_audio_list);
+static loff_t usb_audio_llseek(struct file *file, loff_t offset, int origin)
+{
+        return -ESPIPE;
+}
 
-struct usb_audio {
-	struct usb_device *dev;
-	struct list_head list;
+/* --------------------------------------------------------------------- */
+
+static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
+{
+        int minor = MINOR(inode->i_rdev);
+	struct list_head *devs, *mdevs;
+	struct usb_mixerdev *ms;
+        struct usb_audio_state *s;
+
+        down(&open_sem);
+	for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) {
+		s = list_entry(devs, struct usb_audio_state, audiodev);
+		for (mdevs = s->mixerlist.next; mdevs != &s->mixerlist; mdevs = mdevs->next) {
+			ms = list_entry(mdevs, struct usb_mixerdev, list);
+			if (ms->dev_mixer == minor)
+				goto mixer_found;
+		}
+	}
+	up(&open_sem);
+	return -ENODEV;
+
+ mixer_found:
+	if (!s->usbdev) {
+		up(&open_sem);
+		return -EIO;
+	}
+        file->private_data = ms;
+	s->count++;
+	up(&open_sem);
+        return 0;
+}
+
+static int usb_audio_release_mixdev(struct inode *inode, struct file *file)
+{
+        struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
+	struct usb_audio_state *s = ms->state;
+
+	down(&open_sem);
+	release(s);
+        return 0;
+}
+
+static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
+        int i, j, val;
+
+        if (cmd == SOUND_MIXER_INFO) {
+                mixer_info info;
+                strncpy(info.id, "USB_AUDIO", sizeof(info.id));
+                strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
+                info.modify_counter = ms->modcnt;
+                if (copy_to_user((void *)arg, &info, sizeof(info)))
+                        return -EFAULT;
+                return 0;
+        }
+        if (cmd == SOUND_OLD_MIXER_INFO) {
+                _old_mixer_info info;
+                strncpy(info.id, "USB_AUDIO", sizeof(info.id));
+                strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
+                if (copy_to_user((void *)arg, &info, sizeof(info)))
+                        return -EFAULT;
+                return 0;
+        }
+        if (cmd == OSS_GETVERSION)
+                return put_user(SOUND_VERSION, (int *)arg);
+        if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+                return -EINVAL;
+        if (_IOC_DIR(cmd) == _IOC_READ) {
+                switch (_IOC_NR(cmd)) {
+                case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+			/* don't know how to handle this yet */
+                        return put_user(0, (int *)arg);
+                        
+                case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+                        for (val = i = 0; i < ms->numch; i++)
+				val |= 1 << ms->ch[i].osschannel;
+                        return put_user(val, (int *)arg);
+
+                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+			/* don't know how to handle this yet */
+                        return put_user(0, (int *)arg);
+                        
+                case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+                        for (val = i = 0; i < ms->numch; i++)
+				if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
+					val |= 1 << ms->ch[i].osschannel;
+                        return put_user(0, (int *)arg);
+                        
+                case SOUND_MIXER_CAPS:
+                        return put_user(0, (int *)arg);
+
+                default:
+                        i = _IOC_NR(cmd);
+                        if (i >= SOUND_MIXER_NRDEVICES)
+                                return -EINVAL;
+			for (j = 0; j < ms->numch; j++) {
+				if (ms->ch[j].osschannel == i) {
+					return put_user(ms->ch[j].value, (int *)arg);
+				}
+			}
+			return -EINVAL;
+                }
+        }
+        if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) 
+                return -EINVAL;
+        ms->modcnt++;
+        switch (_IOC_NR(cmd)) {
+        case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+                get_user_ret(val, (int *)arg, -EFAULT);
+                /* set recording source: val */
+                return 0;
+
+        default:
+                i = _IOC_NR(cmd);
+                if (i >= SOUND_MIXER_NRDEVICES)
+                        return -EINVAL;
+		for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++);
+		if (j >= ms->numch)
+			return -EINVAL;
+                get_user_ret(val, (int *)arg, -EFAULT);
+		if (wrmixer(ms, j, val))
+			return -EIO;
+                return put_user(ms->ch[j].value, (int *)arg);
+        }
+}
+
+static /*const*/ struct file_operations usb_mixer_fops = {
+        &usb_audio_llseek,
+        NULL,  /* read */
+        NULL,  /* write */
+        NULL,  /* readdir */
+        NULL,  /* poll */
+        &usb_audio_ioctl_mixdev,
+        NULL,  /* mmap */
+        &usb_audio_open_mixdev,
+        NULL,   /* flush */
+        &usb_audio_release_mixdev,
+        NULL,  /* fsync */
+        NULL,  /* fasync */
+        NULL,  /* check_media_change */
+        NULL,  /* revalidate */
+        NULL,  /* lock */
+};
+
+/* --------------------------------------------------------------------- */
+
+static int drain_out(struct usb_audiodev *as, int nonblock)
+{
+        DECLARE_WAITQUEUE(wait, current);
+        unsigned long flags;
+        int count, tmo;
+        
+        if (as->usbout.dma.mapped || !as->usbout.dma.ready)
+                return 0;
+        __set_current_state(TASK_INTERRUPTIBLE);
+        add_wait_queue(&as->usbout.dma.wait, &wait);
+        for (;;) {
+                spin_lock_irqsave(&as->lock, flags);
+                count = as->usbout.dma.count;
+                spin_unlock_irqrestore(&as->lock, flags);
+                if (count <= 0)
+                        break;
+                if (signal_pending(current))
+                        break;
+                if (nonblock) {
+                        remove_wait_queue(&as->usbout.dma.wait, &wait);
+                        set_current_state(TASK_RUNNING);
+                        return -EBUSY;
+                }
+                tmo = 3 * HZ * count / as->usbout.dma.srate;
+		tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format);
+                if (!schedule_timeout(tmo + 1))
+                        printk(KERN_DEBUG "usbaudio: dma timed out??\n");
+        }
+        remove_wait_queue(&as->usbout.dma.wait, &wait);
+        set_current_state(TASK_RUNNING);
+        if (signal_pending(current))
+                return -ERESTARTSYS;
+        return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static ssize_t usb_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+        struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+        ssize_t ret = 0;
+        unsigned long flags;
+        unsigned int ptr;
+        int cnt, err;
+
+        if (ppos != &file->f_pos)
+                return -ESPIPE;
+        if (as->usbin.dma.mapped)
+                return -ENXIO;
+        if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
+                return ret;
+        if (!access_ok(VERIFY_WRITE, buffer, count))
+                return -EFAULT;
+	__set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&as->usbin.dma.wait, &wait);
+	while (count > 0) {
+		spin_lock_irqsave(&as->lock, flags);
+		ptr = as->usbin.dma.rdptr;
+		cnt = as->usbin.dma.count;
+		spin_unlock_irqrestore(&as->lock, flags);
+		if (cnt > count)
+			cnt = count;
+                if (cnt <= 0) {
+                        usbin_start(as);
+                        if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			schedule();
+                        if (signal_pending(current)) {
+                                if (!ret)
+                                        ret = -ERESTARTSYS;
+                                break;
+			}
+			continue;
+                }
+		if ((err = dmabuf_copyout_user(&as->usbin.dma, ptr, buffer, cnt))) {
+			if (!ret)
+				ret = err;
+			break;
+		}
+		ptr += cnt;
+		if (ptr >= as->usbin.dma.dmasize)
+			ptr -= as->usbin.dma.dmasize;
+		spin_lock_irqsave(&as->lock, flags);
+		as->usbin.dma.rdptr = ptr;
+		as->usbin.dma.count -= cnt;
+		spin_unlock_irqrestore(&as->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+	}
+        __set_current_state(TASK_RUNNING);
+        remove_wait_queue(&as->usbin.dma.wait, &wait);
+	return ret;
+}
+
+static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+        struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+        ssize_t ret = 0;
+        unsigned long flags;
+        unsigned int ptr;
+        int cnt, err;
+
+        if (ppos != &file->f_pos)
+                return -ESPIPE;
+        if (as->usbout.dma.mapped)
+                return -ENXIO;
+        if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
+                return ret;
+        if (!access_ok(VERIFY_READ, buffer, count))
+                return -EFAULT;
+	__set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&as->usbout.dma.wait, &wait);
+        while (count > 0) {
+                spin_lock_irqsave(&as->lock, flags);
+                if (as->usbout.dma.count < 0) {
+                        as->usbout.dma.count = 0;
+                        as->usbout.dma.rdptr = as->usbout.dma.wrptr;
+                }
+                ptr = as->usbout.dma.wrptr;
+                cnt = as->usbout.dma.dmasize - as->usbout.dma.count;
+                spin_unlock_irqrestore(&as->lock, flags);
+                if (cnt > count)
+                        cnt = count;
+                if (cnt <= 0) {
+                        usbout_start(as);
+                        if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			schedule();
+                        if (signal_pending(current)) {
+                                if (!ret)
+                                        ret = -ERESTARTSYS;
+                                break;
+			}
+			continue;
+		}
+		if ((err = dmabuf_copyin_user(&as->usbout.dma, ptr, buffer, cnt))) {
+			if (!ret)
+				ret = err;
+			break;
+		}
+		ptr += cnt;
+		if (ptr >= as->usbout.dma.dmasize)
+			ptr -= as->usbout.dma.dmasize;
+                spin_lock_irqsave(&as->lock, flags);
+                as->usbout.dma.wrptr = ptr;
+                as->usbout.dma.count += cnt;
+                spin_unlock_irqrestore(&as->lock, flags);
+                count -= cnt;
+                buffer += cnt;
+                ret += cnt;
+                usbout_start(as);
+        }
+        __set_current_state(TASK_RUNNING);
+        remove_wait_queue(&as->usbout.dma.wait, &wait);
+	return ret;
+}
+
+static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait)
+{
+        struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+        unsigned long flags;
+        unsigned int mask = 0;
+
+        if (file->f_mode & FMODE_WRITE) {
+		if (!as->usbout.dma.ready)
+			prog_dmabuf_out(as);
+                poll_wait(file, &as->usbout.dma.wait, wait);
+	}
+        if (file->f_mode & FMODE_READ) {
+		if (!as->usbin.dma.ready)
+			prog_dmabuf_in(as);
+                poll_wait(file, &as->usbin.dma.wait, wait);
+	}
+        spin_lock_irqsave(&as->lock, flags);
+        if (file->f_mode & FMODE_READ) {
+                if (as->usbin.dma.count >= (signed)as->usbin.dma.fragsize)
+                        mask |= POLLIN | POLLRDNORM;
+        }
+        if (file->f_mode & FMODE_WRITE) {
+                if (as->usbout.dma.mapped) {
+                        if (as->usbout.dma.count >= (signed)as->usbout.dma.fragsize) 
+                                mask |= POLLOUT | POLLWRNORM;
+                } else {
+                        if ((signed)as->usbout.dma.dmasize >= as->usbout.dma.count + (signed)as->usbout.dma.fragsize)
+                                mask |= POLLOUT | POLLWRNORM;
+                }
+        }
+        spin_unlock_irqrestore(&as->lock, flags);
+        return mask;
+}
+
+static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+        struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+        struct dmabuf *db;
+        int ret;
+
+        if (vma->vm_flags & VM_WRITE) {
+                if ((ret = prog_dmabuf_out(as)) != 0)
+                        return ret;
+                db = &as->usbout.dma;
+        } else if (vma->vm_flags & VM_READ) {
+                if ((ret = prog_dmabuf_in(as)) != 0)
+                        return ret;
+                db = &as->usbin.dma;
+        } else
+                return -EINVAL;
+        if (vma->vm_offset != 0)
+                return -EINVAL;
+	return dmabuf_mmap(db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+        struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+	struct usb_audio_state *s = as->state;
+        unsigned long flags;
+        audio_buf_info abinfo;
+        count_info cinfo;
+        int val, val2, mapped, ret;
+
+	if (!s->usbdev)
+		return -EIO;
+        mapped = ((file->f_mode & FMODE_WRITE) && as->usbout.dma.mapped) ||
+                ((file->f_mode & FMODE_READ) && as->usbin.dma.mapped);
+        switch (cmd) {
+        case OSS_GETVERSION:
+                return put_user(SOUND_VERSION, (int *)arg);
+
+        case SNDCTL_DSP_SYNC:
+                if (file->f_mode & FMODE_WRITE)
+                        return drain_out(as, 0/*file->f_flags & O_NONBLOCK*/);
+                return 0;
+
+        case SNDCTL_DSP_SETDUPLEX:
+                return 0;
+
+        case SNDCTL_DSP_GETCAPS:
+                return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | 
+				DSP_CAP_MMAP | DSP_CAP_BATCH, (int *)arg);
+
+        case SNDCTL_DSP_RESET:
+                if (file->f_mode & FMODE_WRITE) {
+                        usbout_stop(as);
+                        as->usbout.dma.rdptr = as->usbout.dma.wrptr = as->usbout.dma.count = as->usbout.dma.total_bytes = 0;
+                }
+                if (file->f_mode & FMODE_READ) {
+                        usbin_stop(as);
+                        as->usbin.dma.rdptr = as->usbin.dma.wrptr = as->usbin.dma.count = as->usbin.dma.total_bytes = 0;
+                }
+                return 0;
+
+        case SNDCTL_DSP_SPEED:
+                get_user_ret(val, (int *)arg, -EFAULT);
+                if (val >= 0) {
+                        if (val < 4000)
+                                val = 4000;
+                        if (val > 100000)
+                                val = 100000;
+			if (set_format(as, file->f_mode, AFMT_QUERY, val))
+				return -EIO;
+                }
+                return put_user((file->f_mode & FMODE_READ) ? as->usbin.dma.srate : as->usbout.dma.srate, (int *)arg);
+
+        case SNDCTL_DSP_STEREO:
+		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+		if (set_format(as, file->f_mode, val2 | AFMT_STEREO, 0))
+			return -EIO;
+                return 0;
+
+        case SNDCTL_DSP_CHANNELS:
+                get_user_ret(val, (int *)arg, -EFAULT);
+                if (val != 0) {
+			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+			if (val == 1)
+				val2 &= ~AFMT_STEREO;
+			else
+				val2 |= AFMT_STEREO;
+			if (set_format(as, file->f_mode, val2, 0))
+				return -EIO;
+		}
+		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+                return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, (int *)arg);
+
+        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+                return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
+				AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, (int *)arg);
+
+        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+                get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != AFMT_QUERY) {
+			if (hweight32(val) != 1)
+				return -EINVAL;
+			if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
+				     AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE)))
+				return -EINVAL;
+			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+			val |= val2 & AFMT_STEREO;
+			if (set_format(as, file->f_mode, val, 0))
+				return -EIO;
+                }
+		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+                return put_user(val2 & ~AFMT_STEREO, (int *)arg);
+
+        case SNDCTL_DSP_POST:
+                return 0;
+
+        case SNDCTL_DSP_GETTRIGGER:
+                val = 0;
+                if (file->f_mode & FMODE_READ && as->usbin.flags & FLG_RUNNING) 
+                        val |= PCM_ENABLE_INPUT;
+                if (file->f_mode & FMODE_WRITE && as->usbout.flags & FLG_RUNNING) 
+                        val |= PCM_ENABLE_OUTPUT;
+                return put_user(val, (int *)arg);
+
+        case SNDCTL_DSP_SETTRIGGER:
+                get_user_ret(val, (int *)arg, -EFAULT);
+                if (file->f_mode & FMODE_READ) {
+                        if (val & PCM_ENABLE_INPUT) {
+                                if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
+                                        return ret;
+                                usbin_start(as);
+                        } else
+                                usbin_stop(as);
+                }
+                if (file->f_mode & FMODE_WRITE) {
+                        if (val & PCM_ENABLE_OUTPUT) {
+                                if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
+                                        return ret;
+                                usbout_start(as);
+                        } else
+                                usbout_stop(as);
+                }
+                return 0;
+
+        case SNDCTL_DSP_GETOSPACE:
+                if (!(file->f_mode & FMODE_WRITE))
+                        return -EINVAL;
+                if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
+                        return val;
+                spin_lock_irqsave(&as->lock, flags);
+                abinfo.fragsize = as->usbout.dma.fragsize;
+                abinfo.bytes = as->usbout.dma.dmasize - as->usbout.dma.count;
+                abinfo.fragstotal = as->usbout.dma.numfrag;
+                abinfo.fragments = abinfo.bytes >> as->usbout.dma.fragshift;      
+                spin_unlock_irqrestore(&as->lock, flags);
+                return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+        case SNDCTL_DSP_GETISPACE:
+                if (!(file->f_mode & FMODE_READ))
+                        return -EINVAL;
+                if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)
+                        return val;
+                spin_lock_irqsave(&as->lock, flags);
+                abinfo.fragsize = as->usbin.dma.fragsize;
+                abinfo.bytes = as->usbin.dma.count;
+                abinfo.fragstotal = as->usbin.dma.numfrag;
+                abinfo.fragments = abinfo.bytes >> as->usbin.dma.fragshift;      
+                spin_unlock_irqrestore(&as->lock, flags);
+                return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+                
+        case SNDCTL_DSP_NONBLOCK:
+                file->f_flags |= O_NONBLOCK;
+                return 0;
+
+        case SNDCTL_DSP_GETODELAY:
+                if (!(file->f_mode & FMODE_WRITE))
+                        return -EINVAL;
+                spin_lock_irqsave(&as->lock, flags);
+                val = as->usbout.dma.count;
+                spin_unlock_irqrestore(&as->lock, flags);
+                return put_user(val, (int *)arg);
+
+        case SNDCTL_DSP_GETIPTR:
+                if (!(file->f_mode & FMODE_READ))
+                        return -EINVAL;
+                spin_lock_irqsave(&as->lock, flags);
+                cinfo.bytes = as->usbin.dma.total_bytes;
+                cinfo.blocks = as->usbin.dma.count >> as->usbin.dma.fragshift;
+                cinfo.ptr = as->usbin.dma.wrptr;
+                if (as->usbin.dma.mapped)
+                        as->usbin.dma.count &= as->usbin.dma.fragsize-1;
+                spin_unlock_irqrestore(&as->lock, flags);
+                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+        case SNDCTL_DSP_GETOPTR:
+                if (!(file->f_mode & FMODE_WRITE))
+                        return -EINVAL;
+                spin_lock_irqsave(&as->lock, flags);
+                cinfo.bytes = as->usbout.dma.total_bytes;
+                cinfo.blocks = as->usbout.dma.count >> as->usbout.dma.fragshift;
+                cinfo.ptr = as->usbout.dma.rdptr;
+                if (as->usbout.dma.mapped)
+                        as->usbout.dma.count &= as->usbout.dma.fragsize-1;
+                spin_unlock_irqrestore(&as->lock, flags);
+                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+       case SNDCTL_DSP_GETBLKSIZE:
+                if (file->f_mode & FMODE_WRITE) {
+                        if ((val = prog_dmabuf_out(as)))
+                                return val;
+                        return put_user(as->usbout.dma.fragsize, (int *)arg);
+                }
+                if ((val = prog_dmabuf_in(as)))
+                        return val;
+                return put_user(as->usbin.dma.fragsize, (int *)arg);
+
+        case SNDCTL_DSP_SETFRAGMENT:
+                get_user_ret(val, (int *)arg, -EFAULT);
+                if (file->f_mode & FMODE_READ) {
+                        as->usbin.dma.ossfragshift = val & 0xffff;
+                        as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff;
+                        if (as->usbin.dma.ossfragshift < 4)
+                                as->usbin.dma.ossfragshift = 4;
+                        if (as->usbin.dma.ossfragshift > 15)
+                                as->usbin.dma.ossfragshift = 15;
+                        if (as->usbin.dma.ossmaxfrags < 4)
+                                as->usbin.dma.ossmaxfrags = 4;
+                }
+                if (file->f_mode & FMODE_WRITE) {
+                        as->usbout.dma.ossfragshift = val & 0xffff;
+                        as->usbout.dma.ossmaxfrags = (val >> 16) & 0xffff;
+                        if (as->usbout.dma.ossfragshift < 4)
+                                as->usbout.dma.ossfragshift = 4;
+                        if (as->usbout.dma.ossfragshift > 15)
+                                as->usbout.dma.ossfragshift = 15;
+                        if (as->usbout.dma.ossmaxfrags < 4)
+                                as->usbout.dma.ossmaxfrags = 4;
+                }
+                return 0;
+
+        case SNDCTL_DSP_SUBDIVIDE:
+                if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) ||
+                    (file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision))
+                        return -EINVAL;
+                get_user_ret(val, (int *)arg, -EFAULT);
+                if (val != 1 && val != 2 && val != 4)
+                        return -EINVAL;
+                if (file->f_mode & FMODE_READ)
+                        as->usbin.dma.subdivision = val;
+                if (file->f_mode & FMODE_WRITE)
+                        as->usbout.dma.subdivision = val;
+                return 0;
+
+        case SOUND_PCM_READ_RATE:
+                return put_user((file->f_mode & FMODE_READ) ? as->usbin.dma.srate : as->usbout.dma.srate, (int *)arg);
+
+        case SOUND_PCM_READ_CHANNELS:
+		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+                return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, (int *)arg);
+
+        case SOUND_PCM_READ_BITS:
+		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+		return put_user(AFMT_IS16BIT(val2) ? 16 : 8, (int *)arg);
+
+        case SOUND_PCM_WRITE_FILTER:
+        case SNDCTL_DSP_SETSYNCRO:
+        case SOUND_PCM_READ_FILTER:
+                return -EINVAL;
+        }
+        return -ENOIOCTLCMD;
+}
+
+static int usb_audio_open(struct inode *inode, struct file *file)
+{
+        int minor = MINOR(inode->i_rdev);
+	DECLARE_WAITQUEUE(wait, current);
+	struct list_head *devs, *adevs;
+	struct usb_audiodev *as;
+        struct usb_audio_state *s;
+
+	for (;;) {
+		down(&open_sem);
+		for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) {
+			s = list_entry(devs, struct usb_audio_state, audiodev);
+			for (adevs = s->audiolist.next; adevs != &s->audiolist; adevs = adevs->next) {
+				as = list_entry(adevs, struct usb_audiodev, list);
+				if (!((as->dev_audio ^ minor) & ~0xf))
+					goto device_found;
+			}
+		}
+		up(&open_sem);
+		return -ENODEV;
+
+	device_found:
+		if (!s->usbdev) {
+			up(&open_sem);
+			return -EIO;
+		}
+		/* wait for device to become free */
+		if (!(as->open_mode & file->f_mode))
+			break;
+		if (file->f_flags & O_NONBLOCK) {
+			up(&open_sem);
+                        return -EBUSY;
+                }
+		__set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&open_wait, &wait);
+                up(&open_sem);
+		schedule();
+		__set_current_state(TASK_RUNNING);
+		remove_wait_queue(&open_wait, &wait);
+                if (signal_pending(current))
+                        return -ERESTARTSYS;
+        }
+	if (file->f_mode & FMODE_READ)
+                as->usbin.dma.ossfragshift = as->usbin.dma.ossmaxfrags = as->usbin.dma.subdivision = 0;
+	if (file->f_mode & FMODE_WRITE)
+                as->usbout.dma.ossfragshift = as->usbout.dma.ossmaxfrags = as->usbout.dma.subdivision = 0;
+	if (set_format(as, file->f_mode, ((minor & 0xf) == SND_DEV_DSP16) ? AFMT_S16_LE : AFMT_U8 /* AFMT_ULAW */, 8000)) {
+		up(&open_sem);
+		return -EIO;
+	}
+        file->private_data = as;
+        as->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+	s->count++;
+        up(&open_sem);
+        return 0;
+}
+
+static int usb_audio_release(struct inode *inode, struct file *file)
+{
+        struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+	struct usb_audio_state *s = as->state;
+
+        if (file->f_mode & FMODE_WRITE)
+                drain_out(as, file->f_flags & O_NONBLOCK);
+        down(&open_sem);
+        if (file->f_mode & FMODE_WRITE) {
+                usbout_stop(as);
+		if (s->usbdev)
+			usb_set_interface(s->usbdev, as->usbout.interface, 0);
+                dmabuf_release(&as->usbout.dma);
+		usbout_release(as);
+        }
+        if (file->f_mode & FMODE_READ) {
+                usbin_stop(as);
+		if (s->usbdev)
+			usb_set_interface(s->usbdev, as->usbin.interface, 0);
+                dmabuf_release(&as->usbin.dma);
+		usbin_release(as);
+        }
+        as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+	release(s);
+        wake_up(&open_wait);
+        return 0;
+}
 
-	void *irq_handle;
-	unsigned int irqpipe;
+static /*const*/ struct file_operations usb_audio_fops = {
+        &usb_audio_llseek,
+        &usb_audio_read,
+        &usb_audio_write,
+        NULL,  /* readdir */
+        &usb_audio_poll,
+        &usb_audio_ioctl,
+        &usb_audio_mmap,
+        &usb_audio_open,
+        NULL,   /* flush */
+        &usb_audio_release,
+        NULL,  /* fsync */
+        NULL,  /* fasync */
+        NULL,  /* check_media_change */
+        NULL,  /* revalidate */
+        NULL,  /* lock */
 };
 
+/* --------------------------------------------------------------------- */
+
+/*
+ *	TO DO in order to get to the point of building an OSS interface
+ *	structure, let alone playing music..
+ *
+ *	Use kmalloc/kfree for the descriptors we build
+ *	Write the descriptor->OSS convertor code
+ *	Figure how we deal with mixers
+ *	Check alternate configurations. For now assume we will find one
+ *	zero bandwidth (idle) config and one or more live one pers interface.
+ */
+
+static int usb_audio_probe(struct usb_device *dev);
+static void usb_audio_disconnect(struct usb_device *dev);
+
 static struct usb_driver usb_audio_driver = {
 	"audio",
 	usb_audio_probe,
@@ -32,7 +2502,7 @@
 static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
 {
 #if 0
-	struct usb_audio *aud = (struct usb_audio *)dev_id;
+	struct usb_audio_device *aud = (struct usb_audio_device *)dev_id;
 
 	printk("irq on %p\n", aud);
 #endif
@@ -41,107 +2511,943 @@
 }
 #endif
 
-static int usb_audio_probe(struct usb_device *dev)
+static void *find_descriptor(void *descstart, unsigned int desclen, void *after, 
+			     u8 dtype, int iface, int altsetting)
 {
-	struct usb_interface_descriptor *interface;
-	struct usb_audio *aud;
-	int i;
-	int na=0;
-	
-	for (i=0; i<dev->config[0].bNumInterfaces; i++) {
-		interface = &dev->config->interface[i].altsetting[0];
-
-		if (interface->bInterfaceClass != 1) 
-	        	continue;
-
-		printk(KERN_INFO "USB audio device detected.\n");
-	
-		switch(interface->bInterfaceSubClass) {
-			case 0x01:
-				printk(KERN_INFO "audio: control device\n");
-				break;
-			case 0x02:
-				printk(KERN_INFO "audio: streaming\n");
-				break;
-			case 0x03:
-				printk(KERN_INFO "audio: nonstreaming\n");
-				break;
+	u8 *p, *end, *next;
+	int ifc = -1, as = -1;
+
+	p = descstart;
+	end = p + desclen;
+	for (; p < end;) {
+		if (p[0] < 2)
+			return NULL;
+		next = p + p[0];
+		if (next > end)
+			return NULL;
+		if (p[1] == USB_DT_INTERFACE) {
+			/* minimum length of interface descriptor */
+			if (p[0] < 9)
+				return NULL;
+			ifc = p[2];
+			as = p[3];
+		}
+		if (p[1] == dtype && (!after || (void *)p > after) &&
+		    (iface == -1 || iface == ifc) && (altsetting == -1 || altsetting == as)) {
+			return p;
 		}
-		na++;
+		p = next;
 	}
-	
-	if (!na)
-		return -1;
+	return NULL;
+}
 
-	aud = kmalloc(sizeof(struct usb_audio), GFP_KERNEL);
-	if (!aud)
-		return -1;
+static void *find_csinterface_descriptor(void *descstart, unsigned int desclen, void *after, u8 dsubtype, int iface, int altsetting)
+{
+	unsigned char *p;
 
-       	memset(aud, 0, sizeof(*aud));
-       	aud->dev = dev;
-       	dev->private = aud;
+	p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, altsetting);
+	while (p) {
+		if (p[0] >= 3 && p[2] == dsubtype)
+			return p;
+		p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, altsetting);
+	}
+	return NULL;
+}
 
-/*
-	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
-		printk (KERN_INFO "Failed usb_set_configuration: Audio\n");
-		break;
+static void *find_audiocontrol_unit(void *descstart, unsigned int desclen, void *after, u8 unit, int iface)
+{
+	unsigned char *p;
+
+	p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, -1);
+	while (p) {
+		if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit)
+			return p;
+		p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, -1);
 	}
-	usb_set_protocol(dev, 0);
-	usb_set_idle(dev, 0, 0);
-*/
-        
-/*
-	aud->irqpipe = usb_rcvctrlpipe(dev, endpoint->bEndpointAddress);
-	na = usb_request_irq(dev, aud->irqpipe,
-		usb_audio_irq, endpoint->bInterval,
-		aud, &aud->irq_handle);
-	if (na) {
-		printk (KERN_WARNING "usb-audio: usb_request_irq failed (0x%x)\n", na);
+	return NULL;
+}
+
+static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, int asifin, int asifout)
+{
+	struct usb_device *dev = s->usbdev;
+	struct usb_audiodev *as;
+	struct usb_config_descriptor *config = dev->actconfig;
+	struct usb_interface_descriptor *alts;
+	struct usb_interface *iface;
+	struct audioformat *fp;
+	unsigned char *fmt;
+	unsigned int i, j, k, format;
+
+	if (!(as = kmalloc(sizeof(struct usb_audiodev), GFP_KERNEL)))
+		return;
+	memset(as, 0, sizeof(struct usb_audiodev));
+	init_waitqueue_head(&as->usbin.dma.wait);
+	init_waitqueue_head(&as->usbout.dma.wait);
+	spin_lock_init(&as->lock);
+	as->state = s;
+	as->usbin.interface = asifin;
+	as->usbout.interface = asifout;
+	/* search for input formats */
+	if (asifin >= 0) {
+		iface = &config->interface[asifin];
+		for (i = 0; i < iface->num_altsetting; i++) {
+			alts = &iface->altsetting[i];
+			if (alts->bInterfaceClass != USB_CLASS_AUDIO || alts->bInterfaceSubClass != 2)
+				continue;
+			if (alts->bNumEndpoints < 1) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u does not have an endpoint\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			if ((alts->endpoint[0].bmAttributes & 0x03) != 0x01 ||
+			    !(alts->endpoint[0].bEndpointAddress & 0x80)) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u first endpoint not isochronous in\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifin, i);
+			if (!fmt) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u format not supported\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
+			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifin, i);
+			if (!fmt) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
+				       dev->devnum, asifin, i, fmt[4], fmt[5]);
+				continue;
+			}
+			if (as->numfmtin >= MAXFORMATS)
+				continue;
+			fp = &as->fmtin[as->numfmtin++];
+			if (fmt[5] == 2)
+				format &= (AFMT_U16_LE | AFMT_S16_LE);
+			else
+				format &= (AFMT_U8 | AFMT_S8);
+			if (fmt[4] == 2)
+				format |= AFMT_STEREO;
+			fp->format = format;
+			fp->altsetting = i;
+			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
+			for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
+				k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
+				if (k > fp->sratehi)
+					fp->sratehi = k;
+				if (k < fp->sratelo)
+					fp->sratelo = k;
+			}
+			printk(KERN_INFO "usb_audio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u\n", 
+			       dev->devnum, asifin, i, fp->format, fp->sratelo, fp->sratehi);
+		}
+	}
+	/* search for output formats */
+	if (asifout >= 0) {
+		iface = &config->interface[asifout];
+		for (i = 0; i < iface->num_altsetting; i++) {
+			alts = &iface->altsetting[i];
+			if (alts->bInterfaceClass != USB_CLASS_AUDIO || alts->bInterfaceSubClass != 2)
+				continue;
+			if (alts->bNumEndpoints < 1) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u does not have an endpoint\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			if ((alts->endpoint[0].bmAttributes & 0x03) != 0x01 ||
+			    (alts->endpoint[0].bEndpointAddress & 0x80)) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u first endpoint not isochronous out\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifout, i);
+			if (!fmt) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u format not supported\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
+			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifout, i);
+			if (!fmt) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
+				printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
+				       dev->devnum, asifout, i, fmt[4], fmt[5]);
+				continue;
+			}
+			if (as->numfmtout >= MAXFORMATS)
+				continue;
+			fp = &as->fmtout[as->numfmtout++];
+			if (fmt[5] == 2)
+				format &= (AFMT_U16_LE | AFMT_S16_LE);
+			else
+				format &= (AFMT_U8 | AFMT_S8);
+			if (fmt[4] == 2)
+				format |= AFMT_STEREO;
+			fp->format = format;
+			fp->altsetting = i;
+			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
+			for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
+				k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
+				if (k > fp->sratehi)
+					fp->sratehi = k;
+				if (k < fp->sratelo)
+					fp->sratelo = k;
+			}
+			printk(KERN_INFO "usb_audio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u\n", 
+			       dev->devnum, asifout, i, fp->format, fp->sratelo, fp->sratehi);
+		}
+	}
+	if (as->numfmtin == 0 && as->numfmtout == 0) {
+		kfree(as);
+		return;
+	}
+	if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) {
+		printk(KERN_ERR "usb_audio: cannot register dsp\n");
+		kfree(as);
+		return;
+	}
+	/* everything successful */
+	list_add_tail(&as->list, &s->audiolist);
+}
+
+struct consmixstate {
+	struct usb_audio_state *s;
+	unsigned char *buffer;
+	unsigned int buflen;
+	unsigned int ctrlif;
+	struct mixerchannel mixch[SOUND_MIXER_NRDEVICES];
+	unsigned int nrmixch;
+	unsigned int mixchmask;
+	unsigned long unitbitmap[32/sizeof(unsigned long)];
+	/* return values */
+	unsigned int nrchannels;
+	unsigned int termtype;
+	unsigned int chconfig;
+};
+
+static struct mixerchannel *getmixchannel(struct consmixstate *state, unsigned int nr)
+{
+	struct mixerchannel *c;
+
+	if (nr >= SOUND_MIXER_NRDEVICES) {
+		printk(KERN_ERR "usb_audio: invalid OSS mixer channel %u\n", nr);
+		return NULL;
+	}
+	if (!(state->mixchmask & (1 << nr))) {
+		printk(KERN_WARNING "usb_audio: OSS mixer channel %u already in use\n", nr);
+		return NULL;
 	}
-*/
+	c = &state->mixch[state->nrmixch++];
+	c->osschannel = nr;
+	state->mixchmask &= ~(1 << nr);
+	return c;
+}
+
+static unsigned int getvolchannel(struct consmixstate *state)
+{
+	unsigned int u;
+
+	if ((state->termtype & 0xff00) == 0x0000 && !(state->mixchmask & SOUND_MASK_VOLUME))
+		return SOUND_MIXER_VOLUME;
+	if ((state->termtype & 0xff00) == 0x0100) {
+		if (!(state->mixchmask & SOUND_MASK_PCM))
+			return SOUND_MIXER_PCM;
+		if (!(state->mixchmask & SOUND_MASK_ALTPCM))
+			return SOUND_MIXER_ALTPCM;
+	}
+	if ((state->termtype & 0xff00) == 0x0200 && !(state->mixchmask & SOUND_MASK_MIC))
+		return SOUND_MIXER_MIC;
+	if ((state->termtype & 0xff00) == 0x0300 && !(state->mixchmask & SOUND_MASK_SPEAKER))
+		return SOUND_MIXER_SPEAKER;
+	if ((state->termtype & 0xff00) == 0x0300 && !(state->mixchmask & SOUND_MASK_SPEAKER))
+		return SOUND_MIXER_SPEAKER;
+	if ((state->termtype & 0xff00) == 0x0500) {
+		if (!(state->mixchmask & SOUND_MASK_PHONEIN))
+			return SOUND_MIXER_PHONEIN;
+		if (!(state->mixchmask & SOUND_MASK_PHONEOUT))
+			return SOUND_MIXER_PHONEOUT;
+	}
+	if (state->termtype >= 0x710 && state->termtype <= 0x711 && !(state->mixchmask & SOUND_MASK_RADIO))
+		return SOUND_MIXER_RADIO;
+	if (state->termtype >= 0x709 && state->termtype <= 0x70f && !(state->mixchmask & SOUND_MASK_VIDEO))
+		return SOUND_MIXER_VIDEO;
+	u = ffs(state->mixchmask & (SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_LINE3 |
+				    SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_DIGITAL3));
+	return u-1;
+}
+
+static void prepmixch(struct consmixstate *state)
+{
+	struct usb_device *dev = state->s->usbdev;
+	struct mixerchannel *ch;
+	unsigned char buf[2];
+	__s16 v1;
+	unsigned int v2, v3;
+
+	if (!state->nrmixch || state->nrmixch > SOUND_MIXER_NRDEVICES)
+		return;
+	ch = &state->mixch[state->nrmixch-1];
+	switch (ch->selector) {
+	case 0:  /* mixer unit request */
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+			goto err;
+		ch->minval = buf[0] | (buf[1] << 8);
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+			goto err;
+		ch->maxval = buf[0] | (buf[1] << 8);
+		v2 = ch->maxval - ch->minval;
+		if (!v2)
+			v2 = 1;
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+			goto err;
+		v1 = buf[0] | (buf[1] << 8);
+		v3 = v1 - ch->minval;
+		v3 = 100 * v3 / v2;
+		if (v3 > 100)
+			v3 = 100;
+		ch->value = v3;
+		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
+			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+					    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
+					    state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+			goto err;
+			v1 = buf[0] | (buf[1] << 8);
+			v3 = v1 - ch->minval;
+			v3 = 100 * v3 / v2;
+			if (v3 > 100)
+				v3 = 100;
+		}
+		ch->value |= v3 << 8;
+		break;
 
-	list_add(&aud->list, &usb_audio_list);
+		/* various feature unit controls */
+	case VOLUME_CONTROL:
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+			goto err;
+		ch->minval = buf[0] | (buf[1] << 8);
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+			goto err;
+		ch->maxval = buf[0] | (buf[1] << 8);
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+			goto err;
+		v1 = buf[0] | (buf[1] << 8);
+		v2 = ch->maxval - ch->minval;
+		v3 = v1 - ch->minval;
+		if (!v2)
+			v2 = 1;
+		v3 = 100 * v3 / v2;
+		if (v3 > 100)
+			v3 = 100;
+		ch->value = v3;
+		if (ch->chnum != 0) {
+			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				goto err;
+			v1 = buf[0] | (buf[1] << 8);
+			v3 = v1 - ch->minval;
+			v3 = 100 * v3 / v2;
+			if (v3 > 100)
+				v3 = 100;
+		}
+		ch->value |= v3 << 8;
+		break;
 		
-	return 0;
+	case BASS_CONTROL:
+	case MID_CONTROL:
+	case TREBLE_CONTROL:
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+			goto err;
+		ch->minval = buf[0] << 8;
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+			goto err;
+		ch->maxval = buf[0] << 8;
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+			goto err;
+		v1 = buf[0] << 8;
+		v2 = ch->maxval - ch->minval;
+		v3 = v1 - ch->minval;
+		if (!v2)
+			v2 = 1;
+		v3 = 100 * v3 / v2;
+		if (v3 > 100)
+			v3 = 100;
+		ch->value = v3;
+		if (ch->chnum != 0) {
+			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+				goto err;
+			v1 = buf[0] << 8;
+			v3 = v1 - ch->minval;
+			v3 = 100 * v3 / v2;
+			if (v3 > 100)
+				v3 = 100;
+		}
+		ch->value |= v3 << 8;
+		break;
+		
+	default:
+		goto err;
+	}
+	return;
+
+ err:
+	printk(KERN_ERR "usb_audio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
+	       dev->devnum, state->ctrlif, ch->unitid, ch->chnum, ch->selector);
+	if (state->nrmixch)
+		state->nrmixch--;
 }
 
-static void usb_audio_disconnect(struct usb_device *dev)
+
+static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid);
+
+extern inline int checkmixbmap(unsigned char *bmap, unsigned char flg, unsigned int inidx, unsigned int numoch)
+{
+	unsigned int idx;
+
+	idx = inidx*numoch;
+	if (!(bmap[idx >> 3] & (1 << (idx & 7))))
+		return 0;
+	if (!(flg & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+		return 1;
+	idx = (inidx+!!(flg & MIXFLG_STEREOIN))*numoch+!!(flg & MIXFLG_STEREOOUT);
+	if (!(bmap[idx >> 3] & (1 << (idx & 7))))
+		return 0;
+	return 1;
+}
+
+static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer)
+{
+	unsigned int nroutch = mixer[5+mixer[4]];
+	unsigned int chidx[SOUND_MIXER_NRDEVICES+1];
+	unsigned int termt[SOUND_MIXER_NRDEVICES];
+	unsigned char flg = (nroutch >= 2) ? MIXFLG_STEREOOUT : 0;
+	struct mixerchannel *ch;
+	unsigned int i;
+
+	if (!mixer[4]) {
+		printk(KERN_ERR "usb_audio: unit %u invalid MIXER_UNIT descriptor\n", mixer[3]);
+		return;
+	}
+	if (mixer[4] > SOUND_MIXER_NRDEVICES) {
+		printk(KERN_ERR "usb_audio: mixer unit %u: too many input pins\n", mixer[3]);
+		return;
+	}
+	chidx[0] = 0;
+	for (i = 0; i < mixer[4]; i++) {
+		usb_audio_recurseunit(state, mixer[5+i]);
+		chidx[i+1] = chidx[i] + state->nrchannels;
+		termt[i] = state->termtype;
+	}
+	state->termtype = 0;
+	state->chconfig = mixer[6+mixer[4]] | (mixer[7+mixer[4]] << 8);
+	if (mixer[0] < 10+mixer[4]+((nroutch * chidx[mixer[4]] + 7) >> 3)) {
+		printk(KERN_ERR "usb_audio: unit %u invalid MIXER_UNIT descriptor (bitmap too small)\n", mixer[3]);
+		return;
+	}
+	for (i = 0; i < mixer[4]; i++) {
+		state->termtype = termt[i];
+		if (chidx[i+1]-chidx[i] >= 2) {
+			flg |= MIXFLG_STEREOIN;
+			if (checkmixbmap(&mixer[9+mixer[4]], flg, chidx[i], nroutch)) {
+				ch = getmixchannel(state, getvolchannel(state));
+				if (ch) {
+					ch->unitid = mixer[3];
+					ch->selector = 0;
+					ch->chnum = chidx[i]+1;
+					ch->flags = flg;
+					prepmixch(state);
+				}
+				continue;
+			}
+		}
+		flg &= ~MIXFLG_STEREOIN;
+		if (checkmixbmap(&mixer[9+mixer[4]], flg, chidx[i], nroutch)) {
+			ch = getmixchannel(state, getvolchannel(state));
+			if (ch) {
+				ch->unitid = mixer[3];
+				ch->selector = 0;
+				ch->chnum = chidx[i]+1;
+				ch->flags = flg;
+				prepmixch(state);
+			}
+		}
+	}	
+	state->termtype = 0;
+}
+
+static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector)
 {
-	struct usb_audio *aud = (struct usb_audio*) dev->private;
+	unsigned int chnum, i;
 
-	if (!aud)
+	if (!selector[4]) {
+		printk(KERN_ERR "usb_audio: unit %u invalid SELECTOR_UNIT descriptor\n", selector[3]);
 		return;
+	}
+	usb_audio_recurseunit(state, selector[5]);
+	chnum = state->nrchannels;
+	for (i = 1; i < selector[4]; i++) {
+		usb_audio_recurseunit(state, selector[5+i]);
+		if (chnum != state->nrchannels) {
+			printk(KERN_ERR "usb_audio: selector unit %u: input pins with varying channel numbers\n", selector[3]);
+			state->termtype = 0;
+			state->chconfig = 0;
+			state->nrchannels = 0;
+			return;
+		}
+	}
+	state->termtype = 0;
+	state->chconfig = 0;
+}
 
-       	list_del(&aud->list);
+/* in the future we might try to handle 3D etc. effect units */
 
-	usb_release_irq(aud->dev, aud->irq_handle, aud->irqpipe);
+static void usb_audio_processingunit(struct consmixstate *state, unsigned char *proc)
+{
+	unsigned int i;
 
-       	kfree(aud);
-       	dev->private = NULL;
+	for (i = 0; i < proc[6]; i++)
+		usb_audio_recurseunit(state, proc[7+i]);
+	state->nrchannels = proc[7+proc[6]];
+	state->termtype = 0;
+	state->chconfig = proc[8+proc[6]] | (proc[9+proc[6]] << 8);
 }
 
-int usb_audio_init(void)
+static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr)
 {
-	usb_register(&usb_audio_driver);
+	struct mixerchannel *ch;
+	unsigned short chftr, mchftr;
+
+	usb_audio_recurseunit(state, ftr[4]);
+	if (state->nrchannels == 0) {
+		printk(KERN_ERR "usb_audio: feature unit %u source has no channels\n", ftr[3]);
+		return;
+	}
+	if (state->nrchannels > 2)
+		printk(KERN_WARNING "usb_audio: feature unit %u: OSS mixer interface does not support more than 2 channels\n", ftr[3]);
+	if (ftr[0] < 7+ftr[5]*(1+state->nrchannels)) {
+		printk(KERN_ERR "usb_audio: unit %u: invalid FEATURE_UNIT descriptor\n", ftr[3]);
+		return;
+	}
+	mchftr = ftr[6];
+	chftr = ftr[6+ftr[5]];
+	if (state->nrchannels > 1)
+		chftr &= ftr[6+2*ftr[5]];
+	/* volume control */
+	if (chftr & 2) {
+		ch = getmixchannel(state, getvolchannel(state));
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = VOLUME_CONTROL;
+			ch->chnum = 1;
+			ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+			prepmixch(state);
+		}
+	} else if (mchftr & 2) {
+		ch = getmixchannel(state, getvolchannel(state));
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = VOLUME_CONTROL;
+			ch->chnum = 0;
+			ch->flags = 0;
+			prepmixch(state);
+		}
+	}
+	/* bass control */
+	if (chftr & 4) {
+		ch = getmixchannel(state, SOUND_MIXER_BASS);
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = BASS_CONTROL;
+			ch->chnum = 1;
+			ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+			prepmixch(state);
+		}
+	} else if (mchftr & 4) {
+		ch = getmixchannel(state, getvolchannel(state));
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = BASS_CONTROL;
+			ch->chnum = 0;
+			ch->flags = 0;
+			prepmixch(state);
+		}
+	}
+	/* treble control */
+	if (chftr & 16) {
+		ch = getmixchannel(state, SOUND_MIXER_TREBLE);
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = TREBLE_CONTROL;
+			ch->chnum = 1;
+			ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+			prepmixch(state);
+		}
+	} else if (mchftr & 16) {
+		ch = getmixchannel(state, getvolchannel(state));
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = TREBLE_CONTROL;
+			ch->chnum = 0;
+			ch->flags = 0;
+			prepmixch(state);
+		}
+	}
+}
+
+static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid)
+{
+	unsigned char *p1;
+
+	if (test_and_set_bit(unitid, &state->unitbitmap)) {
+		printk(KERN_ERR "usb_audio: mixer path recursion detected, unit %d!\n", unitid);
+		return;
+	}
+	p1 = find_audiocontrol_unit(state->buffer, state->buflen, NULL, unitid, state->ctrlif);
+	if (!p1) {
+		printk(KERN_ERR "usb_audio: unit %d not found!\n", unitid);
+		return;
+	}
+	state->nrchannels = 0;
+	state->termtype = 0;
+	state->chconfig = 0;
+	switch (p1[2]) {
+	case INPUT_TERMINAL:
+		if (p1[0] < 12) {
+			printk(KERN_ERR "usb_audio: unit %u: invalid INPUT_TERMINAL descriptor\n", unitid);
+			return;
+		}
+		state->nrchannels = p1[7];
+		state->termtype = p1[4] | (p1[5] << 8);
+		state->chconfig = p1[8] | (p1[9] << 8);
+		return;
+
+	case MIXER_UNIT:
+		if (p1[0] < 10 || p1[0] < 10+p1[4]) {
+			printk(KERN_ERR "usb_audio: unit %u: invalid MIXER_UNIT descriptor\n", unitid);
+			return;
+		}
+		usb_audio_mixerunit(state, p1);
+		return;
+
+	case SELECTOR_UNIT:
+		if (p1[0] < 6 || p1[0] < 6+p1[4]) {
+			printk(KERN_ERR "usb_audio: unit %u: invalid SELECTOR_UNIT descriptor\n", unitid);
+			return;
+		}
+		usb_audio_selectorunit(state, p1);
+		return;
+
+	case FEATURE_UNIT:
+		if (p1[0] < 7 || p1[0] < 7+p1[5]) {
+			printk(KERN_ERR "usb_audio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid);
+			return;
+		}
+		usb_audio_featureunit(state, p1);
+		return;		
+
+	case PROCESSING_UNIT:
+		if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]] || p1[0] < 13+p1[6]+p1[11+p1[6]]+p1[13+p1[6]+p1[11+p1[6]]]) {
+			printk(KERN_ERR "usb_audio: unit %u: invalid PROCESSING_UNIT descriptor\n", unitid);
+			return;
+		}
+		usb_audio_processingunit(state, p1);
+		return;		
+
+	case EXTENSION_UNIT:
+		if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) {
+			printk(KERN_ERR "usb_audio: unit %u: invalid EXTENSION_UNIT descriptor\n", unitid);
+			return;
+		}
+		{
+			unsigned int i;
+			
+			for (i = 0; i < p1[6]; i++)
+				usb_audio_recurseunit(state, p1[7+i]);
+		}
+		state->nrchannels = p1[7+p1[6]];
+		state->chconfig = p1[8+p1[6]] | (p1[9+p1[6]] << 8);
+		state->termtype = 0;
+		return;
+
+	default:
+		printk(KERN_ERR "usb_audio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
+		return;
+	}
+}
+
+static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif, unsigned char *oterm)
+{
+	struct usb_mixerdev *ms;
+	struct consmixstate state;
+
+	memset(&state, 0, sizeof(state));
+	state.s = s;
+	state.nrmixch = 0;
+	state.mixchmask = ~0;
+	state.buffer = buffer;
+	state.buflen = buflen;
+	state.ctrlif = ctrlif;
+	set_bit(oterm[3], &state.unitbitmap);  /* mark terminal ID as visited */
+	printk(KERN_INFO "usb_audio: constructing mixer for Terminal %u type 0x%04x\n",
+	       oterm[3], oterm[4] | (oterm[5] << 8));
+	usb_audio_recurseunit(&state, oterm[7]);
+	if (!state.nrmixch) {
+		printk(KERN_INFO "usb_audio: no mixer controls found for Terminal %u\n", oterm[3]);
+		return;
+	}
+	if (!(ms = kmalloc(sizeof(struct usb_mixerdev)+state.nrmixch*sizeof(struct mixerchannel), GFP_KERNEL)))
+		return;
+	memset(ms, 0, sizeof(struct usb_mixerdev));
+	memcpy(&ms->ch, &state.mixch, state.nrmixch*sizeof(struct mixerchannel));
+	ms->state = s;
+	ms->iface = ctrlif;
+	ms->numch = state.nrmixch;
+	if ((ms->dev_mixer = register_sound_mixer(&usb_mixer_fops, -1)) < 0) {
+		printk(KERN_ERR "usb_audio: cannot register mixer\n");
+		kfree(ms);
+		return;
+	}
+	list_add_tail(&ms->list, &s->mixerlist);
+}
+
+static int usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif)
+{
+	struct usb_audio_state *s;
+	struct usb_config_descriptor *config = dev->actconfig;
+	struct usb_interface *iface;
+	unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
+	unsigned char *p1;
+	unsigned int i, j, numifin = 0, numifout = 0;
+
+	if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL)))
+		return -1;
+	memset(s, 0, sizeof(struct usb_audio_state));
+	INIT_LIST_HEAD(&s->audiolist);
+	INIT_LIST_HEAD(&s->mixerlist);
+	s->usbdev = dev;
+	s->count = 1;
+	/* find audiocontrol interface */
+	if (!(p1 = find_csinterface_descriptor(buffer, buflen, NULL, HEADER, ctrlif, -1))) {
+		printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u no HEADER found\n",
+		       dev->devnum, ctrlif);
+		goto ret;
+	}
+	if (p1[0] < 8 + p1[7]) {
+		printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u HEADER error\n",
+		       dev->devnum, ctrlif);
+		goto ret;
+	}
+	if (!p1[7])
+		printk(KERN_INFO "usb_audio: device %d audiocontrol interface %u has no AudioStreaming and MidiStreaming interfaces\n",
+		       dev->devnum, ctrlif);
+	for (i = 0; i < p1[7]; i++) {
+		j = p1[8+i];
+		if (j >= config->bNumInterfaces) {
+			printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u interface %u does not exist\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		iface = &config->interface[j];
+		if (iface->altsetting[0].bInterfaceClass != USB_CLASS_AUDIO) {
+			printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		if (iface->altsetting[0].bInterfaceSubClass == 3) {
+			printk(KERN_INFO "usb_audio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		if (iface->altsetting[0].bInterfaceSubClass != 2) {
+			printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		if (iface->num_altsetting < 2 ||
+		    iface->altsetting[0].bNumEndpoints > 0) {
+			printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u altsetting 0 not zero bandwidth\n",
+			       dev->devnum, ctrlif);
+			continue;
+		}
+		if (iface->altsetting[1].bNumEndpoints < 1) {
+			printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u interface %u has no endpoint\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		/* note: this requires the data endpoint to be ep0 and the optional sync
+		   ep to be ep1, which seems to be the case */
+		if (iface->altsetting[1].endpoint[0].bEndpointAddress & USB_DIR_IN) {
+			if (numifin < USB_MAXINTERFACES)
+				ifin[numifin++] = j;
+		} else {
+			if (numifout < USB_MAXINTERFACES)
+				ifout[numifout++] = j;
+		}
+	}
+	printk(KERN_INFO "usb_audio: device %d audiocontrol interface %u has %u input and %u output AudioStreaming interfaces\n",
+	       dev->devnum, ctrlif, numifin, numifout);
+	for (i = 0; i < numifin && i < numifout; i++)
+		usb_audio_parsestreaming(s, buffer, buflen, ifin[i], ifout[i]);
+	for (j = i; j < numifin; j++)
+		usb_audio_parsestreaming(s, buffer, buflen, ifin[i], -1);
+	for (j = i; j < numifout; j++)
+		usb_audio_parsestreaming(s, buffer, buflen, -1, ifout[i]);
+	/* now walk through all OUTPUT_TERMINAL descriptors to search for mixers */
+	p1 = find_csinterface_descriptor(buffer, buflen, NULL, OUTPUT_TERMINAL, ctrlif, -1);
+	while (p1) {
+		if (p1[0] >= 9)
+			usb_audio_constructmixer(s, buffer, buflen, ctrlif, p1);
+		p1 = find_csinterface_descriptor(buffer, buflen, p1, OUTPUT_TERMINAL, ctrlif, -1);
+	}
+
+ ret:
+	if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) {
+		kfree(s);
+		return -1;
+	}
+	/* everything successful */
+	dev->private = s;
+	down(&open_sem);
+	list_add_tail(&s->audiodev, &audiodevs);
+	up(&open_sem);
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
-/*
- *	Support functions for parsing
- */
- 
-void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data)
+/* we only care for the currently active configuration */
+
+static int usb_audio_probe(struct usb_device *dev)
 {
-#ifdef AUDIO_DEBUG
-	printk(KERN_DEBUG "usb_audio_interface.\n");
-#endif
+	struct usb_config_descriptor *config = dev->actconfig;	
+	unsigned char *buffer;
+	unsigned char buf[8];
+	unsigned int i, buflen;
+	int ret;
+
+	for (i = 0; i < config->bNumInterfaces; i++)
+		if (config->interface[i].altsetting[0].bInterfaceClass == USB_CLASS_AUDIO &&
+		    config->interface[i].altsetting[0].bInterfaceSubClass == 1)  /* audiocontrol interface found */
+			goto audioctrlfound;
+	printk(KERN_DEBUG "usb_audio: vendor id 0x%04x, product id 0x%04x contains no AudioControl interface\n",
+	       dev->descriptor.idVendor, dev->descriptor.idProduct);
+	return -1;
+
+ audioctrlfound:
+	/* find which configuration number is active */
+	for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+		if (dev->config+i == config)
+			goto configfound;
+	printk(KERN_ERR "usb_audio: cannot find active configuration number of device %d\n", dev->devnum);
+	return -1;
+
+ configfound:
+	ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8);
+	if (ret) {
+		printk(KERN_ERR "usb_audio: cannot get first 8 bytes of config descriptor %d of device %d\n", i, dev->devnum);
+		return -1;
+	}
+	if (buf[1] != USB_DT_CONFIG || buf[0] < 9) {
+		printk(KERN_ERR "usb_audio: invalid config descriptor %d of device %d\n", i, dev->devnum);
+		return -1;
+	}
+	buflen = buf[2] | (buf[3] << 8);
+	if (!(buffer = kmalloc(buflen, GFP_KERNEL)))
+		return -1;
+	ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen);
+	if (ret) {
+		kfree(buffer);
+		printk(KERN_ERR "usb_audio: cannot get config descriptor %d of device %d\n", i, dev->devnum);
+		return -1;
+	}
+	/* find first audio control interface; we currently cannot handle more than one */
+	for (i = 0; i < config->bNumInterfaces; i++) {
+		if (config->interface[i].altsetting[0].bInterfaceClass != USB_CLASS_AUDIO ||
+		    config->interface[i].altsetting[0].bInterfaceSubClass != 1)
+			continue;
+		/* audiocontrol interface found */
+		if (!usb_audio_parsecontrol(dev, buffer, buflen, i)) 
+			return 0;
+	}
+	return -1;
 }
 
-void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data)
+
+/* a revoke facility would make things simpler */
+
+static void usb_audio_disconnect(struct usb_device *dev)
 {
-#ifdef AUDIO_DEBUG
-	printk(KERN_DEBUG "usb_audio_interface.\n");
+	struct usb_audio_state *s = (struct usb_audio_state *)dev->private;
+	struct list_head *list;
+	struct usb_audiodev *as;
+	struct usb_mixerdev *ms;
+
+        down(&open_sem);
+	list_del(&s->audiodev);
+	INIT_LIST_HEAD(&s->audiodev);
+	s->usbdev = NULL;
+	/* deregister all audio and mixer devices, so no new processes can open this device */
+	for(list = s->audiolist.next; list != &s->audiolist; list = list->next) {
+		as = list_entry(list, struct usb_audiodev, list);
+		if (as->dev_audio >= 0)
+			unregister_sound_dsp(as->dev_audio);
+		as->dev_audio = -1;
+	}
+	for(list = s->mixerlist.next; list != &s->mixerlist; list = list->next) {
+		ms = list_entry(list, struct usb_mixerdev, list);
+		if (ms->dev_mixer >= 0)
+			unregister_sound_mixer(ms->dev_mixer);
+	}
+#if 0
+	if(aud->irq_handle)
+		usb_release_irq(dev, aud->irq_handle, aud->irqpipe);
+	aud->irq_handle = NULL;
 #endif
+	release(s);
+        wake_up(&open_wait);
+	dev->private = NULL;
+}
+
+int usb_audio_init(void)
+{
+	usb_register(&usb_audio_driver);
+	return 0;
 }
 
 #ifdef MODULE
@@ -156,4 +3462,3 @@
 }
 
 #endif
-
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/audio.h linux/drivers/usb/audio.h
--- v2.3.19/linux/drivers/usb/audio.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/audio.h	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,116 @@
+#define USB_DT_CS_DEVICE                0x21
+#define USB_DT_CS_CONFIG                0x22
+#define USB_DT_CS_STRING                0x23
+#define USB_DT_CS_INTERFACE             0x24
+#define USB_DT_CS_ENDPOINT              0x25
+
+#define CS_AUDIO_UNDEFINED		0x20
+#define CS_AUDIO_DEVICE			0x21
+#define CS_AUDIO_CONFIGURATION		0x22
+#define CS_AUDIO_STRING			0x23
+#define CS_AUDIO_INTERFACE		0x24
+#define CS_AUDIO_ENDPOINT		0x25
+
+#define HEADER				0x01
+#define INPUT_TERMINAL			0x02
+#define OUTPUT_TERMINAL			0x03
+#define MIXER_UNIT			0x04
+#define SELECTOR_UNIT			0x05
+#define FEATURE_UNIT			0x06
+#define PROCESSING_UNIT			0x07
+#define EXTENSION_UNIT			0x08
+
+#define AS_GENERAL			0x01
+#define FORMAT_TYPE			0x02
+#define FORMAT_SPECIFIC			0x03
+
+#define EP_GENERAL			0x01
+
+#define MAX_CHAN			9
+#define MAX_FREQ			16
+#define MAX_IFACE			8
+#define MAX_FORMAT			8
+#define MAX_ALT				8
+
+struct usb_audio_terminal
+{	
+	u8	flags;
+	u8	assoc;
+	u16	type;			/* Mic etc */
+	u8	channels;
+	u8	source;
+	u16	chancfg;
+};
+
+struct usb_audio_format
+{
+	u8	type;
+	u8	channels;
+	u8	num_freq;
+	u8	sfz;
+	u8	bits;
+	u16	freq[MAX_FREQ];
+};
+
+struct usb_audio_interface
+{
+	u8	terminal;
+	u8	delay;
+	u16	num_formats;
+	u16	format_type;
+	u8	flags;
+	u8	idleconf;	/* Idle config */
+#define AU_IFACE_FOUND	1
+	struct  usb_audio_format format[MAX_FORMAT];
+};
+
+struct usb_audio_device
+{
+	struct list_head list;
+	u8	mixer;
+	u8	selector;
+	void	*irq_handle;
+	u8	num_channels;
+	u8	num_dsp_iface;
+	u8	channel_map[MAX_CHAN];
+	struct usb_audio_terminal terminal[MAX_CHAN];
+	struct usb_audio_interface interface[MAX_IFACE][MAX_ALT];
+};
+
+
+
+/* Audio Class specific Request Codes */
+
+#define SET_CUR    0x01
+#define GET_CUR    0x81
+#define SET_MIN    0x02
+#define GET_MIN    0x82
+#define SET_MAX    0x03
+#define GET_MAX    0x83
+#define SET_RES    0x04
+#define GET_RES    0x84
+#define SET_MEM    0x05
+#define GET_MEM    0x85
+#define GET_STAT   0xff
+
+/* Terminal Control Selectors */
+
+#define COPY_PROTECT_CONTROL       0x01
+
+/* Feature Unit Control Selectors */
+
+#define MUTE_CONTROL               0x01
+#define VOLUME_CONTROL             0x02
+#define BASS_CONTROL               0x03
+#define MID_CONTROL                0x04
+#define TREBLE_CONTROL             0x05
+#define GRAPHIC_EQUALIZER_CONTROL  0x06
+#define AUTOMATIC_GAIN_CONTROL     0x07
+#define DELAY_CONTROL              0x08
+#define BASS_BOOST_CONTROL         0x09
+#define LOUDNESS_CONTROL           0x0a
+
+/* Endpoint Control Selectors */
+
+#define SAMPLING_FREQ_CONTROL      0x01
+#define PITCH_CONTROL              0x02
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.19/linux/drivers/usb/cpia.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/cpia.c	Thu Oct  7 10:17:09 1999
@@ -28,452 +28,509 @@
 
 #define CPIA_DEBUG	/* Gobs of debugging info */
 
+/* Video Size 384 x 288 x 3 bytes for RGB */
 #define MAX_FRAME_SIZE (384 * 288 * 3)
 
 /*******************************/
 /* Memory management functions */
 /*******************************/
 
-/* convert virtual user memory address to physical address */
-/* (virt_to_phys only works for kmalloced kernel memory) */
+#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
 
-static inline unsigned long uvirt_to_phys(unsigned long adr)
+/* 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)
 {
-        pgd_t *pgd;
-        pmd_t *pmd;
-        pte_t *ptep, pte;
-  
-        pgd = pgd_offset(current->mm, adr);
-        if (pgd_none(*pgd))
-                return 0;
-        pmd = pmd_offset(pgd, adr);
-        if (pmd_none(*pmd))
-                return 0;
-        ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
-        pte = *ptep;
-        if(pte_present(pte))
-                return 
-                  virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
-        return 0;
+	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 = (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) 
+static inline unsigned long uvirt_to_bus(unsigned long adr)
 {
-        return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
-}
+	unsigned long kva, ret;
 
-/* convert virtual kernel memory address to physical address */
-/* (virt_to_phys only works for kmalloced kernel memory) */
+	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_phys(unsigned long adr) 
+static inline unsigned long kvirt_to_bus(unsigned long adr)
 {
-        return uvirt_to_phys(VMALLOC_VMADDR(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;
 }
 
-static inline unsigned long kvirt_to_bus(unsigned long adr) 
+/* 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)
 {
-        return uvirt_to_bus(VMALLOC_VMADDR(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)
+static void *rvmalloc(unsigned long size)
 {
-	void * mem;
+	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) 
-	{
-		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-		adr=(unsigned long) mem;
-		while (size > 0) 
-		{
-			page = kvirt_to_phys(adr);
-			mem_map_reserve(MAP_NR(phys_to_virt(page)));
-			adr+=PAGE_SIZE;
-			if (size > PAGE_SIZE)
-				size-=PAGE_SIZE;
-			else
-				size=0;
-		}
+	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)
+static void rvfree(void *mem, unsigned long size)
 {
 	unsigned long adr, page;
-        
+
+	if (!mem)
+		return;
+
 	size += (PAGE_SIZE - 1);
 	size &= ~(PAGE_SIZE - 1);
 
-	if (mem) 
-	{
-		adr=(unsigned long) mem;
-		while (size > 0) 
-		{
- 			page = kvirt_to_phys(adr);
-			mem_map_unreserve(MAP_NR(phys_to_virt(page)));
-			adr+=PAGE_SIZE;
-			if (size > PAGE_SIZE)
-				size-=PAGE_SIZE;
-			else
-				size=0;
-		}
-		vfree(mem);
+	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);
 }
 
-int usb_cpia_get_version(struct usb_device *dev, void *buf)
+static int usb_cpia_get_version(struct usb_device *dev, void *buf)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
-	dr.request = USB_REQ_CPIA_GET_VERSION;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 4;
-
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 4);
+	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);
 }
 
-int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
+#ifdef NOTUSED
+static int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
-	dr.request = USB_REQ_CPIA_GET_PNP_ID;
-	dr.value = 0;
-	dr.index = 0;
- 	dr.length = 6;
-
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 6);
+	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
 
-int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
+#ifdef NOTUSED
+static int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
-	dr.request = USB_REQ_CPIA_GET_CAMERA_STATUS;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 8;
-
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 8);
+	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
 
-int usb_cpia_goto_hi_power(struct usb_device *dev)
+static int usb_cpia_goto_hi_power(struct usb_device *dev)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_GOTO_HI_POWER;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	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);
 }
 
-int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
+static int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_GET_VP_VERSION;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 4;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, buf, 4);
+	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);
 }
 
-int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
+static int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_SET_SENSOR_FPS;
-	dr.value = (sensorclkdivisor << 8) + sensorbaserate;
-	dr.index = 0;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	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);
 }
 
-int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
+static int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_GRAB_FRAME;
-	dr.value = streamstartline << 8;
-	dr.index = 0;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	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);
 }
 
-int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
+static int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_UPLOAD_FRAME;
-	dr.value = forceupload;
-	dr.index = 0;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	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);
 }
 
-int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
+static int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_SET_GRAB_MODE;
-	dr.value = continuousgrab;
-	dr.index = 0;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	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);
 }
 
-int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
+static int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_SET_FORMAT;
-	dr.value = (subsample << 8) + size;
-	dr.index = order;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	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);
 }
 
-int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
+static int usb_cpia_set_roi(struct usb_device *dev, int colstart, int colend, int rowstart, int rowend)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_SET_COMPRESSION;
-	dr.value = (decimation << 8) + compmode;
-	dr.index = 0;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	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);
 }
 
-int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
+static int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_INIT_STREAM_CAP;
-	dr.value = (streamstartline << 8) + skipframes;
-	dr.index = 0;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	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);
 }
 
-int usb_cpia_finistreamcap(struct usb_device *dev)
+#ifdef NOTUSED
+static int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_FINI_STREAM_CAP;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	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);
 }
 
-int usb_cpia_startstreamcap(struct usb_device *dev)
+static int usb_cpia_finistreamcap(struct usb_device *dev)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_START_STREAM_CAP;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	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);
 }
 
-int usb_cpia_endstreamcap(struct usb_device *dev)
+static int usb_cpia_startstreamcap(struct usb_device *dev)
 {
-	devrequest dr;
-
-	dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
-	dr.request = USB_REQ_CPIA_END_STREAM_CAP;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 0;
+	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);
+}
 
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+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 l;
-	int done;
 
-	done = 0;
-	while (!done && scratch_left(data)) {
-		switch (cpia->state) {
+	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:
 		{
-			unsigned char *begin = data;
+			struct cpia_frame_header *header;
 
 			/* We need atleast 2 bytes for the magic value */
-			if (scratch_left(data) < 2) {
-				done = 1;
-				break;
-			}
+			if (scratch_left(data) < 2)
+				goto out;
+
+			header = (struct cpia_frame_header *)data;
 
-			/* 0x1968 is magic */
-			printk("header: %X\n", (*data << 8) + *(data + 1));
-			if ((*data == 0x19) && (*(data + 1) == 0x68)) {
-				cpia->state = STATE_HEADER;
-				printk("moving to header\n");
+			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) {
-				done = 1;
-				break;
-			}
+			if (scratch_left(data) < 4)
+				goto out;
 
-			printk("Scanning for end of frame\n");
+			/* See if we found the end of the frame */
 			while (scratch_left(data) >= 4) {
-				if ((*data == 0xFF) &&
-					(*(data + 1) == 0xFF) &&
-					(*(data + 2) == 0xFF) &&
-					(*(data + 3) == 0xFF)) {
+				if (*((__u32 *)data) == 0xFFFFFFFF) {
+printk("found end of frame\n");
 					data += 4;
-					break;
+goto error;
 				}
 				data++;
 			}
-#ifdef CPIA_DEBUG
-			printk("scan: scanned %d bytes\n", data-begin);
-#endif
 			break;
 		}
 		case STATE_HEADER:
 			/* We need atleast 64 bytes for the header */
-			if (scratch_left(data) < 64) {
-				done = 1;
-				break;
-			}
+			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;
 #ifdef CPIA_DEBUG
-			printk("header: framerate %d\n", data[41]);
+			printk("cpia: frame size %dx%d\n",
+				frame->hdrwidth, frame->hdrheight);
+			printk("cpia: frame %scompressed\n",
+				frame->header.comp_enable ? "" : "not ");
 #endif
 
-			data += 64;
+			frame->scanstate = STATE_LINES;
+			frame->curline = 0;
 
-			cpia->state = STATE_LINES;
-				
 			break;
 		case STATE_LINES:
 		{
-			unsigned char *begin = data;
-			int found = 0;
-
-			while (scratch_left(data)) {
-				if (*data == 0xFD) {
-					data++;
-					found = 1;
-					break;
-				} else if ((*data == 0xFF) &&
-						(scratch_left(data) >= 3) &&
-						(*(data + 1) == 0xFF) &&
-						(*(data + 2) == 0xFF) &&
-						(*(data + 3) == 0xFF)) {
-					data += 4;
-					cpia->curline = 144;
-					found = 1;
-					break;
-				}
-
-				data++;
+			unsigned char *f, *end;
+			unsigned int len;
+			int i;
+			int y, u, y1, v, r, g, b;
+
+			/* We want atleast 2 bytes for the length */
+			if (scratch_left(data) < 2)
+				goto out;
+
+			/* Grab the length */
+			len = data[0] + (data[1] << 8);
+
+printk("line %d, %d bytes long\n", frame->curline, len);
+			/* Check to make sure it's nothing outrageous */
+			if (len > (frame->hdrwidth * 2) + 1) {
+				printk(KERN_INFO "cpia: bad length, resynching\n");
+				goto error;
 			}
 
-			if (data-begin == 355 && cpia->frame[cpia->curframe].width != 64) {
-				int i;
-				char *f = cpia->frame[cpia->curframe].data, *b = begin;
-
-				b += 2;
-				f += (cpia->frame[cpia->curframe].width * 3) * cpia->curline;
-
-				for (i = 0; i < 176; i++)
-					f[(i * 3) + 0] =
-					f[(i * 3) + 1] =
-					f[(i * 3) + 2] =
-						b[(i * 2)];
+			/* 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) {
+				printk(KERN_INFO "cpia: lost synch\n");
+end = data + len - 1 - 4;
+printk("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+end[0], end[1],
+end[2], end[3],
+end[4], end[5],
+end[6], end[7]);
+				goto error;
 			}
 
-			if (found) {
-				cpia->curline++;
-				if (cpia->curline >= 144) {
-					wake_up(&cpia->wq);
-					cpia->state = STATE_SCANNING;
-					cpia->curline = 0;
-					cpia->curframe = -1;
-					done = 1;
+			/* 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);
+						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;
+/*
+						f[0] = f[1] = f[2] = *data;
+						f += 3;
+						data += 2;
+						fp += 3;
+*/
+					}
 				}
 			} else {
-				data = begin;
-				done = 1;
+				/* 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);
+				}
 			}
-			
+
+#ifdef CPIA_DEBUG
+			/* Make sure we found the end correctly */
+			if (*data != 0xFD)
+				printk("cpia: missed end!\n");
+#endif
+
+			/* Skip the last byte */
+			data++;
+
+			if (++frame->curline >= frame->hdrheight)
+				goto nextframe;
+
 			break;
 		}
 		}
 	}
 
+nextframe:
+	if (scratch_left(data) >= 4 && *((__u32 *)data) == 0xFFFFFFFF) {
+		data += 4;
+printk("end of frame found normally\n");
+}
+
+	frame->grabstate = FRAME_DONE;
+	cpia->curframe = -1;
+
+	/* This will cause the process to request another frame */
+	if (waitqueue_active(&frame->wq))
+		wake_up_interruptible(&frame->wq);
+
+	goto out;
+
+error:
+	frame->grabstate = FRAME_ERROR;
+	cpia->curframe = -1;
+	cpia->compress = 0;
+
+	/* This will cause the process to request another frame */
+	if (waitqueue_active(&frame->wq))
+		wake_up_interruptible(&frame->wq);
+
+out:
+printk("scanned %d bytes, %d left\n", data - cpia->scratch, scratch_left(data));
 	/* Grab the remaining */
 	l = scratch_left(data);
 	memmove(cpia->scratch, data, l);
-
 	cpia->scratchlen = l;
 }
 
 /*
- * For the moment there is no actual data compression (making blocks
- * of data contiguous).  This just checks the "frames" array for errors.
+ * Make all of the blocks of data contiguous
  */
-static int cpia_compress_isochronous(struct usb_isoc_desc *isodesc)
+static int cpia_compress_isochronous(struct usb_cpia *cpia, struct usb_isoc_desc *isodesc)
 {
-	char *data = isodesc->data;
+	unsigned char *cdata, *data;
 	int i, totlen = 0;
 
+	cdata = isodesc->data;
+	data = cpia->scratch + cpia->scratchlen;
 	for (i = 0; i < isodesc->frame_count; i++) {
-		int n = isodesc->frames [i].frame_length;
-		int st = isodesc->frames [i].frame_status;
-
+		int n = isodesc->frames[i].frame_length;
 #ifdef CPIA_DEBUG
-		/* Debugging */
+		int st = isodesc->frames[i].frame_status;
+
 		if (st)
 			printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n",
 				i, n, st);
 #endif
+		if ((cpia->scratchlen + n) > SCRATCH_BUF_SIZE) {
+			printk(KERN_ERR "cpia: scratch buf overflow!\n");
+			return 0;
+		}
+
+		if (n)
+			memmove(data, cdata, n);
 
+		data += n;
+		totlen += n;
+		cpia->scratchlen += n;
+		cdata += isodesc->frame_size;
 	}
 
 	return totlen;
@@ -481,157 +538,114 @@
 
 static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id)
 {
-	struct usb_cpia *cpia = dev_id;
-	struct usb_device *dev = cpia->dev;
+	struct usb_cpia *cpia = (struct usb_cpia *)dev_id;
 	struct cpia_sbuf *sbuf;
 	int i;
-	char *p;
 
 	if (!cpia->streaming) {
 		printk("oops, not streaming, but interrupt\n");
 		return 0;
 	}
 	
-	if (cpia->curframe < 0) {
-		if (cpia->frame[0].state == FRAME_READY) {
-			cpia->curframe = 0;
-			cpia->frame[0].state = FRAME_GRABBING;
-#ifdef CPIA_DEBUG
-			printk("capturing to frame 0\n");
-#endif
-		} else if (cpia->frame[1].state == FRAME_READY) {
-			cpia->curframe = 1;
-			cpia->frame[1].state = FRAME_GRABBING;
-#ifdef CPIA_DEBUG
-			printk("capturing to frame 1\n");
-#endif
-#ifdef CPIA_DEBUG
-		} else
-			printk("no frame available\n");
-#else
-		}
-#endif
-	}
-
-	sbuf = &cpia->sbuf[cpia->receivesbuf];
-
+	sbuf = &cpia->sbuf[cpia->cursbuf];
 	usb_kill_isoc(sbuf->isodesc);
 
-	/* Do something to it now */
-	sbuf->len = cpia_compress_isochronous(sbuf->isodesc);
+	/* Copy the data received into our scratch buffer */
+	len = cpia_compress_isochronous(cpia, sbuf->isodesc);
 
-#ifdef CPIA_DEBUG
-	if (sbuf->len)
-		printk("%d bytes received\n", sbuf->len);
-#endif
+printk("%d bytes received\n", len);
+	/* If we don't have a frame we're current working on, complain */
+	if (len) {
+		if (cpia->curframe < 0)
+			printk("cpia: received data, but no frame available\n");
+		else
+			cpia_parse_data(cpia);
+	}
 
-	if (sbuf->len && cpia->curframe >= 0) {
-		if (sbuf->len > (SCRATCH_BUF_SIZE - cpia->scratchlen)) {
-			printk("overflow!\n");
-			return 0;
-		}
-		memcpy(cpia->scratch + cpia->scratchlen, sbuf->data, sbuf->len);
-		cpia->scratchlen += sbuf->len;
+	for (i = 0; i < FRAMES_PER_DESC; i++)
+		sbuf->isodesc->frames[i].frame_length = FRAME_SIZE_PER_DESC;
 
-		cpia_parse_data(cpia);
-	}
+	/* Move to the next sbuf */
+	cpia->cursbuf = (cpia->cursbuf + 1) % CPIA_NUMSBUF;
 
 	/* Reschedule this block of Isochronous desc */
-	/*
-	usb_run_isoc(sbuf->isodesc, NULL);
-	*/
-/*
-	usb_schedule_isochronous(dev, sbuf->isodesc, cpia->sbuf[(cpia->receivesbuf + 2) % 3].isodesc);
-*/
-
-	/* Move to the next one */
-	cpia->receivesbuf = (cpia->receivesbuf + 1) % 3;
+	usb_run_isoc(sbuf->isodesc, cpia->sbuf[cpia->cursbuf].isodesc);
 
-	return 1;
+	return -1;
 }
 
-int cpia_init_isoc(struct usb_cpia *cpia)
+static int cpia_init_isoc(struct usb_cpia *cpia)
 {
 	struct usb_device *dev = cpia->dev;
 	struct usb_isoc_desc *id;
 	int fx, err;
 
-	cpia->receivesbuf = 0;
-
+	cpia->curframe = -1;
+	cpia->cursbuf = 0;
 	cpia->scratchlen = 0;
-	cpia->curline = 0;
-	cpia->state = STATE_SCANNING;
 
-	/* ALT_ISOC is only doing double-buffering, not triple. */
-	err = usb_init_isoc (dev, usb_rcvisocpipe (dev, 1), FRAMES_PER_DESC, cpia,
-		&cpia->sbuf[0].isodesc);
-	if (err)
-		printk ("cpia_init_isoc: usb_init_isoc() ret. %d\n", err);
-	err = usb_init_isoc (dev, usb_rcvisocpipe (dev, 1), FRAMES_PER_DESC, cpia,
-		&cpia->sbuf[1].isodesc);
-	if (err)
-		printk ("cpia_init_isoc: usb_init_isoc() ret. %d\n", err);
+	/* We double buffer the Iso lists */
+	err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC,
+		cpia, &cpia->sbuf[0].isodesc);
+	if (err) {
+		printk(KERN_ERR "cpia_init_isoc: usb_init_isoc() ret %d\n",
+			err);
+		return -ENOMEM;
+	}
 
-	if (!cpia->sbuf[0].isodesc || !cpia->sbuf[1].isodesc) {
-		if (cpia->sbuf[0].isodesc)
-			usb_free_isoc (cpia->sbuf[0].isodesc);
-		if (cpia->sbuf[1].isodesc)
-			usb_free_isoc (cpia->sbuf[1].isodesc);
+	err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC,
+		cpia, &cpia->sbuf[1].isodesc);
+	if (err) {
+		printk(KERN_ERR "cpia_init_isoc: usb_init_isoc() ret %d\n",
+			err);
+		usb_free_isoc (cpia->sbuf[0].isodesc);
 		return -ENOMEM;
 	}
-#if 0
-	cpia->sbuf[0].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[0].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
-	cpia->sbuf[1].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
-	cpia->sbuf[2].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
-#endif
 
 #ifdef CPIA_DEBUG
 	printk("isodesc[0] @ %p\n", cpia->sbuf[0].isodesc);
 	printk("isodesc[1] @ %p\n", cpia->sbuf[1].isodesc);
-#if 0
-	printk("isodesc[2] @ %p\n", cpia->sbuf[2].isodesc);
-#endif
 #endif
 
 	/* Set the Isoc. desc. parameters. */
 	/* First for desc. [0] */
-	id = cpia->sbuf [0].isodesc;
+	id = cpia->sbuf[0].isodesc;
 	id->start_type = START_ASAP;
 	id->callback_frames = 10;	/* on every 10th frame */
 	id->callback_fn = cpia_isoc_irq;
 	id->data = cpia->sbuf[0].data;
 	id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
 	for (fx = 0; fx < FRAMES_PER_DESC; fx++)
-		id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
+		id->frames[fx].frame_length = FRAME_SIZE_PER_DESC;
 
 	/* and the desc. [1] */
-	id = cpia->sbuf [1].isodesc;
+	id = cpia->sbuf[1].isodesc;
 	id->start_type = 0;             /* will follow the first desc. */
 	id->callback_frames = 10;	/* on every 10th frame */
 	id->callback_fn = cpia_isoc_irq;
 	id->data = cpia->sbuf[1].data;
 	id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
 	for (fx = 0; fx < FRAMES_PER_DESC; fx++)
-		id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
+		id->frames[fx].frame_length = FRAME_SIZE_PER_DESC;
 
-	usb_run_isoc (cpia->sbuf[0].isodesc, NULL);
-	usb_run_isoc (cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
-
-#if 0
-	usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL);
-	usb_schedule_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
-	usb_schedule_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc);
-#endif
+	usb_run_isoc(cpia->sbuf[0].isodesc, NULL);
+	usb_run_isoc(cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
 
 #ifdef CPIA_DEBUG
 	printk("done scheduling\n");
 #endif
-	if (usb_set_interface(cpia->dev, 1, 3)) {
-		printk("cpia_set_interface error\n");
-		return -EINVAL;
+	/* Alternate interface 3 is is the biggest frame size */
+	if (usb_set_interface(cpia->dev, 1, 3) < 0) {
+		printk("usb_set_interface error\n");
+		return -EBUSY;
 	}
 
-	usb_cpia_startstreamcap(cpia->dev);
+#if 0
+	if (usb_cpia_grab_frame(dev, 120) < 0) {
+		printk(KERN_INFO "cpia_grab_frame error\n");
+		return -EBUSY;
+	}
+#endif
 
 	cpia->streaming = 1;
 #ifdef CPIA_DEBUG
@@ -641,41 +655,102 @@
 	return 0;
 }
 
-void cpia_stop_isoc(struct usb_cpia *cpia)
+static void cpia_stop_isoc(struct usb_cpia *cpia)
 {
-	struct usb_device *dev = cpia->dev;
-
 	if (!cpia->streaming)
 		return;
 
 	cpia->streaming = 0;
 
-	/* Stop the streaming */
-	usb_cpia_endstreamcap(cpia->dev);
+	/* Turn off continuous grab */
+	if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) {
+		printk(KERN_INFO "cpia_set_grab_mode error\n");
+		return /* -EBUSY */;
+	}
+
+#if 0
+	if (usb_cpia_grab_frame(cpia->dev, 0) < 0) {
+		printk(KERN_INFO "cpia_grab_frame error\n");
+		return /* -EBUSY */;
+	}
+#endif
 
 	/* Set packet size to 0 */
-	if (usb_set_interface(cpia->dev, 1, 0)) {
-		printk("cpia_set_interface error\n");
+	if (usb_set_interface(cpia->dev, 1, 0) < 0) {
+		printk(KERN_INFO "usb_set_interface error\n");
 		return /* -EINVAL */;
 	}
 
 	/* Unschedule all of the iso td's */
-	usb_kill_isoc (cpia->sbuf[1].isodesc);
-	usb_kill_isoc (cpia->sbuf[0].isodesc);
-#if 0
-	usb_unschedule_isochronous(dev, cpia->sbuf[2].isodesc);
-	usb_unschedule_isochronous(dev, cpia->sbuf[1].isodesc);
-	usb_unschedule_isochronous(dev, cpia->sbuf[0].isodesc);
-#endif
+	usb_kill_isoc(cpia->sbuf[1].isodesc);
+	usb_kill_isoc(cpia->sbuf[0].isodesc);
 
 	/* Delete them all */
-	usb_free_isoc (cpia->sbuf[1].isodesc);
-	usb_free_isoc (cpia->sbuf[0].isodesc);
-#if 0
-	usb_delete_isochronous(dev, cpia->sbuf[2].isodesc);
-	usb_delete_isochronous(dev, cpia->sbuf[1].isodesc);
-	usb_delete_isochronous(dev, cpia->sbuf[0].isodesc);
-#endif
+	usb_free_isoc(cpia->sbuf[1].isodesc);
+	usb_free_isoc(cpia->sbuf[0].isodesc);
+}
+
+static int cpia_new_frame(struct usb_cpia *cpia, int framenum)
+{
+	struct cpia_frame *frame;
+	int width, height;
+
+printk("new frame %d\n", framenum);
+	if (framenum == -1) {
+		int i;
+		for (i = 0; i < CPIA_NUMFRAMES; i++)
+			if (cpia->frame[i].grabstate == FRAME_READY)
+				break;
+
+		if (i >= CPIA_NUMFRAMES) {
+			printk("no frame ready\n");
+			return 0;
+		}
+
+		framenum = i;
+printk("using frame %d\n", framenum);
+	}
+
+	if (cpia->curframe != -1 && cpia->curframe != framenum)
+		return 0;
+
+	frame = &cpia->frame[framenum];
+	width = frame->width;
+	height = frame->height;
+
+	/* 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 ? 1 : 0, 0) < 0) {
+		printk(KERN_INFO "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, 1) < 0) {
+		printk(KERN_INFO "cpia_upload_frame error\n");
+		return -EBUSY;
+	}
+
+	frame->grabstate = FRAME_GRABBING;
+	frame->scanstate = STATE_SCANNING;
+
+	cpia->curframe = framenum;
+
+	return 0;
 }
 
 /* Video 4 Linux API */
@@ -688,13 +763,14 @@
 	printk("cpia_open\n");
 #endif
 
+	cpia->frame[0].grabstate = FRAME_UNUSED;
+	cpia->frame[1].grabstate = FRAME_UNUSED;
+
+	/* Allocate memory for the frame buffers */
 	cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
 	if (!cpia->fbuf)
 		goto open_err_ret;
 
-	cpia->frame[0].state = FRAME_DONE;
-	cpia->frame[1].state = FRAME_DONE;
-
 	cpia->frame[0].data = cpia->fbuf;
 	cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE;
 #ifdef CPIA_DEBUG
@@ -710,37 +786,17 @@
 	if (!cpia->sbuf[1].data)
 		goto open_err_on1;
 
-#if 0
-	cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
-	if (!cpia->sbuf[0].data)
-		goto open_err_on0;
-
-	cpia->sbuf[1].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
-	if (!cpia->sbuf[1].data)
-		goto open_err_on1;
-
-	cpia->sbuf[2].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
-	if (!cpia->sbuf[2].data)
-		goto open_err_on2;
-#endif
-
 #ifdef CPIA_DEBUG
 	printk("sbuf[0] @ %p\n", cpia->sbuf[0].data);
 	printk("sbuf[1] @ %p\n", cpia->sbuf[1].data);
-#if 0
-	printk("sbuf[2] @ %p\n", cpia->sbuf[2].data);
-#endif
 #endif
 
-	cpia->curframe = -1;
-	cpia->receivesbuf = 0;
-
-	usb_cpia_initstreamcap(cpia->dev, 0, 60);
-
 	err = cpia_init_isoc(cpia);
 	if (err)
 		goto open_err_on2;
 
+	MOD_INC_USE_COUNT;
+
 	return 0;
 
 open_err_on2:
@@ -761,13 +817,12 @@
 	printk("cpia_close\n");
 #endif
 
-	cpia_stop_isoc(cpia);
+	MOD_DEC_USE_COUNT;
 
-	usb_cpia_finistreamcap(cpia->dev);
+	cpia_stop_isoc(cpia);
 
 	rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
 
-	kfree(cpia->sbuf[2].data);
 	kfree(cpia->sbuf[1].data);
 	kfree(cpia->sbuf[0].data);
 }
@@ -791,23 +846,32 @@
 		{
 			struct video_capability b;
 
+#ifdef CPIA_DEBUG
+			printk("GCAP\n");
+#endif
+
 			strcpy(b.name, "CPiA USB Camera");
-			b.type = VID_TYPE_CAPTURE /* | VID_TYPE_SUBCAPTURE */;
+			b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
 			b.channels = 1;
 			b.audios = 0;
-			b.maxwidth = 176	/* 352 */;
-			b.maxheight = 144	/* 240 */;
-			b.minwidth = 176	/* (Something small?) */;
-			b.minheight = 144	/* "         " */;
+			b.maxwidth = 352;	/* CIF */
+			b.maxheight = 288;	/*  "  */
+			b.minwidth = 176;	/* QCIF */
+			b.minheight = 144;	/*  "   */
 
 			if (copy_to_user(arg, &b, sizeof(b)))
 				return -EFAULT;
+
 			return 0;
 		}
 		case VIDIOCGCHAN:
 		{
 			struct video_channel v;
 
+#ifdef CPIA_DEBUG
+			printk("GCHAN\n");
+#endif
+
 			if (copy_from_user(&v, arg, sizeof(v)))
 				return -EFAULT;
 			if (v.channel != 0)
@@ -826,47 +890,14 @@
 		{
 			int v;
 
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-
-			if (v != 0)
-				return -EINVAL;
-
-			return 0;
-		}
-		case VIDIOCGTUNER:
-		{
-			struct video_tuner v;
-
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-
-			if (v.tuner)
-				return -EINVAL;
-
-			strcpy(v.name, "Format");
-
-			v.rangelow = 0;
-			v.rangehigh = 0;
-			v.flags = 0;
-			v.mode = VIDEO_MODE_AUTO;
-
-			if (copy_to_user(arg, &v, sizeof(v)))
-				return -EFAULT;
-
-			return 0;
-		}
-		case VIDIOCSTUNER:
-		{
-			struct video_tuner v;
+#ifdef CPIA_DEBUG
+			printk("SCHAN\n");
+#endif
 
 			if (copy_from_user(&v, arg, sizeof(v)))
 				return -EFAULT;
 
-			if (v.tuner)
-				return -EINVAL;
-
-			if (v.mode != VIDEO_MODE_AUTO)
+			if (v != 0)
 				return -EINVAL;
 
 			return 0;
@@ -875,6 +906,10 @@
 		{
 			struct video_picture p;
 
+#ifdef CPIA_DEBUG
+			printk("GPICT\n");
+#endif
+
 			p.colour = 0x8000;	/* Damn British people :) */
 			p.hue = 0x8000;
 			p.brightness = 180 << 8;	/* XXX */
@@ -895,6 +930,10 @@
 		{
 			struct video_picture p;
 
+#ifdef CPIA_DEBUG
+			printk("SPICT\n");
+#endif
+
 			if (copy_from_user(&p, arg, sizeof(p)))
 				return -EFAULT;
 
@@ -910,7 +949,7 @@
 			struct video_window vw;
 
 #ifdef CPIA_DEBUG
-			printk("VIDIOCSWIN\n");
+			printk("SWIN\n");
 #endif
 
 			if (copy_from_user(&vw, arg, sizeof(vw)))
@@ -924,6 +963,8 @@
 			if (vw.width != 144)
 				return -EINVAL;
 
+			cpia->compress = 0;
+
 			return 0;
 		}
 		case VIDIOCGWIN:
@@ -931,7 +972,7 @@
 			struct video_window vw;
 
 #ifdef CPIA_DEBUG
-			printk("VIDIOCGWIN\n");
+			printk("GWIN\n");
 #endif
 
 			vw.x = 0;
@@ -949,6 +990,9 @@
 		case VIDIOCGMBUF:
 		{
 			struct video_mbuf vm;
+#ifdef CPIA_DEBUG
+			printk("MBUF\n");
+#endif
 
 			memset(&vm, 0, sizeof(vm));
 			vm.size = MAX_FRAME_SIZE * 2;
@@ -965,6 +1009,7 @@
 		{
 			struct video_mmap vm;
 
+
 			if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
 				return -EFAULT;
 
@@ -980,53 +1025,85 @@
 			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 free */
-			cpia->frame[vm.frame].state = FRAME_READY;
+			/* Mark it as ready */
+			cpia->frame[vm.frame].grabstate = FRAME_READY;
 
-			return 0;
+			return cpia_new_frame(cpia, vm.frame);
 		}
 		case VIDIOCSYNC:
 		{
 			int frame;
 
+#ifdef CPIA_DEBUG
+			printk("SYNC\n");
+#endif
+
 			if (copy_from_user((void *)&frame, arg, sizeof(int)))
 				return -EFAULT;
 
 #ifdef CPIA_DEBUG
-			printk("syncing to frame %d\n", frame);
+			printk("cpia: syncing to frame %d\n", frame);
 #endif
-			switch (cpia->frame[frame].state) {
-				case FRAME_UNUSED:
-					return -EINVAL;
-				case FRAME_READY:
-				case FRAME_GRABBING:
-					interruptible_sleep_on(&cpia->wq);
-				case FRAME_DONE:
-					cpia->frame[frame].state = FRAME_UNUSED;
-					break;
+
+			switch (cpia->frame[frame].grabstate) {
+			case FRAME_UNUSED:
+				return -EINVAL;
+			case FRAME_READY:
+			case FRAME_GRABBING:
+redo:
+				do {
+printk("enter sleeping\n");
+					interruptible_sleep_on(&cpia->frame[frame].wq);
+printk("back from sleeping\n");
+					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;
 			}
+
 #ifdef CPIA_DEBUG
-			printk("synced to frame %d\n", frame);
+			printk("cpia: finished, synced to frame %d\n", frame);
 #endif
-			return 0;
+
+			return cpia_new_frame(cpia, -1);
 		}
+		case VIDIOCKEY:
+			return 0;
 		case VIDIOCCAPTURE:
 			return -EINVAL;
 		case VIDIOCGFBUF:
-			return -EINVAL;
 		case VIDIOCSFBUF:
 			return -EINVAL;
-		case VIDIOCKEY:
-			return 0;
-		case VIDIOCGFREQ:
+		case VIDIOCGTUNER:
+		case VIDIOCSTUNER:
 			return -EINVAL;
+		case VIDIOCGFREQ:
 		case VIDIOCSFREQ:
 			return -EINVAL;
 		case VIDIOCGAUDIO:
-			return -EINVAL;
 		case VIDIOCSAUDIO:
 			return -EINVAL;
 		default:
@@ -1037,17 +1114,14 @@
 
 static long cpia_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
 {
+#if 0
 	struct usb_cpia *cpia = (struct usb_cpia *)dev;
 	int len;
+#endif
 
 #ifdef CPIA_DEBUG
 	printk("cpia_read: %ld bytes\n", count);
 #endif
-#if 0
-	len = cpia_capture(cpia, buf, count);
-
-	return len;
-#endif
 	return 0;
 }
 
@@ -1064,17 +1138,17 @@
 		return -EINVAL;
 
 	pos = (unsigned long)cpia->fbuf;
-	while (size > 0)
-	{
-		page = kvirt_to_phys(pos);
+	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;
+
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
 		if (size > PAGE_SIZE)
-			size-=PAGE_SIZE;
+			size -= PAGE_SIZE;
 		else
-			size=0;
+			size = 0;
 	}
 
 	return 0;
@@ -1097,87 +1171,92 @@
 	0
 };
 
-static void usb_cpia_configure(struct usb_cpia *cpia)
+static int usb_cpia_configure(struct usb_cpia *cpia)
 {
 	struct usb_device *dev = cpia->dev;
 	unsigned char version[4];
-	unsigned char pnpid[6];
-	unsigned char camerastat[8];
-	unsigned char *buf;
 
-	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
-		printk (KERN_INFO " Failed usb_set_configuration: CPIA\n");
-		return;
+	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) < 0) {
+		printk(KERN_INFO "cpia: usb_set_configuration failed\n");
+		return -EBUSY;
 	}
 
-	if (usb_cpia_get_version(dev, version)) {
-		printk("cpia_get_version error\n");
-		return;
+	/* Set packet size to 0 */
+	if (usb_set_interface(dev, 1, 0) < 0) {
+		printk(KERN_INFO "usb_set_interface error\n");
+		return -EBUSY;
 	}
 
-	printk("cpia: Firmware v%d.%d, VC Hardware v%d.%d\n",
-		version[0], version[1], version[2], version[3]);
-
-	if (usb_cpia_get_pnp_id(dev, pnpid)) {
-		printk("cpia_get_pnp_id error\n");
-		return;
+	if (usb_cpia_get_version(dev, version) < 0) {
+		printk(KERN_INFO "cpia_get_version error\n");
+		return -EBUSY;
 	}
 
-	printk("cpia: PnP Id: Vendor: %X, Product: %X, Revision: %X\n",
-		(pnpid[1] << 8) + pnpid[0], (pnpid[3] << 8) + pnpid[2],
-		(pnpid[5] << 8) + pnpid[4]);
+	printk("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->wq);
+	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("video_register_device failed\n");
-		return;
+		printk(KERN_INFO "video_register_device failed\n");
+		return -EBUSY;
 	}
 
-	if (usb_cpia_goto_hi_power(dev)) {
-		printk("cpia_goto_hi_power error\n");
-		return;
+	if (usb_cpia_goto_hi_power(dev) < 0) {
+		printk(KERN_INFO "cpia_goto_hi_power error\n");
+		goto error;
 	}
 
-	if (usb_cpia_get_vp_version(dev, version)) {
-		printk("cpia_get_vp_version error\n");
-		return;
+	if (usb_cpia_get_vp_version(dev, version) < 0) {
+		printk(KERN_INFO "cpia_get_vp_version error\n");
+		goto error;
 	}
 
 	printk("cpia: VP v%d rev %d\n", version[0], version[1]);
 	printk("cpia: Camera Head ID %04X\n", (version[3] << 8) + version[2]);
 
-	/* Turn off continuous grab */
-	if (usb_cpia_set_grab_mode(dev, 1)) {
-		printk("cpia_set_grab_mode error\n");
-		return;
+	/* Turn on continuous grab */
+	if (usb_cpia_set_grab_mode(dev, 1) < 0) {
+		printk(KERN_INFO "cpia_set_grab_mode error\n");
+		goto error;
 	}
 
 	/* Set up the sensor to be 30fps */
-	if (usb_cpia_set_sensor_fps(dev, 1, 0)) {
-		printk("cpia_set_sensor_fps error\n");
-		return;
+	if (usb_cpia_set_sensor_fps(dev, 1, 0) < 0) {
+		printk(KERN_INFO "cpia_set_sensor_fps error\n");
+		goto error;
 	}
 
-	/* Set video into QCIF mode, and order into YUYV mode */
-	if (usb_cpia_set_format(dev, CPIA_QCIF, 1, CPIA_YUYV)) {
-		printk("cpia_set_format error\n");
-		return;
+	/* Set video into CIF mode, and order into YUYV mode */
+	if (usb_cpia_set_format(dev, CPIA_CIF, 1, CPIA_YUYV) < 0) {
+		printk(KERN_INFO "cpia_set_format error\n");
+		goto error;
 	}
 
 	/* Turn off compression */
-	if (usb_cpia_set_compression(dev, 0, 0)) {
-		printk("cpia_set_compression error\n");
-		return;
+	if (usb_cpia_set_compression(dev, 0, 0) < 0) {
+		printk(KERN_INFO "cpia_set_compression error\n");
+		goto error;
 	}
+
+	cpia->compress = 0;
+
+	return 0;
+
+error:
+	video_unregister_device(&cpia->vdev);
+
+	kfree(cpia);
+
+	return -EBUSY;
 }
 
 static int cpia_probe(struct usb_device *dev)
 {
 	struct usb_interface_descriptor *interface;
-	struct usb_endpoint_descriptor *endpoint;
 	struct usb_cpia *cpia;
 
 	/* We don't handle multi-config cameras */
@@ -1191,6 +1270,8 @@
 		return -1;
 	if (dev->descriptor.idProduct != 0x0002)
 		return -1;
+
+	/* Checking vendor/product should be enough, but what the hell */
 	if (interface->bInterfaceClass != 0xFF)
 		return -1;
 	if (interface->bInterfaceSubClass != 0x00)
@@ -1209,9 +1290,7 @@
 	dev->private = cpia;
 	cpia->dev = dev;
 
-	usb_cpia_configure(cpia);
-
-	return 0;
+	return usb_cpia_configure(cpia);
 }
 
 static void cpia_disconnect(struct usb_device *dev)
@@ -1231,9 +1310,6 @@
 	{ NULL, NULL }
 };
 
-/*
- * This should be a separate module.
- */
 int usb_cpia_init(void)
 {
 	usb_register(&cpia_driver);
@@ -1241,6 +1317,11 @@
 	return 0;
 }
 
+void usb_cpia_cleanup(void)
+{
+	usb_deregister(&cpia_driver);
+}
+
 #ifdef MODULE
 int init_module(void)
 {
@@ -1249,6 +1330,7 @@
 
 void cleanup_module(void)
 {
+	usb_cpia_cleanup();
 }
 #endif
 
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/cpia.h linux/drivers/usb/cpia.h
--- v2.3.19/linux/drivers/usb/cpia.h	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/cpia.h	Thu Oct  7 10:17:09 1999
@@ -78,9 +78,10 @@
 #define CPIA_YUYV	0
 #define CPIA_UYVY	1
 
-#define STREAM_BUF_SIZE	(PAGE_SIZE * 4)
+#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 SCRATCH_BUF_SIZE	(STREAM_BUF_SIZE * 2)
 
 #define FRAMES_PER_DESC		10
 #define FRAME_SIZE_PER_DESC	960	/* Shouldn't be hardcoded */
@@ -91,54 +92,97 @@
 	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;
-	int len;
 	struct usb_isoc_desc *isodesc;
-#if 0
-	void *isodesc;
-#endif
 };
 
 enum {
-	FRAME_READY,		/* Ready to grab into */
+	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_UNUSED,		/* Unused (no MCAPTURE) */
+	FRAME_ERROR,		/* Something bad happened while processing */
 };
 
 struct cpia_frame {
-	char *data;
-	int width;
-	int height;
-	int state;
+	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 */
+
+	int grabstate;		/* State of grabbing */
+	int scanstate;		/* State of scanning */
+
+	int curline;		/* Line of frame we're working on */
+
+	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;
 
-	int streaming;
+	int streaming;		/* Are we streaming Isochronous? */
+	int grabbing;		/* Are we grabbing? */
 
-	char *fbuf;			/* Videodev buffer area */
+	int compress;		/* Should the next frame be compressed? */
 
-	int curframe;
-	struct cpia_frame frame[2];	/* Double buffering */
+	char *fbuf;		/* Videodev buffer area */
 
-	int receivesbuf;		/* Current receiving sbuf */
-	struct cpia_sbuf sbuf[3];	/* Triple buffering */
+	int curframe;
+	struct cpia_frame frame[CPIA_NUMFRAMES];	/* Double buffering */
 
-	int state;			/* Current scanning state */
-	int curline;
+	int cursbuf;		/* Current receiving sbuf */
+	struct cpia_sbuf sbuf[CPIA_NUMSBUF];		/* Double buffering */
 
-	char scratch[SCRATCH_BUF_SIZE];
+	/* Scratch space from the Isochronous pipe */
+	unsigned char scratch[SCRATCH_BUF_SIZE];
 	int scratchlen;
-
-	wait_queue_head_t wq;
 };
 
 #endif
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/ezusb.c linux/drivers/usb/ezusb.c
--- v2.3.19/linux/drivers/usb/ezusb.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/ezusb.c	Thu Oct  7 10:17:09 1999
@@ -27,7 +27,8 @@
  *                  Implemented EZUSB_SETINTERFACE, more sanity checks for EZUSB_BULK.
  *                  Preliminary ISO support
  *   0.3  01.09.99  Async Bulk and ISO support
- *   0.4  01.09.99
+ *   0.4  01.09.99  Set callback_frames to the total number of frames to make
+ *                  it work with OHCI-HCD
  *
  */
 
@@ -40,9 +41,10 @@
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
-#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
+#include <linux/spinlock.h>
+
 #include "usb.h"
 #include "ezusb.h"
 
@@ -76,9 +78,9 @@
 
 /* --------------------------------------------------------------------- */
 
-extern inline unsigned ld2(unsigned int x)
+extern inline unsigned int ld2(unsigned int x)
 {
-        unsigned r = 0;
+        unsigned int r = 0;
         
         if (x >= 0x10000) {
                 x >>= 16;
@@ -101,6 +103,17 @@
         return r;
 }
 
+#if 0
+/* why doesn't this work properly on i386? */
+extern inline unsigned int ld2(unsigned int x)
+{
+        unsigned int r;
+
+	__asm__("bsrl %1,%0" : "=r" (r) : "g" (x));
+	return r;
+}
+#endif
+
 /* --------------------------------------------------------------------- */
 
 extern __inline__ void async_removelist(struct async *as)
@@ -173,22 +186,41 @@
 
 /* --------------------------------------------------------------------- */
 
-static int async_completed(int status, void *__buffer, int rval, void *dev_id)
+static int bulk_completed(int status, void *__buffer, int rval, void *dev_id)
 {
 	struct async *as = (struct async *)dev_id;
 	struct ezusb *ez = as->ez;
 	unsigned cnt;
 
-printk(KERN_DEBUG "ezusb: async_completed: status %d rval %d\n", status, rval);
+printk(KERN_DEBUG "ezusb: bulk_completed: status %d rval %d\n", status, rval);
 	as->completed.length = rval;
-	if (as->numframes > 0) {
-		as->completed.status = USB_ST_NOERROR;
-		for (cnt = 0; cnt < as->numframes; cnt++) {
-			as->completed.isostat[cnt].status = as->desc.iso->frames[cnt].frame_status;
-			as->completed.isostat[cnt].length = as->desc.iso->frames[cnt].frame_length;
-		}
-	} else
-		as->completed.status = status;
+	as->completed.status = status;
+	spin_lock(&ez->lock);
+	list_del(&as->asynclist);
+	list_add_tail(&as->asynclist, &ez->async_completed);
+	spin_unlock(&ez->lock);
+	wake_up(&ez->wait);
+	return 0;
+}
+
+static int iso_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 1
+	struct async *as = (struct async *)dev_id;
+#else
+	struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+	struct async *as = (struct async *)id->context;
+#endif
+	struct ezusb *ez = as->ez;
+	unsigned cnt;
+
+printk(KERN_DEBUG "ezusb: iso_completed: status %d rval %d\n", status, rval);
+	as->completed.length = rval;
+	as->completed.status = USB_ST_NOERROR;
+	for (cnt = 0; cnt < as->numframes; cnt++) {
+		as->completed.isostat[cnt].status = as->desc.iso->frames[cnt].frame_status;
+		as->completed.isostat[cnt].length = as->desc.iso->frames[cnt].frame_length;
+	}
 	spin_lock(&ez->lock);
 	list_del(&as->asynclist);
 	list_add_tail(&as->asynclist, &ez->async_completed);
@@ -264,7 +296,6 @@
 	unsigned ret = 0;
 	unsigned len;
 	unsigned char b[64];
-        devrequest dr;
 	int i;
 
 	if (*ppos < 0 || *ppos >= 0x10000)
@@ -280,15 +311,10 @@
 			len = sizeof(b);
 		if (pos + len > 0x10000)
 			len = 0x10000 - pos;
-		dr.requesttype = 0xc0;
-		dr.request = 0xa0;
-		dr.value = pos;
-		dr.index = 0;
-		dr.length = len;
-		i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), &dr, b, len);
+		i = usb_control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), 0xa0, 0xc0, pos, 0, b, len, HZ);
 		if (i) {
 			up(&ez->mutex);
-			printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", dr.value, dr.length, i);
+			printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", pos, len, i);
 			*ppos = pos;
 			if (ret)
 				return ret;
@@ -318,7 +344,6 @@
 	unsigned ret = 0;
 	unsigned len;
 	unsigned char b[64];
-        devrequest dr;
 	int i;
 
 	if (*ppos < 0 || *ppos >= 0x10000)
@@ -341,15 +366,10 @@
 				return ret;
 			return -EFAULT;
 		}
-		dr.requesttype = 0x40;
-		dr.request = 0xa0;
-		dr.value = pos;
-		dr.index = 0;
-		dr.length = len;
-		i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), &dr, b, len);
+		i = usb_control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), 0xa0, 0x40, pos, 0, b, len, HZ);
 		if (i) {
 			up(&ez->mutex);
-			printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", dr.value, dr.length, i);
+			printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", pos, len, i);
 			*ppos = pos;
 			if (ret)
 				return ret;
@@ -401,7 +421,7 @@
 static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
 			 unsigned char request, unsigned short value, 
 			 unsigned short index, unsigned short length,
-			 void *data)
+			 unsigned int timeout, void *data)
 {
 	unsigned char *tbuf = NULL;
 	unsigned int pipe;
@@ -429,7 +449,7 @@
 			}
 		}
 	}
-	i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length);
+	i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length, timeout);
 	if (i < 0) {
 		if (length > 0)
 			free_page((unsigned long)tbuf);
@@ -444,7 +464,7 @@
 	return i;
 }
 
-static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, void *data)
+static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, unsigned int timeout, void *data)
 {
 	unsigned char *tbuf = NULL;
 	unsigned int pipe;
@@ -473,7 +493,7 @@
 			}
 		}
 	}
-	ret = usbdev->bus->op->bulk_msg(usbdev, pipe, tbuf, length, &len2);
+	ret = usbdev->bus->op->bulk_msg(usbdev, pipe, tbuf, length, &len2, timeout);
 	if (ret < 0) {
 		if (length > 0)
 			free_page((unsigned long)tbuf);
@@ -553,7 +573,7 @@
 		}
 	}
 	async_newpending(as);
-	if (!(as->desc.bulk = usb_request_bulk(ez->usbdev, pipe, async_completed, as->data, ab->len, as))) {
+	if (!(as->desc.bulk = usb_request_bulk(ez->usbdev, pipe, bulk_completed, as->data, ab->len, as))) {
 		async_removelist(as);
 		goto err_inval;
 	}
@@ -592,6 +612,7 @@
 	if (!(maxpkt = usb_maxpacket(ez->usbdev, pipe, !(ai->ep & 0x80))))
 		return -EINVAL;
 	dsize = maxpkt * ai->framecnt;
+printk(KERN_DEBUG "ezusb: iso: dsize %d\n", dsize);
 	if (dsize > 65536) 
 		return -EINVAL;
 	order = ld2(dsize >> PAGE_SHIFT);
@@ -603,6 +624,7 @@
 	assize = sizeof(struct async) + ai->framecnt * sizeof(struct ezusb_isoframestat);
 	if (!(as = kmalloc(assize, GFP_KERNEL)))
 		return -ENOMEM;
+printk(KERN_DEBUG "ezusb: iso: assize %d\n", assize);
 	memset(as, 0, assize);
 	INIT_LIST_HEAD(&as->asynclist);
 	as->ez = ez;
@@ -630,8 +652,8 @@
 	}
 	as->desc.iso->start_type = START_ABSOLUTE;
 	as->desc.iso->start_frame = ai->startframe;
-	as->desc.iso->callback_frames = 0;
-	as->desc.iso->callback_fn = async_completed;
+	as->desc.iso->callback_frames = /*0*/ai->framecnt;
+	as->desc.iso->callback_fn = iso_completed;
 	as->desc.iso->data = as->data;
 	as->desc.iso->buf_size = dsize;
 	for (j = 0; j < ai->framecnt; j++) {
@@ -709,9 +731,13 @@
         DECLARE_WAITQUEUE(wait, current);
 	struct usb_proc_ctrltransfer pctrl;
 	struct usb_proc_bulktransfer pbulk;
+	struct usb_proc_old_ctrltransfer opctrl;
+	struct usb_proc_old_bulktransfer opbulk;
 	struct usb_proc_setinterface psetintf;
 	struct ezusb_ctrltransfer ctrl;
 	struct ezusb_bulktransfer bulk;
+	struct ezusb_old_ctrltransfer octrl;
+	struct ezusb_old_bulktransfer obulk;
 	struct ezusb_setinterface setintf;
 	struct ezusb_asyncbulk abulk;
 	struct ezusb_asynciso aiso;
@@ -732,7 +758,8 @@
 			break;
 		}
 		ret = ezusb_control(ez->usbdev, pctrl.requesttype, pctrl.request, 
-				    pctrl.value, pctrl.index, pctrl.length, pctrl.data);
+				    pctrl.value, pctrl.index, pctrl.length, 
+				    (pctrl.timeout * HZ + 500) / 1000, pctrl.data);
 		break;
 
 	case USB_PROC_BULK:
@@ -740,7 +767,25 @@
 			ret = -EFAULT;
 			break;
 		}
-		ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len, pbulk.data);
+		ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len, 
+				 (pbulk.timeout * HZ + 500) / 1000, pbulk.data);
+		break;
+
+	case USB_PROC_OLD_CONTROL:
+		if (copy_from_user(&opctrl, (void *)arg, sizeof(opctrl))) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = ezusb_control(ez->usbdev, opctrl.requesttype, opctrl.request, 
+				    opctrl.value, opctrl.index, opctrl.length, HZ, opctrl.data);
+		break;
+
+	case USB_PROC_OLD_BULK:
+		if (copy_from_user(&opbulk, (void *)arg, sizeof(opbulk))) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = ezusb_bulk(ez->usbdev, opbulk.ep, opbulk.len, 5*HZ, opbulk.data);
 		break;
 
 	case USB_PROC_RESETEP:
@@ -772,12 +817,9 @@
 			ret = -EFAULT;
 			break;
 		}
-		if (ctrl.dlen != ctrl.length) {
-			ret = -EINVAL;
-			break;
-		}
 		ret = ezusb_control(ez->usbdev, ctrl.requesttype, ctrl.request, 
-				    ctrl.value, ctrl.index, ctrl.length, ctrl.data);
+				    ctrl.value, ctrl.index, ctrl.length, 
+				    (ctrl.timeout * HZ + 500) / 1000, ctrl.data);
 		break;
 
 	case EZUSB_BULK:
@@ -785,7 +827,29 @@
 			ret = -EFAULT;
 			break;
 		}
-		ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len, bulk.data);
+		ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len, 
+				 (bulk.timeout * HZ + 500) / 1000, bulk.data);
+		break;
+
+	case EZUSB_OLD_CONTROL:
+		if (copy_from_user(&octrl, (void *)arg, sizeof(octrl))) {
+			ret = -EFAULT;
+			break;
+		}
+		if (octrl.dlen != octrl.length) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = ezusb_control(ez->usbdev, octrl.requesttype, octrl.request, 
+				    octrl.value, octrl.index, octrl.length, HZ, octrl.data);
+		break;
+
+	case EZUSB_OLD_BULK:
+		if (copy_from_user(&obulk, (void *)arg, sizeof(obulk))) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = ezusb_bulk(ez->usbdev, obulk.ep, obulk.len, 5*HZ, obulk.data);
 		break;
 
 	case EZUSB_RESETEP:
@@ -813,6 +877,7 @@
 		break;
 
 	case EZUSB_ASYNCCOMPLETED:
+		as = NULL;
 		current->state = TASK_INTERRUPTIBLE;
 		add_wait_queue(&ez->wait, &wait);
 		for (;;) {
@@ -928,9 +993,11 @@
         if (usbdev->descriptor.bNumConfigurations != 1)
                 return -1;
 
+#if 0
         /* We don't handle multiple interfaces */
         if (usbdev->config[0].bNumInterfaces != 1)
                 return -1;
+#endif
 
 	down(&ez->mutex);
 	if (ez->usbdev) {
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/ezusb.h linux/drivers/usb/ezusb.h
--- v2.3.19/linux/drivers/usb/ezusb.h	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/ezusb.h	Thu Oct  7 10:17:09 1999
@@ -31,6 +31,23 @@
 
 /* --------------------------------------------------------------------- */
 
+struct ezusb_old_ctrltransfer {
+	/* keep in sync with usb.h:devrequest */
+	unsigned char requesttype;
+	unsigned char request;
+	unsigned short value;
+	unsigned short index;
+	unsigned short length;
+	unsigned int dlen;
+	void *data;
+};
+
+struct ezusb_old_bulktransfer {
+	unsigned int ep;
+	unsigned int len;
+	void *data;
+};
+
 struct ezusb_ctrltransfer {
 	/* keep in sync with usb.h:devrequest */
 	unsigned char requesttype;
@@ -38,14 +55,14 @@
 	unsigned short value;
 	unsigned short index;
 	unsigned short length;
-	/* pointer to data */
-	unsigned dlen;
+	unsigned int timeout;  /* in milliseconds */
 	void *data;
 };
 
 struct ezusb_bulktransfer {
 	unsigned int ep;
 	unsigned int len;
+	unsigned int timeout;  /* in milliseconds */
 	void *data;
 };
 
@@ -84,8 +101,10 @@
 	struct ezusb_isoframestat isostat[0];
 };
 
-#define EZUSB_CONTROL           _IOWR('E', 0, struct ezusb_ctrltransfer)
+#define EZUSB_CONTROL           _IOWR('E', 1, struct ezusb_ctrltransfer)
 #define EZUSB_BULK              _IOWR('E', 2, struct ezusb_bulktransfer)
+#define EZUSB_OLD_CONTROL       _IOWR('E', 0, struct ezusb_old_ctrltransfer)
+#define EZUSB_OLD_BULK          _IOWR('E', 2, struct ezusb_old_bulktransfer)
 #define EZUSB_RESETEP           _IOR('E', 3, unsigned int)
 #define EZUSB_SETINTERFACE      _IOR('E', 4, struct ezusb_setinterface)
 #define EZUSB_SETCONFIGURATION  _IOR('E', 5, unsigned int)
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/hp_scanner.c linux/drivers/usb/hp_scanner.c
--- v2.3.19/linux/drivers/usb/hp_scanner.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/hp_scanner.c	Thu Oct  7 10:17:09 1999
@@ -130,7 +130,7 @@
 				return bytes_written ? bytes_written : -EINTR;
 			}
 
-			result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, 2), obuf, thistime, &partial);
+			result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, 2), obuf, thistime, &partial, HZ*10);
 			
 			//printk(KERN_DEBUG "write stats: result:%d thistime:%lu partial:%lu\n", result, thistime, partial);
 
@@ -188,7 +188,7 @@
 			return -ENODEV;
 		this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count;
 		
-		result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, 1), ibuf, this_read, &partial);
+		result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, 1), ibuf, this_read, &partial, HZ*10);
 
 		printk(KERN_DEBUG "read stats: result:%d this_read:%u partial:%lu\n", result, this_read, partial);
 		
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.3.19/linux/drivers/usb/hub.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/hub.c	Thu Oct  7 10:17:09 1999
@@ -34,33 +34,33 @@
 {
 	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 		USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
-		USB_DT_HUB << 8, 0, data, size);
+		USB_DT_HUB << 8, 0, data, size, HZ);
 }
 
 static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
 {
 	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0);
+		USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
 }
 
 static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
 {
 	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0);
+		USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
 }
 
 static int usb_get_hub_status(struct usb_device *dev, void *data)
 {
 	/* FIXME: Don't hardcode 4 */
 	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, data, 4);
+		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, data, 4, HZ);
 }
 
 static int usb_get_port_status(struct usb_device *dev, int port, void *data)
 {
 	/* FIXME: Don't hardcode 4 */
 	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, data, 4);
+		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, data, 4, HZ);
 }
 
 /*
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/inits.h linux/drivers/usb/inits.h
--- v2.3.19/linux/drivers/usb/inits.h	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/inits.h	Fri Oct  8 15:47:08 1999
@@ -6,5 +6,8 @@
 void usb_hub_cleanup(void);
 void usb_mouse_cleanup(void);
 int usb_scsi_init(void);
+int usb_hp_scanner_init(void);
+void usb_hp_scanner_cleanup(void);
 int proc_usb_init (void);
 void proc_usb_cleanup (void);
+int usb_serial_init (void);
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/keyboard.c linux/drivers/usb/keyboard.c
--- v2.3.19/linux/drivers/usb/keyboard.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/keyboard.c	Thu Oct  7 10:17:09 1999
@@ -21,7 +21,7 @@
 #define PCKBD_RELEASED 0x80
 #define PCKBD_NEEDS_E0 0x80
 
-#define USBKBD_MODIFIER_BASE  120
+#define USBKBD_MODIFIER_BASE  224
 #define USBKBD_KEYCODE_OFFSET 2
 #define USBKBD_KEYCODE_COUNT  6
 
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/keymap.c linux/drivers/usb/keymap.c
--- v2.3.19/linux/drivers/usb/keymap.c	Mon May 24 09:31:36 1999
+++ linux/drivers/usb/keymap.c	Thu Oct  7 10:17:09 1999
@@ -22,7 +22,7 @@
     0xbd,  0xbe,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
 
     0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-    0x1d,  0x2a,  0x38,  0xdb,  0x9d,  0x36,  0xb8,  0xdc,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
 
     0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
     0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
@@ -42,7 +42,7 @@
     0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
     0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
 
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x1d,  0x2a,  0x38,  0xdb,  0x9d,  0x36,  0xb8,  0xdc,
     0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
 
     0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/maps/usb.map linux/drivers/usb/maps/usb.map
--- v2.3.19/linux/drivers/usb/maps/usb.map	Tue Jun 29 09:33:33 1999
+++ linux/drivers/usb/maps/usb.map	Thu Oct  7 10:17:09 1999
@@ -223,11 +223,11 @@
 keycode 105 = F14             
 
 # modifiers
-keycode 120 = Control
-keycode 121 = Shift
-keycode 122 = Alt
-keycode 123 = Window
-keycode 124 = Control_R
-keycode 125 = Shift_R
-keycode 126 = Alt_R
-keycode 127 = Window_R
+keycode 224 = Control
+keycode 225 = Shift
+keycode 226 = Alt
+keycode 227 = Window
+keycode 228 = Control_R
+keycode 229 = Shift_R
+keycode 230 = Alt_R
+keycode 231 = Window_R
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/ohci-debug.c linux/drivers/usb/ohci-debug.c
--- v2.3.19/linux/drivers/usb/ohci-debug.c	Sun Jul 25 20:30:46 1999
+++ linux/drivers/usb/ohci-debug.c	Thu Oct  7 10:17:09 1999
@@ -80,7 +80,7 @@
 
 	printk(KERN_DEBUG "   ohci ED:\n");
 	printk(KERN_DEBUG "     status     =  0x%x\n", stat);
-	printk(KERN_DEBUG "       %sMPS %d%s%s%s%s tc%d e%d fa%d%s\n",
+	printk(KERN_DEBUG "       %sMPS %d%s%s%s%s tc%d e%d fa%d [HCD_%d%s]\n",
 			skip ? "Skip " : "",
 			mps,
 			isoc ? " Isoc." : "",
@@ -91,7 +91,8 @@
 			toggle,
 			endnum,
 			funcaddr,
-			(stat & ED_ALLOCATED) ? " Allocated" : "");
+			ohci_ed_hcdtype(ed) >> 27,
+			(stat & ED_ALLOCATED) ? ", Allocated" : "");
 	printk(KERN_DEBUG "     tail_td    =  0x%x\n", ed_tail_td(ed));
 	printk(KERN_DEBUG "     head_td    =  0x%x\n", ed_head_td(ed));
 	printk(KERN_DEBUG "     next_ed    =  0x%x\n", le32_to_cpup(&ed->next_ed));
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c
--- v2.3.19/linux/drivers/usb/ohci-hcd.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/ohci-hcd.c	Thu Oct  7 10:17:09 1999
@@ -14,7 +14,7 @@
  * [ Open Host Controller Interface driver for USB. ]
  * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
  * [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
- * [ $Log: ohci.c,v $ ]
+ * [ _Log: ohci-hcd.c,v _
  * [ Revision 1.1  1999/04/05 08:32:30  greg ]
  * 
  * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
@@ -224,7 +224,7 @@
 	return 0;
 }
 
-static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len)
+static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len, int timeout)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct ohci_state state = {0, TD_NOTACCESSED};
@@ -254,7 +254,7 @@
     OHCI_DEBUG(printk("USB HC trans req ed %x: %x :", ed->hwINFO, (unsigned int ) ed); )
  	OHCI_DEBUG({ int i; for( i= 0; i<8 ;i++) printk(" %4x", ((unsigned int *) ed)[i]) ; printk("\n"); }; )
  	if (ED_STATE(ed) != ED_OPER)  ohci_link_ed(ohci, ed);
- 	schedule_timeout(HZ*5);
+ 	schedule_timeout(timeout);
    
     if(state.status == TD_NOTACCESSED) {	
     	current->state = TASK_UNINTERRUPTIBLE;
@@ -266,7 +266,7 @@
 	return state.status;
 }
 
-static int sohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval)
+static int sohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval, int timeout)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct ohci_state state = {0, TD_NOTACCESSED};
@@ -286,7 +286,7 @@
 	ohci_trans_req(ohci, ed, 0, NULL, data, len, (__OHCI_BAG) &state, (__OHCI_BAG) &wait,(usb_pipeout(pipe))?BULK_OUT:BULK_IN, sohci_blocking_handler);
 	if (ED_STATE(ed) != ED_OPER)  ohci_link_ed(ohci, ed);
 	
-	schedule_timeout(HZ*5);
+	schedule_timeout(timeout);
 
 	if(state.status == TD_NOTACCESSED) {		
     	current->state = TASK_UNINTERRUPTIBLE;
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/ohci-hcd.h linux/drivers/usb/ohci-hcd.h
--- v2.3.19/linux/drivers/usb/ohci-hcd.h	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/ohci-hcd.h	Thu Oct  7 10:17:09 1999
@@ -12,7 +12,7 @@
  * [ Open Host Controller Interface driver for USB. ]
  * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
  * [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
- * [ $Log: ohci.c,v $ ]
+ * [ _Log: ohci-hcd.h,v _
  * [ Revision 1.1  1999/04/05 08:32:30  greg ]
  * 
  * v4.0 1999/08/18
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.19/linux/drivers/usb/ohci.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/ohci.c	Thu Oct  7 10:17:09 1999
@@ -15,7 +15,7 @@
  * Architecture" book by Mindshare, Inc.  It was a reasonable introduction
  * and overview of USB and the two dominant host controller interfaces
  * however you're better off just reading the real specs available
- * from www.usb.org as you'll need them to get enough detailt to
+ * from www.usb.org as you'll need them to get enough details to
  * actually implement a HCD.  The book has many typos and omissions
  * Beware, the specs are the victim of a committee.
  *
@@ -24,7 +24,7 @@
  *
  * No filesystems were harmed in the development of this code.
  *
- * $Id: ohci.c,v 1.43 1999/05/16 22:35:24 greg Exp $
+ * $Id: ohci.c,v 1.77 1999/09/16 04:30:19 greg Exp $
  */
 
 #include <linux/config.h>
@@ -201,7 +201,6 @@
 	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
 } /* ohci_add_ed_to_hw() */
 
-
 /*
  *  Put a control ED on the controller's list
  */
@@ -275,24 +274,19 @@
 	for (;;) {
 		int_ed = bus_to_virt(le32_to_cpup(&int_ed->next_ed));
 		/* stop if we get to the end or to another dummy ED. */
-		if (int_ed == 0)
-			break;
+		if (!int_ed)
+			break;  /* return NULL */
 		status = le32_to_cpup(&int_ed->status);
-		if ((status & OHCI_ED_FA) == 0)
-			break;
+		if ((status & OHCI_ED_FA) == 0) {
+			int_ed = NULL;
+			break;  /* return NULL */
+		}
 		/* check whether all the appropriate fields match */
 		if ((status & 0x7ffa7ff) == req_status)
-			return int_ed;
+			break;  /* return int_ed */
 	}
-	return 0;
-}
-
-/*
- *  Put an isochronous ED on the controller's list
- */
-inline void ohci_add_isoc_ed(struct ohci *ohci, struct ohci_ed *ed)
-{
-	ohci_add_periodic_ed(ohci, ed, 1);
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+	return int_ed;
 }
 
 
@@ -326,14 +320,14 @@
  * adds it to a list of EDs to destroy during the SOF interrupt
  * processing would be useful (and be callable from an interrupt).
  */
-void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_type)
+void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed)
 {
 	__u32 *hw_listcurrent;
 
 	/* tell the controller to skip this ED */
 	ed->status |= cpu_to_le32(OHCI_ED_SKIP);
 
-	switch (ed_type) {
+	switch (ohci_ed_hcdtype(ed)) {
 	case HCD_ED_CONTROL:
 		hw_listcurrent = &regs->ed_controlcurrent;
 		break;
@@ -370,7 +364,7 @@
  *  
  *  Note that the SKIP bit is left on in the removed ED.
  */
-void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_type)
+void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed)
 {
 	unsigned long flags;
 	struct ohci_regs *regs = ohci->regs;
@@ -378,6 +372,7 @@
 	__u32 bus_ed = virt_to_bus(ed);
 	__u32 bus_cur;
 	__u32 *hw_listhead_p;
+	__u32 ed_type = ohci_ed_hcdtype(ed);
 
 	if (ed == NULL || !bus_ed)
 		return;
@@ -391,7 +386,9 @@
 		hw_listhead_p = &regs->ed_bulkhead;
 		break;
 	default:
-		printk(KERN_ERR "Unknown HCD ED type %d.\n", ed_type);
+#ifdef OHCI_DEBUG
+		printk(KERN_ERR "Wrong HCD ED type: %d.\n", ed_type);
+#endif
 		return;
 	}
 
@@ -426,7 +423,7 @@
 	/*
 	 * Make sure this ED is not being accessed by the HC as we speak.
 	 */
-	ohci_wait_for_ed_safe(regs, ed, ed_type);
+	ohci_wait_for_ed_safe(regs, ed);
 
 	/* clear any links from the ED for safety */
 	ed->next_ed = 0;
@@ -434,24 +431,6 @@
 	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
 } /* ohci_remove_norm_ed_from_hw() */
 
-/*
- *  Remove an ED from the controller's control list.  Note that the SKIP bit
- *  is left on in the removed ED.
- */
-inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed)
-{
-	ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_CONTROL);
-}
-
-/*
- *  Remove an ED from the controller's bulk list.  Note that the SKIP bit
- *  is left on in the removed ED.
- */
-inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed)
-{
-	ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_BULK);
-}
-
 
 /*
  *  Remove a periodic ED from the host controller
@@ -476,7 +455,7 @@
 	while (cur_ed) {
 		if (ed == cur_ed) {		/* remove the ED */
 			/* set its SKIP bit and be sure its not in use */
-			ohci_wait_for_ed_safe(ohci->regs, ed, HCD_ED_INT);
+			ohci_wait_for_ed_safe(ohci->regs, ed);
 
 			/* unlink it */
 			spin_lock_irqsave(&ohci_edtd_lock, flags);
@@ -506,6 +485,20 @@
 
 
 /*
+ *  Remove an ED from the host controller, choosing 
+ */
+void ohci_remove_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+	/* Remove the ED from the HC */
+	if (ohci_ed_hcdtype(ed) & HCD_ED_NORMAL) {
+		ohci_remove_norm_ed_from_hw(ohci, ed);
+	} else {
+		ohci_remove_periodic_ed(ohci, ed);
+	}
+} /* ohci_remove_ed() */
+
+
+/*
  * Remove all the EDs which have a given device address from a list.
  * Used when the device is unplugged.
  * Returns 1 if anything was changed.
@@ -573,7 +566,7 @@
  *  Remove a TD from the given EDs TD list.  The TD is freed as well.
  *  (so far this function hasn't been needed)
  */
-static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
+void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
 {
 	unsigned long flags;
 	struct ohci_td *head_td;
@@ -670,10 +663,9 @@
  * pool.  Return NULL if none are left.
  *
  * NOTE: This function does not allocate and attach the dummy_td.
- * That is done in ohci_fill_ed().  FIXME: it should probably be moved
- * into here.
+ * That is done in ohci_fill_ed().  [should we really do that here?]
  */
-static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev)
+static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev, __u32 ed_type)
 {
 	int idx;
 
@@ -687,6 +679,7 @@
 			new_ed->status |= cpu_to_le32(OHCI_ED_SKIP);
 			/* mark it as allocated */
 			allocate_ed(new_ed);
+			ohci_ed_set_hcdtype(new_ed, ed_type);
 			new_ed->ohci_dev = dev;
 			return new_ed;
 		}
@@ -764,8 +757,7 @@
  *  force the Allocated bit on.
  */
 struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed,
-			     int maxpacketsize, int lowspeed, int endp_id,
-			     int isoc_tds)
+			     int maxpacketsize, int lowspeed, int endp_id)
 {
 	struct ohci_td *dummy_td;
 
@@ -789,11 +781,12 @@
 	/* set the head TD to the dummy and clear the Carry & Halted bits */
 	ed->_head_td = ed->tail_td;
 
-	ed->status = cpu_to_le32(
+	ed->status &= cpu_to_le32(OHCI_ED_HCD_MASK);
+	ed->status |= cpu_to_le32(
 		ed_set_maxpacket(maxpacketsize) |
 		ed_set_speed(lowspeed) |
 		(endp_id & 0x7ff) |
-		((isoc_tds == 0) ? OHCI_ED_F_NORM : OHCI_ED_F_ISOC));
+		((ohci_ed_hcdtype(ed) != HCD_ED_ISOC) ? OHCI_ED_F_NORM : OHCI_ED_F_ISOC));
 	allocate_ed(ed);
 	ed->next_ed = 0;
 
@@ -959,7 +952,7 @@
 	/* Get an ED and TD */
 	interrupt_ed = ohci_get_periodic_ed(dev, period, pipe, 0);
 	if (interrupt_ed == 0) {
-		interrupt_ed = ohci_get_free_ed(dev);
+		interrupt_ed = ohci_get_free_ed(dev, HCD_ED_INT);
 		if (!interrupt_ed) {
 			printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
 			return (-ENOMEM);
@@ -970,7 +963,7 @@
 		 * device number (function address), and type of TD.
 		 */
 		ohci_fill_ed(dev, interrupt_ed, maxps, usb_pipeslow(pipe),
-			     usb_pipe_endpdev(pipe), 0 /* normal TDs */);
+			     usb_pipe_endpdev(pipe) );
 		interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
 
 		/* Assimilate the new ED into the collective */
@@ -1077,7 +1070,7 @@
 static void * ohci_generic_trans(struct usb_device *usb_dev, int pipe,
 	int data_td_toggle, int round, int autofree,
 	void *dev_id, usb_device_irq handler, void *data, int len,
-	int ed_type, struct ohci_td *setup_td, struct ohci_td *status_td)
+	__u32 ed_type, struct ohci_td *setup_td, struct ohci_td *status_td)
 {
 	struct ohci_device *dev = usb_to_ohci(usb_dev);
 	struct ohci_ed *trans_ed;
@@ -1089,7 +1082,7 @@
 		printk(KERN_DEBUG "ohci_request_trans()\n");
 #endif
 
-	trans_ed = ohci_get_free_ed(dev);
+	trans_ed = ohci_get_free_ed(dev, ed_type);
 	if (!trans_ed) {
 		printk("usb-ohci: couldn't get ED for dev %p\n", dev);
 		return NULL;
@@ -1142,8 +1135,7 @@
 	ohci_fill_ed(dev, trans_ed,
 		usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)),
 		usb_pipeslow(pipe),
-		usb_pipe_endpdev(pipe),
-		(ed_type == HCD_ED_ISOC) );
+		usb_pipe_endpdev(pipe) );
 
 	/* initialize the toggle carry flag in the ED */
 	if (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
@@ -1202,7 +1194,7 @@
  *
  * This function is NOT safe to call from an interrupt.
  */
-static int ohci_terminate_trans(struct usb_device *usb_dev, void *handle, int ed_type)
+static int ohci_terminate_trans(struct usb_device *usb_dev, void *handle)
 {
 	struct ohci_ed *req_ed = (struct ohci_ed *) handle;
 	struct ohci_device *dev = usb_to_ohci(usb_dev);
@@ -1213,20 +1205,10 @@
 
 	/* stop the transfer & collect the number of bytes */
 	/* (this is the non-interrupt safe function call) */
-	ohci_wait_for_ed_safe(regs, req_ed, ed_type);
+	ohci_wait_for_ed_safe(regs, req_ed);
 
-	/* Remove the ED from the appropriate HC list */
-	switch (ed_type) {
-		case HCD_ED_ISOC:
-			ohci_remove_periodic_ed(dev->ohci, req_ed);
-			break;
-		case HCD_ED_CONTROL:
-			ohci_remove_control_ed(dev->ohci, req_ed);
-			break;
-		case HCD_ED_BULK:
-			ohci_remove_bulk_ed(dev->ohci, req_ed);
-			break;
-	}
+	/* Remove the ED from the HC */
+	ohci_remove_ed(dev->ohci, req_ed);
 
 	ohci_free_ed(req_ed);	/* return it to the pool */
 
@@ -1252,7 +1234,15 @@
 	/* pass the TDs completion status back to control_msg */
 	if (dev_id) {
 		int *completion_status = (int *)dev_id;
-		*completion_status = stats;
+
+		switch (stats) {
+		case USB_ST_NOERROR:
+		case USB_ST_DATAOVERRUN:
+			*completion_status = len;
+			break;
+		default:
+			*completion_status = -stats;
+		}
 	}
 
 	wake_up(&control_wakeup);
@@ -1274,13 +1264,13 @@
  * This function can NOT be called from an interrupt.
  */
 static int ohci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
-			    devrequest *cmd, void *data, int len)
+			    devrequest *cmd, void *data, int len, int timeout)
 {
 	struct ohci_device *dev = usb_to_ohci(usb_dev);
 	void *trans_handle;
 	struct ohci_td *setup_td, *status_td;
 	DECLARE_WAITQUEUE(wait, current);
-	int completion_status = -1;
+	int completion_status = USB_ST_TIMEOUT;
 	devrequest our_cmd;
 
 	/* byte-swap fields of cmd if necessary */
@@ -1356,8 +1346,8 @@
 		return USB_ST_INTERNALERROR;
 	}
 
-	/* wait a "reasonable" amount of time for it to complete */
-	schedule_timeout(HZ);
+	/* wait a user defined amount of time for it to complete */
+	schedule_timeout(timeout);
 
 	remove_wait_queue(&control_wakeup, &wait);
 
@@ -1369,9 +1359,12 @@
 	 * Also, since the TDs were autofreed, there is no guarantee that
 	 * they haven't been reclaimed by another transfer by now...
 	 */
-	if (completion_status != 0) {
-		const char *what = (completion_status < 0)? "timed out":
-			cc_names[completion_status & 0xf];
+	if (completion_status < 0) {
+		const char *what;
+		if (completion_status == USB_ST_TIMEOUT) 
+		        what = "timed out";
+		else
+		        what = cc_names[(-completion_status) & 0xf];
 		printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x",
 		       what, pipe, cmd->requesttype, cmd->request,
 		       cmd->value, cmd->index, cmd->length);
@@ -1422,10 +1415,8 @@
 	/* no TD cleanup, the TDs were auto-freed as they finished */
 
 	/* remove the generic_trans ED from the HC and free it */
-	ohci_terminate_trans(usb_dev, trans_handle, HCD_ED_CONTROL);
+	ohci_terminate_trans(usb_dev, trans_handle);
 
-	if (completion_status < 0)
-		completion_status = USB_ST_TIMEOUT;
 	return completion_status;
 } /* ohci_control_msg() */
 
@@ -1471,7 +1462,7 @@
  */
 static int ohci_terminate_bulk(struct usb_device *usb_dev, void * handle)
 {
-	return ohci_terminate_trans(usb_dev, handle, HCD_ED_CONTROL);
+	return ohci_terminate_trans(usb_dev, handle);
 } /* ohci_terminate_bulk() */
 
 
@@ -1536,24 +1527,6 @@
 } /* ohci_bulk_msg_td_handler() */
 
 
-/*
- * Request to send or receive bulk data for a blocking bulk_msg call.
- *
- * bulk_request->bytes_transferred_p is a pointer to an integer that
- * will be set to the number of bytes that have been successfully
- * transferred upon completion.  The interrupt handler will update it
- * after each internal TD completes successfully.
- */
-static struct ohci_ed* ohci_request_bulk_msg(struct ohci_bulk_msg_request_state *bulk_request)
-{
-	/* initialize the internal counter */
-	bulk_request->_bytes_done = 0;
-
-	return ohci_request_bulk(bulk_request->usb_dev, bulk_request->pipe,
-			ohci_bulk_msg_td_handler,
-			bulk_request->data, bulk_request->length,
-			bulk_request);
-} /* ohci_request_bulk_msg() */
 
 
 static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
@@ -1574,7 +1547,7 @@
 } /* ohci_bulk_msg_completed() */
 
 
-static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *bytes_transferred_p)
+static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *bytes_transferred_p, int timeout)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	int completion_status = USB_ST_INTERNALERROR;
@@ -1598,6 +1571,7 @@
 	req.bytes_transferred_p = bytes_transferred_p;
 	req.dev_id = &completion_status;
 	req.completion = ohci_bulk_msg_completed;
+	req._bytes_done = 0;
 	if (bytes_transferred_p)
 		*bytes_transferred_p = 0;
 
@@ -1611,10 +1585,20 @@
 	current->state = TASK_UNINTERRUPTIBLE;
 	add_wait_queue(&bulk_wakeup, &wait);
 
-	req_ed = ohci_request_bulk_msg(&req);
+	/*
+ 	 * Request to send or receive bulk data for a blocking bulk_msg call.
+ 	 *
+ 	 * req.bytes_transferred_p is a pointer to an integer that
+ 	 * will be set to the number of bytes that have been successfully
+ 	 * transferred upon completion.  The interrupt handler will update it
+ 	 * after each internal TD completes successfully.
+ 	 */
+	req_ed = ohci_request_bulk(usb_dev, pipe,
+			ohci_bulk_msg_td_handler,
+			data, len, &req);
 
-	/* FIXME this should to wait for a caller specified time... */
-	schedule_timeout(HZ*5);
+	/* wait for a caller specified time... */
+	schedule_timeout(timeout);
 
 	/* completion_status will only stay in this state of the
 	 * request never finished */
@@ -1629,7 +1613,7 @@
 		 * a previously requested bulk transfer. -greg */
 
 		/* stop the transfer & collect the number of bytes */
-		ohci_wait_for_ed_safe(regs, req_ed, HCD_ED_BULK);
+		ohci_wait_for_ed_safe(regs, req_ed);
 
 		/* Get the number of bytes transferred out of the head TD
 		 * on the ED if it didn't finish while we were waiting. */
@@ -1659,7 +1643,7 @@
 	remove_wait_queue(&bulk_wakeup, &wait);
 
 	/* remove the ED from the HC */
-	ohci_remove_bulk_ed(usb_to_ohci(usb_dev)->ohci, req_ed);
+	ohci_remove_norm_ed_from_hw(usb_to_ohci(usb_dev)->ohci, req_ed);
 
 	/* save the toggle value back into the usb_dev */
 	usb_settoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe),
@@ -1681,31 +1665,19 @@
 
 
 /*
- * Allocate a new USB device to be attached to an OHCI controller
+ * Allocate a new USB device attached to this OHCI controller
  */
-static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
+static int ohci_dev_allocate(struct usb_device *usb_dev)
 {
-	struct usb_device *usb_dev;
 	struct ohci_device *dev;
 	int idx;
 
 	/*
-	 * Allocate the generic USB device
-	 */
-	usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
-	if (!usb_dev)
-		return NULL;
-
-	memset(usb_dev, 0, sizeof(*usb_dev));
-
-	/*
 	 * Allocate an OHCI device (EDs and TDs for this device)
 	 */
 	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		kfree(usb_dev);
-		return NULL;
-	}
+	if (!dev)
+		return -1;
 
 	memset(dev, 0, sizeof(*dev));
 
@@ -1721,80 +1693,71 @@
 	usb_dev->hcpriv = dev;
 	dev->usb = usb_dev;
 
-	/*
-	 * Link the device to its parent (hub, etc..) if any.
-	 */
-	usb_dev->parent = parent;
+	if (usb_dev->parent)
+		dev->ohci = usb_to_ohci(usb_dev->parent)->ohci;
 
-	if (parent) {
-		usb_dev->bus = parent->bus;
-		dev->ohci = usb_to_ohci(parent)->ohci;
-	}
-
-	return usb_dev;
-} /* ohci_usb_allocate() */
+	return 0;
+} /* ohci_dev_allocate() */
 
 
 /*
- * Free a usb device.
- *
- * TODO This function needs to take better care of the EDs and TDs, etc.
+ * Free a usb device on this ohci controller.
  */
-static int ohci_usb_deallocate(struct usb_device *usb_dev)
+static int ohci_dev_deallocate(struct usb_device *usb_dev)
 {
 	struct ohci_device *dev = usb_to_ohci(usb_dev);
 
 	ohci_remove_device(dev->ohci, usb_dev->devnum);
 
-	/* kfree(usb_to_ohci(usb_dev)); */
-	/* kfree(usb_dev); */
+	kfree(usb_to_ohci(usb_dev));
 	return 0;
 }
 
-
-static void *ohci_alloc_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
+static int ohci_get_current_frame_number(struct usb_device *usb_dev)
 {
-	return NULL;
+	return USB_ST_NOTSUPPORTED;
 }
 
-static void ohci_delete_isochronous (struct usb_device *dev, void *_isodesc)
+static int ohci_alloc_isochronous (struct usb_device *usb_dev,
+unsigned int pipe, int frame_count, void *context,
+struct usb_isoc_desc **isocdesc)
 {
-	return;
+	return USB_ST_NOTSUPPORTED;
 }
 
-static int ohci_sched_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
+static void ohci_delete_isochronous (struct usb_isoc_desc *isocdesc)
 {
-	return USB_ST_NOTSUPPORTED;
+	return;
 }
 
-static int ohci_unsched_isochronous (struct usb_device *usb_dev, void *_isodesc)
+static int ohci_sched_isochronous (struct usb_isoc_desc *isocdesc,
+struct usb_isoc_desc *pr_isocdesc)
 {
 	return USB_ST_NOTSUPPORTED;
 }
 
-static int ohci_compress_isochronous (struct usb_device *usb_dev, void *_isodesc)
+static int ohci_unsched_isochronous (struct usb_isoc_desc *isocdesc)
 {
 	return USB_ST_NOTSUPPORTED;
 }
 
-
 /*
  * functions for the generic USB driver
  */
 struct usb_operations ohci_device_operations = {
-	ohci_usb_allocate,
-	ohci_usb_deallocate,
+	ohci_dev_allocate,
+	ohci_dev_deallocate,
 	ohci_control_msg,
 	ohci_bulk_msg,
 	ohci_request_irq,
 	ohci_release_irq,
 	ohci_request_bulk,
 	ohci_terminate_bulk,
+        ohci_get_current_frame_number,
 	ohci_alloc_isochronous,
 	ohci_delete_isochronous,
 	ohci_sched_isochronous,
-	ohci_unsched_isochronous,
-	ohci_compress_isochronous
+	ohci_unsched_isochronous
 };
 
 
@@ -1887,8 +1850,10 @@
 	/* Enter the USB Operational state & start the frames a flowing.. */
 	writel_set(OHCI_USB_OPER, &ohci->regs->control);
 	
-	/* Enable control lists */
-	writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control);
+	/* Enable control lists, claim the host controller */
+	writel_set(
+		OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE,
+		&ohci->regs->control);
 
 	/* Force global power enable -gal@cs.uni-magdeburg.de */
 	/* 
@@ -1988,10 +1953,11 @@
 	/*
 	 * Allocate a device for the new thingy that's been attached
 	 */
-	usb_dev = ohci_usb_allocate(root_hub->usb);
-	dev = usb_dev->hcpriv;
+	usb_dev = usb_alloc_dev(root_hub->usb, root_hub->usb->bus);
+	if (!usb_dev)
+	        return;
 
-	dev->ohci = ohci;
+	dev = usb_dev->hcpriv;
 
 	usb_connect(dev->usb);
 
@@ -2360,6 +2326,8 @@
 	struct usb_bus *bus;
 	struct ohci_device *dev;
 	struct usb_device *usb;
+        struct ohci_hcca *hcca;
+	u32 ctrl;
 
 #if 0
 	printk(KERN_DEBUG "entering alloc_ohci %p\n", mem_base);
@@ -2368,22 +2336,28 @@
 	ohci = kmalloc(sizeof(*ohci), GFP_KERNEL);
 	if (!ohci)
 		return NULL;
-
 	memset(ohci, 0, sizeof(*ohci));
 
 	ohci->irq = -1;
 	ohci->regs = mem_base;
 	INIT_LIST_HEAD(&ohci->interrupt_list);
 
-	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
-	if (!bus)
-		return NULL;
-
-	memset(bus, 0, sizeof(*bus));
+	/*
+	 * Allocate the Host Controller Communications Area on a 256
+	 * byte boundary.  XXX take the easy way out and just grab a
+	 * page as that's guaranteed to have a nice boundary.
+	 */
+	hcca = (struct ohci_hcca *) __get_free_page(GFP_KERNEL);
+	if (hcca == NULL)
+	        goto au_free_ohci;
+	memset(hcca, 0, sizeof(struct ohci_hcca));
+
+        bus = usb_alloc_bus(&ohci_device_operations);
+        if (!bus)
+                goto au_free_hcca;
 
 	ohci->bus = bus;
 	bus->hcpriv = ohci;
-	bus->op = &ohci_device_operations;
 
 	/*
 	 * Allocate the USB device structure and root hub.
@@ -2393,25 +2367,21 @@
 	 * a nice pool of memory with pointers to endpoint descriptors
 	 * for the different interrupts.
 	 */
-	usb = ohci_usb_allocate(NULL);
+	usb = usb_alloc_dev(NULL, bus);
 	if (!usb)
-		return NULL;
+		goto au_free_bus;
 
-	dev = usb_to_ohci(usb);
-	ohci->bus->root_hub= ohci_to_usb(dev);
 	usb->bus = bus;
+	
+	dev = usb_to_ohci(usb);
+	dev->ohci = ohci;
+	dev->hcca = hcca;
+
+	ohci->bus->root_hub = ohci_to_usb(dev);
 
 	/* Initialize the root hub */
 	dev->ohci = ohci;    /* link back to the controller */
 
-	/*
-	 * Allocate the Host Controller Communications Area on a 256
-	 * byte boundary.  XXX take the easy way out and just grab a
-	 * page as that's guaranteed to have a nice boundary.
-	 */
-	dev->hcca = (struct ohci_hcca *) __get_free_page(GFP_KERNEL);
-	memset(dev->hcca, 0, sizeof(struct ohci_hcca));
- 
 	/* Tell the controller where the HCCA is */
 	writel(virt_to_bus(dev->hcca), &ohci->regs->hcca);
 
@@ -2431,6 +2401,25 @@
 	}
 	printk(KERN_DEBUG "usb-ohci: %d root hub ports found\n", usb->maxchild);
 
+
+	/*
+	 *	Fix up legacy mode
+         */
+	     	 		
+	ctrl = readl(&ohci->regs->control);  
+	if(ctrl&OHCI_USB_IR)
+	{
+		int ct = 0; 
+		/* Ask SMM for the controls */
+	        writel(8, &ohci->regs->cmdstatus);
+	        printk(KERN_INFO "usb-ohci: switching interface from legacy mode.\n");
+	        while((readl(&ohci->regs->control)&OHCI_USB_IR) && ct < 250)
+	        {
+	        	udelay(100);
+	         	ct++;
+	         }
+	}
+	
 	/*
 	 * Initialize the ED polling "tree" (for simplicity's sake in
 	 * this driver many nodes in the tree will be identical)
@@ -2485,6 +2474,15 @@
 #endif
 
 	return ohci;
+
+au_free_bus:
+	usb_free_bus(bus);
+au_free_hcca:
+	free_page((unsigned long)hcca);
+au_free_ohci:
+	kfree(ohci);
+	return NULL;
+
 } /* alloc_ohci() */
 
 
@@ -2752,6 +2750,8 @@
 	/* If its OHCI, its memory */
 	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
 		return -ENODEV;
+
+	pci_set_master(dev);
 
 	/* Get the memory address and map it for IO */
 	mem_base = dev->resource[0].start;
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h
--- v2.3.19/linux/drivers/usb/ohci.h	Sun Jul 25 20:30:46 1999
+++ linux/drivers/usb/ohci.h	Thu Oct  7 10:17:09 1999
@@ -6,7 +6,7 @@
  *
  * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
  *
- * $Id: ohci.h,v 1.24 1999/05/16 10:18:26 greg Exp $
+ * $Id: ohci.h,v 1.40 1999/09/05 07:26:46 greg Exp $
  */
 
 #include <linux/list.h>
@@ -148,19 +148,45 @@
 #define OHCI_ED_EN	(0xf << 7)
 #define OHCI_ED_FA	(0x7f)
 
+
 #define ed_get_en(ed)	((le32_to_cpup(&(ed)->status) & OHCI_ED_EN) >> 7)
 #define ed_get_fa(ed)	(le32_to_cpup(&(ed)->status) & OHCI_ED_FA)
 
 /* NOTE: bits 27-31 of the status dword are reserved for the HCD */
+#define OHCI_ED_HCD_MASK	(0x1f << 27)
 /*
  * We'll use this status flag for to mark if an ED is in use by the
- * driver or not.  If the bit is set, it is being used.
+ * driver or not.  If the bit is set, it is being used.  (bit 31)
  */
 #define ED_ALLOCATED	(1 << 31)
 #define ed_allocated(ed)	(le32_to_cpup(&(ed).status) & ED_ALLOCATED)
 #define allocate_ed(ed)		((ed)->status |= cpu_to_le32(ED_ALLOCATED))
 
 /*
+ * These store the endpoint transfer type for this ED in the status
+ * field.  (bits 27 and 28)
+ *   Bit 28:
+ *     0 = Periodic ED
+ *       Bit 27:
+ *         0 = Isochronous
+ *         1 = Interrupt
+ *     1 = Normal ED
+ *       Bit 27:
+ *         0 = Control
+ *         1 = Bulk
+ */
+#define HCD_ED_NORMAL	(1 << 28)  /* (2 << 27) */
+#define HCD_ED_ISOC     (0)
+#define HCD_ED_INT      (1 << 27)
+#define HCD_ED_CONTROL  (2 << 27)
+#define HCD_ED_BULK     (3 << 27)
+#define HCD_ED_MASK	(3 << 27)
+
+#define ohci_ed_hcdtype(ed)	(le32_to_cpup(&(ed)->status) & HCD_ED_MASK)
+#define ohci_ed_set_hcdtype(ed, t)	( (ed)->status = ((ed)->status & ~cpu_to_le32(HCD_ED_MASK)) | cpu_to_le32((t) & HCD_ED_MASK) )
+
+
+/*
  * The HCCA (Host Controller Communications Area) is a 256 byte
  * structure defined in the OHCI spec. that the host controller is
  * told the base address of.  It must be 256-byte aligned.
@@ -299,15 +325,6 @@
 	} roothub;
 } __attribute((aligned(32)));
 
-/*
- * These are used by internal ED managing functions as a
- * parameter to state the type of ED to deal with (when it matters).
- */
-#define HCD_ED_ISOC     (0)
-#define HCD_ED_INT      (1)
-#define HCD_ED_CONTROL  (2)
-#define HCD_ED_BULK     (3)
-
 /* 
  * Read a MMIO register and re-write it after ANDing with (m)
  */
@@ -368,12 +385,16 @@
 /*
  * Control register masks
  */
+#define OHCI_USB_RESUME		(1 << 6)
 #define OHCI_USB_OPER		(2 << 6)
 #define OHCI_USB_SUSPEND	(3 << 6)
 #define OHCI_USB_PLE		(1 << 2)  /* Periodic (interrupt) list enable */
 #define OHCI_USB_IE		(1 << 3)  /* Isochronous list enable */
 #define OHCI_USB_CLE		(1 << 4)  /* Control list enable */
 #define OHCI_USB_BLE		(1 << 5)  /* Bulk list enable */
+#define OHCI_USB_IR		(1 << 8)  /* Int. Routing, HCD ownership */
+#define OHCI_USB_RWC		(1 << 9)  /* Remote Wakeup Connected */
+#define OHCI_USB_RWE		(1 << 10) /* Remote Wakeup Enable */
 
 /*
  * Command status register masks
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.19/linux/drivers/usb/printer.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/printer.c	Thu Oct  7 10:17:09 1999
@@ -58,7 +58,7 @@
 	dr.value = 0;
 	dr.index = 0;
 	dr.length = 1;
-	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 1)) {
+	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 1, HZ)) {
 		return 0;
 	}
 	return status;
@@ -104,7 +104,7 @@
 	dr.value = 0;
 	dr.index = 0;
 	dr.length = 0;
-	dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0, HZ);
 }
 
 static int open_printer(struct inode * inode, struct file * file)
@@ -129,10 +129,11 @@
 
 	printer_check_status(p);
 
-
 	file->private_data = p;
 //	printer_reset(p);
 	init_waitqueue_head(&p->wait_q);
+
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -143,13 +144,12 @@
 	free_page((unsigned long)p->obuf);
 	p->isopen = 0;
 	file->private_data = NULL;
+	/* free the resources if the printer is no longer around */
 	if(!p->pusb_dev) {
 		minor_data[p->minor] = NULL;
 		kfree(p);
-
-		MOD_DEC_USE_COUNT;
-
 	}
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -184,7 +184,7 @@
 			}
 			result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
 					 usb_sndbulkpipe(p->pusb_dev, endpoint_num),
-					 obuf, thistime, &partial);
+					 obuf, thistime, &partial, HZ*20);
 			if (partial) {
 				obuf += partial;
 				thistime -= partial;
@@ -243,7 +243,7 @@
 
 		result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
 			  usb_rcvbulkpipe(p->pusb_dev, endpoint_num),
-			  buf, this_read, &partial);
+			  buf, this_read, &partial, HZ*20);
 
 		/* unlike writes, we don't retry a NAK, just stop now */
 		if (!result & partial)
@@ -344,7 +344,7 @@
 		dr.value = 0;
 		dr.index = 0;
 		dr.length = sizeof(ieee_id) - 1;
-		if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, ieee_id, sizeof(ieee_id)-1) == 0) {
+		if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, ieee_id, sizeof(ieee_id)-1, HZ) == 0) {
 			if (ieee_id[1] < sizeof(ieee_id) - 1)
 				ieee_id[ieee_id[1]+2] = '\0';
 			else
@@ -373,7 +373,6 @@
 	minor_data[pp->minor] = NULL;
 	kfree(pp);
 	dev->private = NULL;		/* just in case */
-	MOD_DEC_USE_COUNT;
 }
 
 static struct usb_driver printer_driver = {
@@ -402,8 +401,6 @@
 {
 	int result;
 
-	MOD_INC_USE_COUNT;
-	
 	if ((result = register_chrdev(USB_PRINTER_MAJOR, "usblp", &usb_printer_fops)) < 0) {
 		printk(KERN_WARNING "usbprinter: Cannot register device\n");
 		return result;
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/proc_usb.c linux/drivers/usb/proc_usb.c
--- v2.3.19/linux/drivers/usb/proc_usb.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/proc_usb.c	Fri Oct  8 15:47:08 1999
@@ -286,9 +286,12 @@
 static int usb_hcd_bandwidth (const struct usb_device *dev, char *buf, int *len)
 {
 	*len += sprintf (buf + *len, format_bandwidth,
-			dev->bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC,
-			100 * dev->bus->bandwidth_allocated / FRAME_TIME_MAX_USECS_ALLOC,
-			dev->bus->bandwidth_int_reqs, dev->bus->bandwidth_isoc_reqs
+			dev->bus->bandwidth_allocated,
+			FRAME_TIME_MAX_USECS_ALLOC,
+			(100 * dev->bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) /
+				FRAME_TIME_MAX_USECS_ALLOC,
+			dev->bus->bandwidth_int_reqs,
+			dev->bus->bandwidth_isoc_reqs
 			);
 
 	return (*len >= DUMP_LIMIT) ? -1 : 0;
@@ -360,12 +363,12 @@
 	if (*len >= DUMP_LIMIT)
 		return -1;
 
-	if (usbdev->devnum > 0) {	/* for any except root hub */
-		if (usb_dump_desc (usbdev, buf, len) < 0)
+	if ((level == 0) && (usbdev->devnum < 0)) {	/* for root hub */
+		if (usb_hcd_bandwidth (usbdev, buf, len) < 0)
 			return -1;
 	}
-	else {		/* for a host controller */
-		if (usb_hcd_bandwidth (usbdev, buf, len) < 0)
+	else {	/* for anything but a root hub */
+		if (usb_dump_desc (usbdev, buf, len) < 0)
 			return -1;
 	}
 
@@ -509,8 +512,10 @@
 	struct usb_device *dev = (struct usb_device *)dp->data;
 	struct ezusb_ctrltransfer ctrl;
 	struct ezusb_bulktransfer bulk;
+	struct ezusb_old_ctrltransfer octrl;
+	struct ezusb_old_bulktransfer obulk;
 	struct ezusb_setinterface setintf;
-	unsigned int len1, ep, pipe;
+	unsigned int len1, ep, pipe, cfg;
 	unsigned long len2;
 	unsigned char *tbuf;
 	int i;
@@ -525,24 +530,28 @@
 		if (!capable(CAP_SYS_RAWIO))
 			return -EPERM;
 		copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
-		if (ctrl.dlen > PAGE_SIZE)
+		if (ctrl.length > PAGE_SIZE)
 			return -EINVAL;
 		if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
 			return -ENOMEM;
 		if (ctrl.requesttype & 0x80) {
-			if (ctrl.dlen && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.dlen)) {
+			if (ctrl.length && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.length)) {
 				free_page((unsigned long)tbuf);
 				return -EINVAL;
 			}
-			i = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), (devrequest *)&ctrl, tbuf, ctrl.dlen);
-			if (!i && ctrl.dlen) {
-				copy_to_user_ret(ctrl.data, tbuf, ctrl.dlen, -EFAULT);
+			i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+					    ctrl.value, ctrl.index, tbuf, ctrl.length, 
+					    (ctrl.timeout * HZ + 500) / 1000);
+			if (!i && ctrl.length) {
+				copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
 			}
 		} else {
-			if (ctrl.dlen) {
-				copy_from_user_ret(tbuf, ctrl.data, ctrl.dlen, -EFAULT);
+			if (ctrl.length) {
+				copy_from_user_ret(tbuf, ctrl.data, ctrl.length, -EFAULT);
 			}
-			i = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), (devrequest *)&ctrl, tbuf, ctrl.dlen);
+			i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+					    ctrl.value, ctrl.index, tbuf, ctrl.length, 
+					    (ctrl.timeout * HZ + 500) / 1000);
 		}
 		free_page((unsigned long)tbuf);
 		if (i) {
@@ -577,7 +586,7 @@
 				free_page((unsigned long)tbuf);
 				return -EINVAL;
 			}
-			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2);
+			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, (ctrl.timeout * HZ + 500) / 1000);
 			if (!i && len2) {
 				copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
 			}
@@ -585,7 +594,7 @@
 			if (len1) {
 				copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
 			}
-			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2);
+			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, (ctrl.timeout * HZ + 500) / 1000);
 		}
 		free_page((unsigned long)tbuf);
 		if (i) {
@@ -595,6 +604,85 @@
 		}
 		return len2;
 
+	case EZUSB_OLD_CONTROL:
+		if (obsolete_warn < 20) {
+			printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_OLD_CONTROL ioctl\n",
+			       current->pid, current->comm);
+			obsolete_warn++;
+		}
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		copy_from_user_ret(&octrl, (void *)arg, sizeof(octrl), -EFAULT);
+		if (octrl.dlen > PAGE_SIZE)
+			return -EINVAL;
+		if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+			return -ENOMEM;
+		if (octrl.requesttype & 0x80) {
+			if (octrl.dlen && !access_ok(VERIFY_WRITE, octrl.data, octrl.dlen)) {
+				free_page((unsigned long)tbuf);
+				return -EINVAL;
+			}
+			i = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), (devrequest *)&octrl, tbuf, octrl.dlen, HZ);
+			if (!i && octrl.dlen) {
+				copy_to_user_ret(octrl.data, tbuf, octrl.dlen, -EFAULT);
+			}
+		} else {
+			if (octrl.dlen) {
+				copy_from_user_ret(tbuf, octrl.data, octrl.dlen, -EFAULT);
+			}
+			i = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), (devrequest *)&octrl, tbuf, octrl.dlen, HZ);
+		}
+		free_page((unsigned long)tbuf);
+		if (i) {
+			printk(KERN_WARNING "procusb: EZUSB_OLD_CONTROL failed rqt %u rq %u len %u ret %d\n", 
+			       octrl.requesttype, octrl.request, octrl.length, i);
+			return -ENXIO;
+		}
+		return 0;
+
+	case EZUSB_OLD_BULK:
+		if (obsolete_warn < 20) {
+			printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_OLD_BULK ioctl\n",
+			       current->pid, current->comm);
+			obsolete_warn++;
+		}
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		copy_from_user_ret(&obulk, (void *)arg, sizeof(obulk), -EFAULT);
+		if (obulk.ep & 0x80)
+			pipe = usb_rcvbulkpipe(dev, obulk.ep & 0x7f);
+		else
+			pipe = usb_sndbulkpipe(dev, obulk.ep & 0x7f);
+		if (!usb_maxpacket(dev, pipe, !(obulk.ep & 0x80)))
+			return -EINVAL;
+		len1 = obulk.len;
+		if (len1 > PAGE_SIZE)
+			len1 = PAGE_SIZE;
+		if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+			return -ENOMEM;
+		if (obulk.ep & 0x80) {
+			if (len1 && !access_ok(VERIFY_WRITE, obulk.data, len1)) {
+				free_page((unsigned long)tbuf);
+				return -EINVAL;
+			}
+			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
+			if (!i && len2) {
+				copy_to_user_ret(obulk.data, tbuf, len2, -EFAULT);
+			}
+		} else {
+			if (len1) {
+				copy_from_user_ret(tbuf, obulk.data, len1, -EFAULT);
+			}
+			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
+		}
+		free_page((unsigned long)tbuf);
+		if (i) {
+			printk(KERN_WARNING "procusb: EZUSB_OLD_BULK failed ep 0x%x len %u ret %d\n", 
+			       obulk.ep, obulk.len, i);
+			return -ENXIO;
+		}
+		return len2;
+
 	case EZUSB_RESETEP:
 		if (obsolete_warn < 20) {
 			printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_RESETEP ioctl\n",
@@ -621,6 +709,20 @@
 		if (usb_set_interface(dev, setintf.interface, setintf.altsetting))
 			return -EINVAL;
 		return 0;
+
+	case EZUSB_SETCONFIGURATION:
+		if (obsolete_warn < 20) {
+			printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_SETCONFIGURATION ioctl\n",
+			       current->pid, current->comm);
+			obsolete_warn++;
+		}
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		get_user_ret(cfg, (unsigned int *)arg, -EFAULT);
+		if (usb_set_configuration(dev, cfg) < 0)
+			return -EINVAL;
+		return 0;
+
 	}
 	return -ENOIOCTLCMD;
 }
@@ -633,8 +735,10 @@
 	struct usb_device *dev = (struct usb_device *)dp->data;
 	struct usb_proc_ctrltransfer ctrl;
 	struct usb_proc_bulktransfer bulk;
+	struct usb_proc_old_ctrltransfer octrl;
+	struct usb_proc_old_bulktransfer obulk;
 	struct usb_proc_setinterface setintf;
-	unsigned int len1, ep, pipe;
+	unsigned int len1, ep, pipe, cfg;
 	unsigned long len2;
 	unsigned char *tbuf;
 	int i;
@@ -655,7 +759,7 @@
 			}
 			i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, 
 					    ctrl.requesttype, ctrl.value, ctrl.index, tbuf, 
-					    ctrl.length);
+					    ctrl.length, (ctrl.timeout * HZ + 500) / 1000);
 			if (!i && ctrl.length) {
 				copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
 			}
@@ -665,7 +769,7 @@
 			}
 			i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, 
 					    ctrl.requesttype, ctrl.value, ctrl.index, tbuf, 
-					    ctrl.length);
+					    ctrl.length, (ctrl.timeout * HZ + 500) / 1000);
 		}
 		free_page((unsigned long)tbuf);
 		if (i) {
@@ -695,7 +799,7 @@
 				free_page((unsigned long)tbuf);
 				return -EINVAL;
 			}
-			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2);
+			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, (bulk.timeout * HZ + 500) / 1000);
 			if (!i && len2) {
 				copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
 			}
@@ -703,7 +807,7 @@
 			if (len1) {
 				copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
 			}
-			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2);
+			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, (bulk.timeout * HZ + 500) / 1000);
 		}
 		free_page((unsigned long)tbuf);
 		if (i) {
@@ -713,6 +817,79 @@
 		}
 		return len2;
 
+	case USB_PROC_OLD_CONTROL:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		copy_from_user_ret(&octrl, (void *)arg, sizeof(octrl), -EFAULT);
+		if (octrl.length > PAGE_SIZE)
+			return -EINVAL;
+		if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+			return -ENOMEM;
+		if (octrl.requesttype & 0x80) {
+			if (octrl.length && !access_ok(VERIFY_WRITE, octrl.data, octrl.length)) {
+				free_page((unsigned long)tbuf);
+				return -EINVAL;
+			}
+			i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), octrl.request, 
+					    octrl.requesttype, octrl.value, octrl.index, tbuf, 
+					    octrl.length, HZ);
+			if (!i && octrl.length) {
+				copy_to_user_ret(octrl.data, tbuf, octrl.length, -EFAULT);
+			}
+		} else {
+			if (octrl.length) {
+				copy_from_user_ret(tbuf, octrl.data, octrl.length, -EFAULT);
+			}
+			i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), octrl.request, 
+					    octrl.requesttype, octrl.value, octrl.index, tbuf, 
+					    octrl.length, HZ);
+		}
+		free_page((unsigned long)tbuf);
+		if (i) {
+			printk(KERN_WARNING "/proc/bus/usb: USB_PROC_OLD_CONTROL failed rqt %u rq %u len %u ret %d\n", 
+			       octrl.requesttype, octrl.request, octrl.length, i);
+			return -ENXIO;
+		}
+		return 0;
+
+	case USB_PROC_OLD_BULK:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		copy_from_user_ret(&obulk, (void *)arg, sizeof(obulk), -EFAULT);
+		if (obulk.ep & 0x80)
+			pipe = usb_rcvbulkpipe(dev, obulk.ep & 0x7f);
+		else
+			pipe = usb_sndbulkpipe(dev, obulk.ep & 0x7f);
+		if (!usb_maxpacket(dev, pipe, !(obulk.ep & 0x80)))
+			return -EINVAL;
+		len1 = obulk.len;
+		if (len1 > PAGE_SIZE)
+			len1 = PAGE_SIZE;
+		if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+			return -ENOMEM;
+		if (obulk.ep & 0x80) {
+			if (len1 && !access_ok(VERIFY_WRITE, obulk.data, len1)) {
+				free_page((unsigned long)tbuf);
+				return -EINVAL;
+			}
+			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
+			if (!i && len2) {
+				copy_to_user_ret(obulk.data, tbuf, len2, -EFAULT);
+			}
+		} else {
+			if (len1) {
+				copy_from_user_ret(tbuf, obulk.data, len1, -EFAULT);
+			}
+			i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
+		}
+		free_page((unsigned long)tbuf);
+		if (i) {
+			printk(KERN_WARNING "/proc/bus/usb: USB_PROC_OLD_BULK failed ep 0x%x len %u ret %d\n", 
+			       obulk.ep, obulk.len, i);
+			return -ENXIO;
+		}
+		return len2;
+
 	case USB_PROC_RESETEP:
 		if (!capable(CAP_SYS_RAWIO))
 			return -EPERM;
@@ -730,10 +907,21 @@
 			return -EINVAL;
 		return 0;
 
+	case USB_PROC_SETCONFIGURATION:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		get_user_ret(cfg, (unsigned int *)arg, -EFAULT);
+		if (usb_set_configuration(dev, cfg) < 0)
+			return -EINVAL;
+		return 0;
+
 	case EZUSB_CONTROL:
 	case EZUSB_BULK:
+	case EZUSB_OLD_CONTROL:
+	case EZUSB_OLD_BULK:
 	case EZUSB_RESETEP:
 	case EZUSB_SETINTERFACE:
+	case EZUSB_SETCONFIGURATION:
 		return usbdev_ioctl_ezusbcompat(inode, file, cmd, arg);
 	}
 	return -ENOIOCTLCMD;
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/serial.c linux/drivers/usb/serial.c
--- v2.3.19/linux/drivers/usb/serial.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial.c	Fri Oct  8 10:06:21 1999
@@ -0,0 +1,691 @@
+/*
+ * USB Serial Converter driver
+ *
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This was based on the ACM driver by Armin Fuerst (which was based
+ * on a driver by Brad Keryan)
+ *
+ * Currently only works for the Belkin and Peracom Serial converters.
+ * Should also work on the Etek serial converter, if anyone knows the
+ * vendor and device ids for that 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.
+ * 
+ * (C) Copyright 1999 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ */
+
+#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>
+
+
+#include "usb.h"
+/*#define SERIAL_DEBUG 1*/
+
+#ifdef SERIAL_DEBUG
+	#define debug_info(message); printk(message);
+#else
+	#define debug_info(message);
+#endif
+
+
+/* USB Serial devices vendor ids and device ids that this driver supports */
+#define BELKIN_VENDOR_ID		0x056c
+#define BELKIN_SERIAL_CONVERTER		0x8007
+#define PERACOM_VENDOR_ID		0x0565
+#define PERACOM_SERIAL_CONVERTER	0x0001
+
+
+#define SERIAL_MAJOR	240
+
+#define NUM_PORTS	4	/* Have to pick a number for now. Need to look */
+				/* into dynamically creating them at insertion time. */
+
+
+static int usb_serial_probe(struct usb_device *dev);
+static void usb_serial_disconnect(struct usb_device *dev);
+
+typedef enum {
+	unknown = 0,
+	Belkin = 1,
+	Peracom = 2
+	} SERIAL_TYPE;
+
+struct usb_serial_state {
+	struct usb_device *	dev;
+	SERIAL_TYPE		type;		/* what manufacturer's type of converter */
+	void *			irq_handle;
+	unsigned int		irqpipe;
+	struct tty_struct	*tty;		/* the coresponding tty for this device */
+	char			present;
+	char			active;
+
+	char			interrupt_in_inuse;
+	__u8			interrupt_in_endpoint;
+	__u8			interrupt_in_interval;
+	__u16			interrupt_in_size;
+	unsigned int		interrupt_in_pipe;
+	unsigned char *		interrupt_in_buffer;
+	void *			interrupt_in_transfer;
+
+	char			bulk_in_inuse;
+	__u8			bulk_in_endpoint;
+	__u8			bulk_in_interval;
+	__u16			bulk_in_size;
+	unsigned int		bulk_in_pipe;
+	unsigned char *		bulk_in_buffer;
+	void *			bulk_in_transfer;
+
+	char			bulk_out_inuse;
+	__u8			bulk_out_endpoint;
+	__u8			bulk_out_interval;
+	__u16			bulk_out_size;
+	unsigned int		bulk_out_pipe;
+	unsigned char *		bulk_out_buffer;
+	void *			bulk_out_transfer;
+};
+
+static struct usb_driver usb_serial_driver = {
+	"serial",
+	usb_serial_probe,
+	usb_serial_disconnect,
+	{ NULL, NULL }
+};
+
+static int			serial_refcount;
+static struct tty_driver 	serial_tty_driver;
+static struct tty_struct *	serial_tty[NUM_PORTS];
+static struct termios *		serial_termios[NUM_PORTS];
+static struct termios *		serial_termios_locked[NUM_PORTS];
+static struct usb_serial_state	serial_state_table[NUM_PORTS];
+
+
+
+static int serial_read_irq (int state, void *buffer, int count, void *dev_id)
+{
+	struct usb_serial_state *serial = (struct usb_serial_state *)dev_id;
+       	struct tty_struct *tty = serial->tty; 
+       	unsigned char* data = buffer;
+	int i;
+
+	debug_info("USB: serial_read_irq\n");
+
+#ifdef SERIAL_DEBUG
+	if (count) {
+		printk("%d %s\n", count, data);
+	}
+#endif
+
+	if (count) {
+		for (i=0;i<count;i++) {
+			 tty_insert_flip_char(tty,data[i],0);
+	  	}
+	  	tty_flip_buffer_push(tty);
+	}
+
+	/* Continue transfer */
+	/* return (1); */
+
+	/* No more transfer, let the irq schedule us again */
+	serial->bulk_in_inuse = 0;
+	return (0);
+}
+
+
+static int serial_write_irq (int state, void *buffer, int count, void *dev_id)
+{
+	struct usb_serial_state *serial = (struct usb_serial_state *) dev_id; 
+       	struct tty_struct *tty = serial->tty; 
+
+	debug_info("USB Serial: serial_write_irq\n");
+
+	if (!serial->bulk_out_inuse) {
+		debug_info("USB Serial: write irq for a finished pipe?\n");
+		return (0);
+		}
+
+	usb_terminate_bulk (serial->dev, serial->bulk_out_transfer);
+	serial->bulk_out_inuse = 0;
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+	
+	return 0;
+}
+
+
+static int usb_serial_irq (int state, void *buffer, int len, void *dev_id)
+{
+//	struct usb_serial_state *serial = (struct usb_serial_state *) dev_id;
+
+	debug_info("USB Serial: usb_serial_irq\n");
+
+	/* ask for a bulk read */
+//	serial->bulk_in_inuse = 1;
+//	serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
+
+	return (1);
+}
+
+
+
+
+
+/* tty interface functions */
+static int serial_open (struct tty_struct *tty, struct file * filp)
+{
+	struct usb_serial_state *serial;
+	
+	debug_info("USB: serial_open\n");
+
+	serial = &serial_state_table [MINOR(tty->device)-tty->driver.minor_start];
+	tty->driver_data = serial;
+	serial->tty = tty;
+	 
+	if (!serial->present) {
+		debug_info("USB Serial: no device registered\n");
+		return -EINVAL;
+	}
+
+	if (serial->active) {
+		debug_info ("USB Serial: device already open\n");
+		return -EINVAL;
+	}
+	serial->active = 1;
+ 
+	/*Start reading from the device*/
+	serial->bulk_in_inuse = 1;
+	serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
+
+	/* Need to do device specific setup here (control lines, baud rate, etc.) */
+	/* FIXME!!! */
+				                  
+	return (0);
+}
+
+
+static void serial_close(struct tty_struct *tty, struct file * filp)
+{
+	struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+	debug_info("USB: serial_close\n");
+	
+	if (!serial->present) {
+		debug_info("USB Serial: no device registered\n");
+		return;
+	}
+
+	if (!serial->active) {
+		debug_info ("USB Serial: device already open\n");
+		return;
+	}
+
+	/* Need to change the control lines here */
+	/* FIXME */
+	
+	if (serial->bulk_out_inuse){
+		usb_terminate_bulk (serial->dev, serial->bulk_out_transfer);
+		serial->bulk_out_inuse = 0;
+	}
+	if (serial->bulk_in_inuse){
+		usb_terminate_bulk (serial->dev, serial->bulk_in_transfer);
+		serial->bulk_in_inuse = 0;
+	}
+
+	/* release the irq? */
+	
+	serial->active = 0;
+}
+
+
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+	int written;
+	
+	debug_info("USB Serial: serial_write\n");
+
+	if (!serial->present) {
+		debug_info("USB Serial: device not registered\n");
+		return (-EINVAL);
+	}
+
+	if (!serial->active) {
+		debug_info ("USB Serial: device not opened\n");
+		return (-EINVAL);
+	}
+	
+	if (serial->bulk_out_inuse) {
+		debug_info ("USB Serial: already writing\n");
+		return (0);
+	}
+
+	written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count;
+	  
+	if (from_user) {
+		copy_from_user(serial->bulk_out_buffer, buf, written);
+	}
+	else {
+		memcpy (serial->bulk_out_buffer, buf, written);
+	}  
+
+	/* send the data out the bulk port */
+	serial->bulk_out_inuse = 1;
+	serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial);
+
+	return (written);
+} 
+
+
+static void serial_put_char (struct tty_struct *tty, unsigned char ch)
+{
+	struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; 
+	
+	debug_info("USB Serial: serial_put_char\n");
+	
+	if (!serial->present) {
+		debug_info("USB Serial: no device registered\n");
+		return;
+	}
+
+	if (!serial->active) {
+		debug_info ("USB Serial: device not open\n");
+		return;
+	}
+
+	if (serial->bulk_out_inuse) {
+		debug_info ("USB Serial: already writing\n");
+		return;
+	}
+
+	/* send the single character out the bulk port */
+	serial->bulk_out_buffer[0] = ch;
+	serial->bulk_out_inuse = 1;
+	serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial);
+
+	return;
+}                   
+
+
+static int serial_write_room (struct tty_struct *tty) 
+{
+	struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; 
+
+	debug_info("USB Serial: serial_write_room\n");
+	
+	if (!serial->present) {
+		debug_info("USB Serial: no device registered\n");
+		return (-EINVAL);
+	}
+
+	if (!serial->active) {
+		debug_info ("USB Serial: device not open\n");
+		return (-EINVAL);
+	}
+	
+	if (serial->bulk_out_inuse) {
+		return (0);
+	}
+
+	return serial->bulk_out_size;
+}
+
+
+static int serial_chars_in_buffer (struct tty_struct *tty) 
+{
+	struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; 
+
+	debug_info("USB Serial: serial_chars_in_buffer\n");
+	
+	if (!serial->present) {
+		debug_info("USB Serial: no device registered\n");
+		return (-EINVAL);
+	}
+
+	if (!serial->active) {
+		debug_info ("USB Serial: device not open\n");
+		return (-EINVAL);
+	}
+	
+	if (serial->bulk_out_inuse) {
+		return (serial->bulk_out_size);
+	}
+
+	return (0);
+}
+
+
+static void serial_throttle (struct tty_struct * tty)
+{
+	struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+
+	debug_info("USB Serial: serial_throttle\n");
+	
+	if (!serial->present) {
+		debug_info("USB Serial: no device registered\n");
+		return;
+	}
+
+	if (!serial->active) {
+		debug_info ("USB Serial: device not open\n");
+		return;
+	}
+
+
+	/* Change the control signals */
+	/* FIXME!!! */
+
+	return;
+}
+
+
+static void serial_unthrottle (struct tty_struct * tty)
+{
+	struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+
+	debug_info("USB Serial: serial_unthrottle\n");
+	
+	if (!serial->present) {
+		debug_info("USB Serial: no device registered\n");
+		return;
+	}
+
+	if (!serial->active) {
+		debug_info ("USB Serial: device not open\n");
+		return;
+	}
+
+
+	/* Change the control signals */
+	/* FIXME!!! */
+
+	return;
+}
+
+
+static int Get_Free_Serial (void)
+{
+	int i;
+ 
+	for (i=0; i < NUM_PORTS; ++i) {
+		if (!serial_state_table[i].present)
+			return (i);
+	}
+	return (-1);
+}
+
+
+static int usb_serial_probe(struct usb_device *dev)
+{
+	struct usb_serial_state *serial;
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	SERIAL_TYPE type;
+	int serial_num;
+//	int ret;
+	int i;
+	
+	/* look at the device descriptor to see if it is a type that we	recognize */
+	type = unknown;
+	if ((dev->descriptor.idVendor == BELKIN_VENDOR_ID) &&
+	    (dev->descriptor.idProduct == BELKIN_SERIAL_CONVERTER)) {
+		/* This is the Belkin serial convertor */
+		type = Belkin;
+		}
+	
+	if ((dev->descriptor.idVendor == PERACOM_VENDOR_ID) &&
+	    (dev->descriptor.idProduct == PERACOM_SERIAL_CONVERTER)) {
+		/* This is the Peracom serial convertor */
+		type = Peracom;
+		}
+
+	if (type == unknown)
+		return (-1);	
+
+	printk (KERN_INFO "USB serial converter detected.\n");
+
+	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+		printk (KERN_INFO " Failed usb_set_configuration: serial\n");
+		return (-1);
+	}
+
+	if (0>(serial_num = Get_Free_Serial())) {
+		debug_info("USB Serial: Too many devices connected\n");
+		return (-1);
+	}
+	
+	serial = &serial_state_table[serial_num];
+
+       	memset(serial, 0, sizeof(serial));
+       	serial->dev = dev;
+	serial->type = type;
+       	dev->private = serial;
+
+	/* we should have 1 bulk in, 1 bulk out, and 1 interrupt in endpoints */
+	interface = &dev->config[0].interface[0].altsetting[0];
+	for (i = 0; i < interface->bNumEndpoints; ++i) {
+		endpoint = &interface->endpoint[i];
+		
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found the bulk in endpoint */
+			serial->bulk_in_inuse = 0;
+			serial->bulk_in_endpoint = endpoint->bEndpointAddress;
+			serial->bulk_in_size = endpoint->wMaxPacketSize;
+			serial->bulk_in_interval = endpoint->bInterval;
+			serial->bulk_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint);
+			serial->bulk_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL);
+			if (!serial->bulk_in_buffer) {
+				printk("USB Serial: Couldn't allocate bulk_in_buffer\n");
+				goto probe_error;
+			}
+		}
+
+		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found the bulk out endpoint */
+			serial->bulk_out_inuse = 0;
+			serial->bulk_out_endpoint = endpoint->bEndpointAddress;
+			serial->bulk_out_size = endpoint->wMaxPacketSize;
+			serial->bulk_out_interval = endpoint->bInterval;
+			serial->bulk_out_pipe = usb_rcvbulkpipe (dev, serial->bulk_out_endpoint);
+			serial->bulk_out_buffer = kmalloc (serial->bulk_out_size, GFP_KERNEL);
+			if (!serial->bulk_out_buffer) {
+				printk("USB Serial: Couldn't allocate bulk_out_buffer\n");
+				goto probe_error;
+			}
+		}
+		
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x03)) {
+			/* we found the interrupt in endpoint */
+			serial->interrupt_in_inuse = 0;
+			serial->interrupt_in_endpoint = endpoint->bEndpointAddress;
+			serial->interrupt_in_size = endpoint->wMaxPacketSize;
+			serial->interrupt_in_interval = endpoint->bInterval;
+			/* serial->interrupt_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint); */
+			serial->interrupt_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL);
+			if (!serial->bulk_in_buffer) {
+				printk("USB Serial: Couldn't allocate interrupt_in_buffer\n");
+				goto probe_error;
+			}
+		}
+
+	}
+	
+
+	/* verify that we found all of the endpoints that we need */
+	if ((!serial->bulk_in_buffer) || 
+	    (!serial->bulk_out_buffer) ||
+	    (!serial->interrupt_in_buffer)) {
+		printk("USB Serial: did not find all of the required endpoints\n");
+		goto probe_error;
+	}
+		
+
+	/* set up an interrupt for out bulk in pipe */
+	/* ask for a bulk read */
+//	serial->bulk_in_inuse = 1;
+//	serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
+
+	/* set up our interrupt to be the time for the bulk in read */
+//	ret = usb_request_irq (dev, serial->bulk_in_pipe, usb_serial_irq, serial->bulk_in_interval, serial, &serial->irq_handle);
+//	if (ret) {
+//		printk(KERN_INFO "USB Serial failed usb_request_irq (0x%x)\n", ret);
+//		goto probe_error;
+//	}
+	
+	serial->present = 1;
+	MOD_INC_USE_COUNT;
+
+	return (0);
+
+probe_error:
+	if (serial) {
+		if (serial->bulk_in_buffer)
+			kfree (serial->bulk_in_buffer);
+		if (serial->bulk_out_buffer)
+			kfree (serial->bulk_out_buffer);
+		if (serial->interrupt_in_buffer)
+			kfree (serial->interrupt_in_buffer);
+	}
+	return (-1);
+}
+
+
+static void usb_serial_disconnect(struct usb_device *dev)
+{
+	struct usb_serial_state *serial = (struct usb_serial_state *)dev->private;
+
+	if (serial) {
+		if (!serial->present) {
+			/* something strange is going on */
+			debug_info("USB Serial: disconnect but not present?\n")
+			return;
+			}
+
+		/* need to stop any transfers...*/
+		if (serial->bulk_in_inuse) {
+			usb_terminate_bulk (serial->dev, serial->bulk_in_transfer);
+			serial->bulk_in_inuse = 0;
+		}
+		if (serial->bulk_out_inuse) {
+			usb_terminate_bulk (serial->dev, serial->bulk_out_transfer);
+			serial->bulk_out_inuse = 0;
+		}
+		// usb_release_irq (serial->dev, serial->irq_handle, serial->bulk_in_pipe);
+		if (serial->bulk_in_buffer)
+			kfree (serial->bulk_in_buffer);
+		if (serial->bulk_out_buffer)
+			kfree (serial->bulk_out_buffer);
+		if (serial->interrupt_in_buffer)
+			kfree (serial->interrupt_in_buffer);
+
+		serial->present = 0;
+		serial->active = 0;
+	}
+       	dev->private = NULL;
+	
+	MOD_DEC_USE_COUNT;
+
+	printk (KERN_INFO "USB Serial device disconnected.\n");
+}
+
+
+
+int usb_serial_init(void)
+{
+	int i;
+
+	/* Initalize our global data */
+	for (i = 0; i < NUM_PORTS; ++i) {
+		memset(&serial_state_table[i], 0x00, sizeof(struct usb_serial_state));
+	}
+
+	/* register the tty driver */
+	memset (&serial_tty_driver, 0, sizeof(struct tty_driver));
+	serial_tty_driver.magic			= TTY_DRIVER_MAGIC;
+	serial_tty_driver.driver_name		= "usb";
+	serial_tty_driver.name			= "ttyUSB";
+	serial_tty_driver.major			= SERIAL_MAJOR;
+	serial_tty_driver.minor_start		= 0;
+	serial_tty_driver.num			= NUM_PORTS;
+	serial_tty_driver.type			= TTY_DRIVER_TYPE_SERIAL;
+	serial_tty_driver.subtype		= SERIAL_TYPE_NORMAL;
+	serial_tty_driver.init_termios		= tty_std_termios;
+	serial_tty_driver.init_termios.c_cflag	= B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	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.put_char		= serial_put_char;
+	serial_tty_driver.flush_chars		= NULL; //serial_flush_chars;
+	serial_tty_driver.write_room		= serial_write_room;
+	serial_tty_driver.ioctl			= NULL; //serial_ioctl;
+	serial_tty_driver.set_termios		= NULL; //serial_set_termios;
+	serial_tty_driver.set_ldisc		= NULL; 
+	serial_tty_driver.throttle		= serial_throttle;
+	serial_tty_driver.unthrottle		= serial_unthrottle;
+	serial_tty_driver.stop			= NULL; //serial_stop;
+	serial_tty_driver.start			= NULL; //serial_start;
+	serial_tty_driver.hangup		= NULL; //serial_hangup;
+	serial_tty_driver.break_ctl		= NULL; //serial_break;
+	serial_tty_driver.wait_until_sent	= NULL; //serial_wait_until_sent;
+	serial_tty_driver.send_xchar		= NULL; //serial_send_xchar;
+	serial_tty_driver.read_proc		= NULL; //serial_read_proc;
+	serial_tty_driver.chars_in_buffer	= serial_chars_in_buffer;
+	serial_tty_driver.flush_buffer		= NULL; //serial_flush_buffer;
+	if (tty_register_driver (&serial_tty_driver)) {
+		printk( "USB Serial: failed to register tty driver\n" );
+		return -EPERM;
+	}
+	
+	/* register the USB driver */
+	usb_register(&usb_serial_driver);
+	printk(KERN_INFO "USB Serial support registered.\n");
+	return 0;
+}
+
+
+#ifdef MODULE
+int init_module(void)
+{
+	return usb_serial_init();
+}
+
+void cleanup_module(void)
+{
+	tty_unregister_driver(&serial_tty_driver);
+	usb_deregister(&usb_serial_driver);
+}
+
+#endif
+
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.19/linux/drivers/usb/uhci.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/uhci.c	Thu Oct  7 10:17:09 1999
@@ -126,7 +126,7 @@
 {
 	unsigned int status;
 	struct uhci_td *tmp;
-	int count = 1000;
+	int count = 1000, bytesreceived = 0;
 
 	if (rval)
 		*rval = 0;
@@ -144,8 +144,10 @@
 	do {
 		status = uhci_status_bits(tmp->status);
 
-		if (status) {
-			if (debug) {
+		if (status)
+			break;
+#if 0
+		if (debug) {
 				/* Must reset the toggle on first error */
     				if (uhci_debug) {
 					printk(KERN_DEBUG "Set toggle from %x rval %ld\n",
@@ -161,6 +163,13 @@
 			if (rval && ((tmp->info & 0xFF) == USB_PID_IN))
 				*rval += uhci_actual_length(tmp->status);
 		}
+#endif
+		/* The length field is only valid if the TD was completed */
+		if (!(tmp->status & TD_CTRL_ACTIVE) && uhci_packetin(tmp->info)) {
+			bytesreceived += uhci_actual_length(tmp->status);
+			if (rval)
+				*rval += uhci_actual_length(tmp->status);
+		}
 
 		if ((tmp->link & UHCI_PTR_TERM) ||
 		    (tmp->link & UHCI_PTR_QH))
@@ -173,8 +182,35 @@
 		printk(KERN_ERR "runaway td's in uhci_td_result!\n");
 		/* Force debugging on */
 		debug = 1;
-	} else if (!status)
-    		return USB_ST_NOERROR;
+	} else {
+		/* If we got to the last TD */
+
+		/* No error */
+		if (!status)
+			return USB_ST_NOERROR;
+
+		/* APC BackUPS Pro kludge */
+		/* It tries to send all of the descriptor instead of */
+		/*  the amount we requested */
+		if (tmp->status & TD_CTRL_IOC &&
+		    tmp->status & TD_CTRL_ACTIVE &&
+		    tmp->status & TD_CTRL_NAK)
+			return USB_ST_NOERROR;
+
+#if 0
+		/* We got to an error, but the controller hasn't finished */
+		/*  with it, yet */
+		if (tmp->status & TD_CTRL_ACTIVE)
+			return USB_ST_NOCHANGE;
+#endif
+
+		/* If this wasn't the last TD and SPD is set, ACTIVE */
+		/*  is not and NAK isn't then we received a short */
+		/*  packet */
+		if (tmp->status & TD_CTRL_SPD &&
+		    !(tmp->status & TD_CTRL_NAK))
+			return USB_ST_NOERROR;
+	}
 
 	/* Some debugging code */
 	if (debug && uhci_debug) {
@@ -1035,7 +1071,7 @@
 }
 
 /* td points to the last td in the list, which interrupts on completion */
-static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last)
+static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last, int timeout)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct uhci_qh *qh = uhci_qh_alloc(dev);
@@ -1053,7 +1089,8 @@
 	/* Add it into the skeleton */
 	uhci_insert_qh(&dev->uhci->skel_control_qh, qh);
 
-	schedule_timeout(HZ * 5);	/* 5 seconds */
+	/* wait a user specified reasonable amount of time */
+	schedule_timeout(timeout);
 
 	remove_wait_queue(&qh->wakeup, &wait);
 
@@ -1094,7 +1131,7 @@
  * there is no restriction on length of transfers
  * anymore
  */
-static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len)
+static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len, int timeout)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
 	struct uhci_td *first, *td, *prevtd;
@@ -1184,7 +1221,7 @@
 	td->link = UHCI_PTR_TERM;			/* Terminate */
 
 	/* Start it up.. */
-	ret = uhci_run_control(dev, first, td);
+	ret = uhci_run_control(dev, first, td, timeout);
 
 	count = 1000;
 	td = first;
@@ -1231,7 +1268,7 @@
  */
 
 /* td points to the last td in the list, which interrupts on completion */
-static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last, unsigned long *rval)
+static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last, unsigned long *rval, int timeout)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct uhci_qh *qh = uhci_qh_alloc(dev);
@@ -1249,7 +1286,8 @@
 	/* Add it into the skeleton */
 	uhci_insert_qh(&dev->uhci->skel_bulk_qh, qh);
 
-	schedule_timeout(HZ * 5);	/* 5 seconds */
+	/* wait a user specified reasonable amount of time */
+	schedule_timeout(timeout);
 
 	remove_wait_queue(&qh->wakeup, &wait);
 
@@ -1272,7 +1310,7 @@
  * A bulk message is only built up from
  * the data phase
  */
-static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval)
+static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval, int timeout)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
 	struct uhci_td *first, *td, *prevtd;
@@ -1334,7 +1372,7 @@
 	/* CHANGE DIRECTION HERE! SAVE IT SOMEWHERE IN THE ENDPOINT!!! */
 
 	/* Start it up.. */
-	ret = uhci_run_bulk(dev, first, td, rval);
+	ret = uhci_run_bulk(dev, first, td, rval, timeout);
 
 	{
 		int count = 100;
@@ -1570,6 +1608,7 @@
 	} while (nr < maxchild);
 }
 
+#if 0
 static int fixup_isoc_desc (struct uhci_td *td)
 {
 	struct usb_isoc_desc    *isocdesc = td->dev_id;
@@ -1621,6 +1660,7 @@
 
 	return 0;
 }
+#endif /* 0 */
 
 static void uhci_interrupt_notify(struct uhci *uhci)
 {
@@ -2097,7 +2137,7 @@
 	for (i = 0; i < 6; i++) {
 		unsigned int io_addr = dev->resource[i].start;
 		unsigned int io_size =
-			dev->resource[i].end - dev->resource[i].start;
+			dev->resource[i].end - dev->resource[i].start + 1;
 
 		/* IO address? */
 		if (!(dev->resource[i].flags & 1))
@@ -2106,6 +2146,9 @@
 		/* Is it already in use? */
 		if (check_region(io_addr, io_size))
 			break;
+
+                /* disable legacy emulation */
+                pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
 
 		return found_uhci(dev->irq, io_addr, io_size);
 	}
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.3.19/linux/drivers/usb/uhci.h	Tue Aug 31 17:29:14 1999
+++ linux/drivers/usb/uhci.h	Thu Oct  7 10:17:09 1999
@@ -53,6 +53,10 @@
 #define   USBPORTSC_PR		0x0200	/* Port Reset */
 #define   USBPORTSC_SUSP	0x1000	/* Suspend */
 
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
+
 #define UHCI_NULL_DATA_SIZE	0x7ff	/* for UHCI controller TD */
 
 #define UHCI_PTR_BITS		0x000F
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c
--- v2.3.19/linux/drivers/usb/usb-core.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/usb-core.c	Fri Oct  8 15:47:08 1999
@@ -2,16 +2,16 @@
  * driver/usb/usb-core.c
  *
  * (C) Copyright David Waite 1999
- * based on code from usb.c, by Linus Torvolds
+ * based on code from usb.c, by Linus Torvalds
  *
  * The purpose of this file is to pull any and all generic modular code from
  * usb.c and put it in a separate file. This way usb.c is kept as a generic
  * library, while this file handles starting drivers, etc.
  *
  */
+
 #include <linux/kernel.h>
 #include <linux/config.h>
-#include <linux/module.h>
 
 #include "inits.h"
 #include "usb.h"
@@ -28,9 +28,11 @@
 #	endif
 #endif
 
-
 int usb_init(void)
 {
+#ifdef CONFIG_USB_PROC
+	proc_usb_init ();
+#endif
 #ifndef CONFIG_USB_MODULE
 #	ifdef CONFIG_USB_UHCI
 		uhci_init();
@@ -59,6 +61,9 @@
 #	ifdef CONFIG_USB_PRINTER
 		usb_printer_init();
 #	endif
+#	ifdef CONFIG_USB_SERIAL
+		usb_serial_init();
+#	endif
 #	ifdef CONFIG_USB_CPIA
 		usb_cpia_init();
 #	endif
@@ -69,11 +74,9 @@
 		usb_scsi_init();
 #	endif
 #endif
-#ifdef CONFIG_USB_PROC
-	proc_usb_init ();
-#endif
 	return 0;
 }
+
 /*
  *  Clean up when unloading the module
  */
@@ -100,10 +103,9 @@
 {
 	return usb_init();
 }
+
 void cleanup_module(void)
 {
 	cleanup_drivers();
 }
 #endif
-
-
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.19/linux/drivers/usb/usb.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/usb.c	Fri Oct  8 15:47:08 1999
@@ -13,15 +13,25 @@
  * are evil.
  */
 
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+
 #define USB_DEBUG	1
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
 #include <linux/malloc.h>
 
 #include "usb.h"
 
+static int usb_find_driver(struct usb_device *);
+static void usb_check_support(struct usb_device *);
+static void usb_driver_purge(struct usb_driver *, struct usb_device *);
+
+
 /*
  * We have a per-interface "registered driver" list.
  */
@@ -172,14 +182,15 @@
  * However, this first cut at USB bandwidth allocation does not
  * contain any frame allocation tracking.
  */
-int check_bandwidth_alloc (unsigned int old_alloc, long bustime)
+static int check_bandwidth_alloc (unsigned int old_alloc, long bustime)
 {
 	unsigned int	new_alloc;
 
 	new_alloc = old_alloc + bustime;
 		/* what new total allocated bus time would be */
 
-	PRINTD ("usb-bandwidth-alloc: was: %ld, new: %ld, bustime = %ld us, Pipe allowed: %s",
+	PRINTD ("usb-bandwidth-alloc: was: %u, new: %u, "
+		"bustime = %ld us, Pipe allowed: %s",
 		old_alloc, new_alloc, bustime,
 		(new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ?
 			"yes" : "no");
@@ -263,6 +274,7 @@
 	if (!dev->driver && dev->devnum > 0)
 		usb_find_driver(dev);
 }
+
 /*
  * This entrypoint gets called for each new device.
  *
@@ -318,7 +330,6 @@
 {
 	if (atomic_dec_and_test(&dev->refcnt)) {
 		usb_destroy_configuration(dev);
-
 		dev->bus->op->deallocate(dev);
 		kfree(dev);
 	}
@@ -681,7 +692,7 @@
 	dr.index = 0;
 	dr.length = 0;
 
-	return dev->bus->op->control_msg(dev, usb_snddefctrl(dev), &dr, NULL, 0);
+	return dev->bus->op->control_msg(dev, usb_snddefctrl(dev), &dr, NULL, 0, HZ);
 }
 
 int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
@@ -697,7 +708,7 @@
 	dr.length = size;
 
 	while (i--) {
-		if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size))
+		if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size, HZ))
 		    || result == USB_ST_STALL)
 			break;
 	}
@@ -714,7 +725,7 @@
 	dr.index = langid;
 	dr.length = size;
 
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size);
+	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size, HZ);
 }
 
 int usb_get_device_descriptor(struct usb_device *dev)
@@ -740,7 +751,7 @@
 	dr.index = target;
 	dr.length = 2;
 
-	return dev->bus->op->control_msg (dev, usb_rcvctrlpipe (dev,0), &dr, data, 2);
+	return dev->bus->op->control_msg (dev, usb_rcvctrlpipe (dev,0), &dr, data, 2, HZ);
 }
 
 int usb_get_protocol(struct usb_device *dev)
@@ -754,7 +765,7 @@
 	dr.index = 1;
 	dr.length = 1;
 
-	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 1))
+	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 1, HZ))
 		return -1;
 
 	return buf[0];
@@ -770,7 +781,7 @@
 	dr.index = 1;
 	dr.length = 0;
 
-	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
 		return -1;
 
 	return 0;
@@ -788,7 +799,7 @@
 	dr.index = 1;
 	dr.length = 0;
 
-	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
 		return -1;
 
 	return 0;
@@ -838,7 +849,7 @@
 	dr.index = endp;
 	dr.length = 0;
 
-	result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0, HZ);
 
 	/* don't clear if failed */
 	if (result)
@@ -850,7 +861,7 @@
 	dr.length = 2;
 	status = 0xffff;
 
-	result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 2);
+	result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 2, HZ);
 
 	if (result)
 	    return result;
@@ -876,7 +887,7 @@
 	dr.index = interface;
 	dr.length = 0;
 
-	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
 		return -1;
 
 	dev->ifnum = interface;
@@ -907,7 +918,7 @@
 		printk(KERN_INFO "usb: selecting invalid configuration %d\n", configuration);
 		return -1;
 	}
-	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
 		return -1;
 
 	dev->actconfig = cp;
@@ -927,7 +938,7 @@
 	dr.index = index;
 	dr.length = size;
 
-	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size))
+	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size, HZ))
 		return -1;
 
 	return 0;
@@ -962,9 +973,9 @@
 		/* We grab the first 8 bytes so we know how long the whole */
 		/*  configuration is */
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
-		if (result)
+		if (result < 0)
 	    		return -1;
-
+		
   	  	/* Get the full buffer */
 		le16_to_cpus(&desc->wTotalLength);
 
@@ -991,7 +1002,6 @@
 	return 0;
 }
 
-
 char *usb_string(struct usb_device *dev, int index)
 {
 	int len, i;
@@ -1115,7 +1125,7 @@
 	return 0;
 }
 
-int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size)
+int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout)
 {
         devrequest dr;
 
@@ -1125,7 +1135,7 @@
         dr.index = cpu_to_le16p(&index);
         dr.length = cpu_to_le16p(&size);
 
-        return dev->bus->op->control_msg(dev, pipe, &dr, data, size);
+        return dev->bus->op->control_msg(dev, pipe, &dr, data, size, timeout);
 }
 
 int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle)
@@ -1148,9 +1158,10 @@
 	if (!ret) {
 		dev->bus->bandwidth_allocated += bustime;
 		dev->bus->bandwidth_int_reqs++;
-		PRINTD ("bw_alloc bumped to %d for %d requesters\n",
+		PRINTD ("bw_alloc bumped to %d for %d requesters",
 			dev->bus->bandwidth_allocated,
-			dev->bus->bandwidth_int_reqs);
+			dev->bus->bandwidth_int_reqs +
+			dev->bus->bandwidth_isoc_reqs);
 	}
 
 	return ret;
@@ -1180,9 +1191,10 @@
 		bustime = NS_TO_US(bustime);
 		dev->bus->bandwidth_allocated -= bustime;
 		dev->bus->bandwidth_int_reqs--;
-		PRINTD ("bw_alloc reduced to %d for %d requesters\n",
+		PRINTD ("bw_alloc reduced to %d for %d requesters",
 			dev->bus->bandwidth_allocated,
-			dev->bus->bandwidth_int_reqs);
+			dev->bus->bandwidth_int_reqs +
+			dev->bus->bandwidth_isoc_reqs);
 	}
 
 	return err;
@@ -1208,11 +1220,14 @@
 	long    bustime;
 	int	err;
 
+	if (frame_count <= 0)
+		return -EINVAL;
+
 	/* Check host controller's bandwidth for this Isoc. request. */
 	/* TBD: some way to factor in frame_spacing ??? */
 	bustime = calc_bus_time (0, usb_pipein(pipe), 1,
 			usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)));
-	bustime = NS_TO_US(bustime);	/* work in microseconds */
+	bustime = NS_TO_US(bustime) / frame_count;	/* work in microseconds */
 	if (check_bandwidth_alloc (usb_dev->bus->bandwidth_allocated, bustime))
 		return USB_ST_BANDWIDTH_ERROR;
 
@@ -1222,8 +1237,9 @@
 	if (!err) {
 		usb_dev->bus->bandwidth_allocated += bustime;
 		usb_dev->bus->bandwidth_isoc_reqs++;
-		PRINTD ("bw_alloc bumped to %d for %d requesters\n",
+		PRINTD ("bw_alloc bumped to %d for %d requesters",
 			usb_dev->bus->bandwidth_allocated,
+			usb_dev->bus->bandwidth_int_reqs +
 			usb_dev->bus->bandwidth_isoc_reqs);
 	}
 
@@ -1238,11 +1254,12 @@
 	bustime = calc_bus_time (0, usb_pipein(isocdesc->pipe), 1,
 			usb_maxpacket(isocdesc->usb_dev, isocdesc->pipe,
 			usb_pipeout(isocdesc->pipe)));
-	bustime = NS_TO_US(bustime);
+	bustime = NS_TO_US(bustime) / isocdesc->frame_count;
 	isocdesc->usb_dev->bus->bandwidth_allocated -= bustime;
 	isocdesc->usb_dev->bus->bandwidth_isoc_reqs--;
-	PRINTD ("bw_alloc reduced to %d for %d requesters\n",
+	PRINTD ("bw_alloc reduced to %d for %d requesters",
 		isocdesc->usb_dev->bus->bandwidth_allocated,
+		isocdesc->usb_dev->bus->bandwidth_int_reqs +
 		isocdesc->usb_dev->bus->bandwidth_isoc_reqs);
 
 	isocdesc->usb_dev->bus->op->free_isoc (isocdesc);
@@ -1271,3 +1288,49 @@
 }
 #endif
 
+/*
+ * USB may be built into the kernel or be built as modules.
+ * If the USB core [and maybe a host controller driver] is built
+ * into the kernel, and other device drivers are built as modules,
+ * then these symbols need to be exported for the modules to use.
+ */
+EXPORT_SYMBOL(usb_register);
+EXPORT_SYMBOL(usb_deregister);
+EXPORT_SYMBOL(usb_alloc_bus);
+EXPORT_SYMBOL(usb_free_bus);
+EXPORT_SYMBOL(usb_register_bus);
+EXPORT_SYMBOL(usb_deregister_bus);
+EXPORT_SYMBOL(usb_alloc_dev);
+EXPORT_SYMBOL(usb_free_dev);
+EXPORT_SYMBOL(usb_inc_dev_use);
+
+EXPORT_SYMBOL(usb_init_root_hub);
+EXPORT_SYMBOL(usb_new_device);
+EXPORT_SYMBOL(usb_connect);
+EXPORT_SYMBOL(usb_disconnect);
+
+EXPORT_SYMBOL(usb_set_address);
+EXPORT_SYMBOL(usb_get_descriptor);
+EXPORT_SYMBOL(usb_get_string);
+EXPORT_SYMBOL(usb_string);
+EXPORT_SYMBOL(usb_get_protocol);
+EXPORT_SYMBOL(usb_set_protocol);
+EXPORT_SYMBOL(usb_get_report);
+EXPORT_SYMBOL(usb_set_idle);
+EXPORT_SYMBOL(usb_clear_halt);
+EXPORT_SYMBOL(usb_set_interface);
+EXPORT_SYMBOL(usb_get_configuration);
+EXPORT_SYMBOL(usb_set_configuration);
+
+EXPORT_SYMBOL(usb_control_msg);
+EXPORT_SYMBOL(usb_request_irq);
+EXPORT_SYMBOL(usb_release_irq);
+/* EXPORT_SYMBOL(usb_bulk_msg); */
+EXPORT_SYMBOL(usb_request_bulk);
+EXPORT_SYMBOL(usb_terminate_bulk);
+
+EXPORT_SYMBOL(usb_get_current_frame_number);
+EXPORT_SYMBOL(usb_init_isoc);
+EXPORT_SYMBOL(usb_free_isoc);
+EXPORT_SYMBOL(usb_run_isoc);
+EXPORT_SYMBOL(usb_kill_isoc);
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.19/linux/drivers/usb/usb.h	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/usb.h	Fri Oct  8 15:47:08 1999
@@ -49,6 +49,15 @@
 #define USB_DIR_OUT			0
 #define USB_DIR_IN			0x80
 
+#define USB_ENDPOINT_NUMBER_MASK	0x0f	/* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK		0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK	0x03	/* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL	0
+#define USB_ENDPOINT_XFER_ISOC		1
+#define USB_ENDPOINT_XFER_BULK		2
+#define USB_ENDPOINT_XFER_INT		3
+
 /*
  * USB Packet IDs (PIDs)
  */
@@ -117,29 +126,44 @@
 	__u16 value;
 	__u16 index;
 	__u16 length;
-        /* pointer to data */
+	__u32 timeout;  /* in milliseconds */
         void *data;
 };
 
-#define USB_PROC_CONTROL           _IOWR('U', 0, struct usb_proc_ctrltransfer)
-
 struct usb_proc_bulktransfer {
         unsigned int ep;
         unsigned int len;
+	unsigned int timeout; /* in milliseconds */
         void *data;
 };
 
-#define USB_PROC_BULK              _IOWR('U', 2, struct usb_proc_bulktransfer)
+struct usb_proc_old_ctrltransfer {
+	__u8 requesttype;
+	__u8 request;
+	__u16 value;
+	__u16 index;
+	__u16 length;
+        /* pointer to data */
+        void *data;
+};
 
-#define USB_PROC_RESETEP           _IOR('U', 3, unsigned int)
+struct usb_proc_old_bulktransfer {
+        unsigned int ep;
+        unsigned int len;
+        void *data;
+};
 
 struct usb_proc_setinterface {
         unsigned int interface;
         unsigned int altsetting;
 };
 
+#define USB_PROC_CONTROL           _IOWR('U', 0, struct usb_proc_ctrltransfer)
+#define USB_PROC_BULK              _IOWR('U', 2, struct usb_proc_bulktransfer)
+#define USB_PROC_OLD_CONTROL       _IOWR('U', 0, struct usb_proc_old_ctrltransfer)
+#define USB_PROC_OLD_BULK          _IOWR('U', 2, struct usb_proc_old_bulktransfer)
+#define USB_PROC_RESETEP           _IOR('U', 3, unsigned int)
 #define USB_PROC_SETINTERFACE      _IOR('U', 4, struct usb_proc_setinterface)
-
 #define USB_PROC_SETCONFIGURATION  _IOR('U', 5, unsigned int)
 
 
@@ -429,8 +453,8 @@
 struct usb_operations {
 	int (*allocate)(struct usb_device *);
 	int (*deallocate)(struct usb_device *);
-	int (*control_msg)(struct usb_device *, unsigned int, devrequest *, void *, int);
-	int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *);
+	int (*control_msg)(struct usb_device *, unsigned int, devrequest *, void *, int, int);
+	int (*bulk_msg)(struct usb_device *, unsigned int, void *, int, unsigned long *, int);
 	int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *, void **);
 	int (*release_irq)(struct usb_device *, void *);
 	void *(*request_bulk)(struct usb_device *, unsigned int, usb_device_irq,
@@ -496,7 +520,7 @@
   
 	void *hcpriv;			/* Host Controller private data */
 	void *private;			/* Upper layer private data */
-
+	void *audiopriv;		/* May be both audio and HID */
 	/* procfs entry */
 	struct proc_dir_entry *proc_entry;
 
@@ -515,10 +539,6 @@
 extern int usb_register(struct usb_driver *);
 extern void usb_deregister(struct usb_driver *);
 
-int usb_find_driver(struct usb_device *);
-void usb_check_support(struct usb_device *);
-void usb_driver_purge(struct usb_driver *, struct usb_device *);
-
 extern struct usb_bus *usb_alloc_bus(struct usb_operations *);
 extern void usb_free_bus(struct usb_bus *);
 extern void usb_register_bus(struct usb_bus *);
@@ -529,7 +549,7 @@
 extern void usb_inc_dev_use(struct usb_device *);
 #define usb_dec_dev_use usb_free_dev
 
-extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size);
+extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
 
 extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *, void **);
 extern int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe);
@@ -695,7 +715,7 @@
 #ifdef USB_DEBUG
 #define PRINTD(format, args...) printk("usb: " format "\n" , ## args);
 #else /* NOT DEBUGGING */
-#define PRINTD(fmt, arg...) do {} while (0) /**/
+#define PRINTD(fmt, arg...) do {} while (0)
 #endif /* USB_DEBUG */
 /* A simple way to change one line from DEBUG to NOT DEBUG: */
 #define XPRINTD(fmt, arg...)	do {} while (0)
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
--- v2.3.19/linux/drivers/usb/usb_scsi.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/usb_scsi.c	Thu Oct  7 10:17:09 1999
@@ -142,7 +142,7 @@
 	do {
 	    /*US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);*/
 	    result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, pipe, buf, 
-						    this_xfer, &partial);
+						    this_xfer, &partial, HZ*5);
 
 	    if (result != 0 || partial != this_xfer)
 		US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n",
@@ -263,7 +263,6 @@
 {
     unsigned char cmd[12];
     devrequest dr;
-    int result;
 
     US_DEBUGP("pop_CB_reset\n");
     dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE;
@@ -276,7 +275,7 @@
     cmd[1] = 4;
     us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
 					usb_sndctrlpipe(us->pusb_dev,0),
-					&dr, cmd, 12);
+					&dr, cmd, 12, HZ);
 
     /* long wait for reset */
 
@@ -338,7 +337,7 @@
 	    }
 	    result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
 						  usb_sndctrlpipe(us->pusb_dev,0),
-						  &dr, cmd, us->fixedlength);
+						  &dr, cmd, us->fixedlength, HZ);
 	    if (!done_start && (us->subclass == US_SC_UFI /*|| us->subclass == US_SC_8070*/)
 		 && cmd[0] == TEST_UNIT_READY && result) {
 		/* as per spec try a start command, wait and retry */
@@ -349,7 +348,7 @@
 		cmd[4] = 1;		/* start */
 		result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
 						      usb_sndctrlpipe(us->pusb_dev,0),
-						      &dr, cmd, us->fixedlength);
+						      &dr, cmd, us->fixedlength, HZ);
 		wait_ms(100);
 		retry++;
 		continue;
@@ -357,7 +356,7 @@
 	} else
 	    result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
 						  usb_sndctrlpipe(us->pusb_dev,0),
-						  &dr, srb->cmnd, srb->cmd_len);
+						  &dr, srb->cmnd, srb->cmd_len, HZ);
 	if (/*result != USB_ST_STALL &&*/ result != USB_ST_TIMEOUT)
 	    return result;
     }
@@ -389,7 +388,7 @@
 	    dr.length = 2;
 	    result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
 						  usb_rcvctrlpipe(us->pusb_dev,0),
-						  &dr, status, sizeof(status));
+						  &dr, status, sizeof(status), HZ);
 	    if (result != USB_ST_TIMEOUT)
 		break;
 	}
@@ -452,7 +451,6 @@
 
 static int pop_CBI(Scsi_Cmnd *srb)
 {
-    struct us_data *us = (struct us_data *)srb->host_scribble;
     int result;
 
     /* run the command */
@@ -500,7 +498,7 @@
     dr.index = 0;
     dr.length = 0;
 
-    result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), &dr, NULL, 0);
+    result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), &dr, NULL, 0, HZ);
     if (result)
 	US_DEBUGP("Bulk hard reset failed %d\n", result);
     usb_clear_halt(us->pusb_dev, us->ep_in | 0x80);
@@ -546,7 +544,7 @@
 	      bcb.Tag, bcb.DataTransferLength, bcb.Flags, bcb.Length);
     result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev,
 		     usb_sndbulkpipe(us->pusb_dev, us->ep_out), &bcb, 
-					    US_BULK_CB_WRAP_LEN, &partial);
+					    US_BULK_CB_WRAP_LEN, &partial, HZ*5);
     if (result) {
 	US_DEBUGP("Bulk command result %x\n", result);
 	return DID_ABORT << 16;
@@ -570,7 +568,7 @@
     do {
 	result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev,
 			 usb_rcvbulkpipe(us->pusb_dev, us->ep_in), &bcs, 
-						US_BULK_CS_WRAP_LEN, &partial);
+						US_BULK_CS_WRAP_LEN, &partial, HZ*5);
 	if (result == USB_ST_STALL || result == USB_ST_TIMEOUT)
 	    stall++;
 	else
@@ -1296,7 +1294,7 @@
 	    dr.index = 0;
 	    dr.value = 0;
 	    dr.length = 0;
-	    ss->pusb_dev->bus->op->control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), &dr, qstat, 2);
+	    ss->pusb_dev->bus->op->control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), &dr, qstat, 2, HZ);
 	    US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]);
 	    init_waitqueue_head(&ss->ip_waitq);
 	    ss->irqpipe = usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int);
@@ -1413,8 +1411,6 @@
 
 void cleanup_module(void)
 {
-	unsigned int offset;
-
 	usb_deregister(&scsi_driver);
 }
 #endif
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/usb_scsi_debug.c linux/drivers/usb/usb_scsi_debug.c
--- v2.3.19/linux/drivers/usb/usb_scsi_debug.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/usb_scsi_debug.c	Fri Oct  8 15:47:08 1999
@@ -5,7 +5,6 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/uss720.c linux/drivers/usb/uss720.c
--- v2.3.19/linux/drivers/usb/uss720.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/uss720.c	Thu Oct  7 10:17:09 1999
@@ -31,6 +31,7 @@
  *                  ECP currently untested
  *   0.3  10.08.99  fixing merge errors
  *   0.4  13.08.99  Added Vendor/Product ID of Brad Hard's cable
+ *   0.5  20.09.99  usb_control_msg wrapper used
  *
  */
 
@@ -61,17 +62,11 @@
 	static const unsigned char regindex[9] = {
 		4, 0, 1, 5, 5, 0, 2, 3, 6
 	};
-        devrequest dr;
         int ret;
 
 	if (!usbdev)
 		return -1;
-        dr.requesttype = 0xc0;
-        dr.request = 3;
-        dr.value = ((unsigned int)reg) << 8;
-        dr.index = 0;
-        dr.length = 7;
-        ret = usbdev->bus->op->control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), &dr, priv->reg, 7);
+        ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, HZ);
         if (ret) {
                 printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x\n",
 		       (unsigned int)reg, ret);
@@ -95,17 +90,11 @@
 {
 	struct parport_uss720_private *priv = pp->private_data;
 	struct usb_device *usbdev = priv->usbdev;
-        devrequest dr;
         int ret;
 
 	if (!usbdev)
 		return -1;
-        dr.requesttype = 0x40;
-        dr.request = 4;
-        dr.value = (((unsigned int)reg) << 8) | val;
-        dr.index = 0;
-        dr.length = 0;
-        ret = usbdev->bus->op->control_msg(usbdev, usb_sndctrlpipe(usbdev,0), &dr, NULL, 0);
+        ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, HZ);
         if (ret) {
                 printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n", 
 		       (unsigned int)reg, (unsigned int)val, ret);
@@ -374,7 +363,7 @@
 		return 0;
 	if (change_mode(pp, ECR_EPP))
 		return 0;
-	i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buf, length, &rlen);
+	i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buf, length, &rlen, HZ*20);
 	if (i)
 		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buf, length, rlen);
 	change_mode(pp, ECR_PS2);
@@ -435,7 +424,7 @@
 		return 0;
 	if (change_mode(pp, ECR_ECP))
 		return 0;
-	i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen);
+	i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen, HZ*20);
 	if (i)
 		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buffer, len, rlen);
 	change_mode(pp, ECR_PS2);
@@ -453,7 +442,7 @@
 		return 0;
 	if (change_mode(pp, ECR_ECP))
 		return 0;
-	i = usbdev->bus->op->bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen);
+	i = usbdev->bus->op->bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, HZ*20);
 	if (i)
 		printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %u rlen %lu\n", buffer, len, rlen);
 	change_mode(pp, ECR_PS2);
@@ -486,7 +475,7 @@
 		return 0;
 	if (change_mode(pp, ECR_PPF))
 		return 0;
-	i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen);
+	i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen, HZ*20);
 	if (i)
 		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buffer, len, rlen);
 	change_mode(pp, ECR_PS2);
diff -u --recursive --new-file v2.3.19/linux/fs/Config.in linux/fs/Config.in
--- v2.3.19/linux/fs/Config.in	Tue Sep  7 12:14:07 1999
+++ linux/fs/Config.in	Thu Oct  7 10:17:09 1999
@@ -59,6 +59,9 @@
 tristate 'ROM filesystem support' CONFIG_ROMFS_FS
 tristate 'Second extended fs support' CONFIG_EXT2_FS
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
+if [ "$CONFIG_SYSV_FS" != "n" -a "$CONFIG_EXPERIMENTAL" ]; then
+  bool '   SYSV filesystem write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE
+fi
 tristate 'UFS filesystem support' CONFIG_UFS_FS
 if [ "$CONFIG_UFS_FS" != "n" ]; then
   bool '   UFS filesystem write support (experimental)' CONFIG_UFS_FS_WRITE
diff -u --recursive --new-file v2.3.19/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.19/linux/fs/buffer.c	Tue Sep  7 12:14:07 1999
+++ linux/fs/buffer.c	Fri Oct  8 10:07:23 1999
@@ -1512,8 +1512,8 @@
 	char * target_buf, *target_data;
 	unsigned long data_offset = offset;
 
-	offset = page->offset-inode->i_size;
-	if (offset < 0) 
+	offset = inode->i_size - page->offset;
+	if (page->offset>inode->i_size)
 		offset = 0;
 	else if (offset >= data_offset)
 		offset = data_offset;
diff -u --recursive --new-file v2.3.19/linux/fs/dcache.c linux/fs/dcache.c
--- v2.3.19/linux/fs/dcache.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/dcache.c	Thu Oct  7 12:47:37 1999
@@ -42,7 +42,7 @@
  * This hash-function tries to avoid losing too many bits of hash
  * information, yet avoid using a prime hash-size or similar.
  */
-#define D_HASHBITS     10
+#define D_HASHBITS     14
 #define D_HASHSIZE     (1UL << D_HASHBITS)
 #define D_HASHMASK     (D_HASHSIZE-1)
 
@@ -196,72 +196,6 @@
 }
 
 /*
- * Select less valuable dentries to be pruned when we need
- * inodes or memory. The selected dentries are moved to the
- * old end of the list where prune_dcache() can find them.
- * 
- * Negative dentries are included in the selection so that
- * they don't accumulate at the end of the list. The count
- * returned is the total number of dentries selected, which
- * may be much larger than the requested number of inodes.
- */
-int select_dcache(int inode_count, int page_count)
-{
-	struct list_head *next, *tail = &dentry_unused;
-	int found = 0;
-	int depth = dentry_stat.nr_unused >> 1;
-	unsigned long max_value = 4;
-
-	if (page_count)
-		max_value = -1;
-
-	next = tail->prev;
-	while (next != &dentry_unused && depth--) {
-		struct list_head *tmp = next;
-		struct dentry *dentry = list_entry(tmp, struct dentry, d_lru);
-		struct inode *inode = dentry->d_inode;
-		unsigned long value = 0;	
-
-		next = tmp->prev;
-		if (dentry->d_count) {
-			dentry_stat.nr_unused--;
-			list_del(tmp);
-			INIT_LIST_HEAD(tmp);
-			continue;
-		}
-
-		/*
-		 * Select dentries based on the page cache count ...
-		 * should factor in number of uses as well. We take
-		 * all negative dentries so that they don't accumulate.
-		 * (We skip inodes that aren't immediately available.)
-		 */
-		if (inode) {
-			value = inode->i_nrpages;	
-			if (value >= max_value)
-				continue;
-			if (inode->i_state || inode->i_count > 1)
-				continue;
-		}
-
-		/*
-		 * Move the selected dentries behind the tail.
-		 */
-		if (tmp != tail->prev) {
-			list_del(tmp);
-			list_add(tmp, tail->prev);
-		}
-		tail = tmp;
-		found++;
-		if (inode && --inode_count <= 0)
-			break;
-		if (page_count && (page_count -= value) <= 0)
-			break;
-	}
-	return found;
-}
-
-/*
  * Throw away a dentry - free the inode, dput the parent.
  * This requires that the LRU list has already been
  * removed.
@@ -470,7 +404,7 @@
  *  ...
  *   6 - base-level: try to shrink a bit.
  */
-void shrink_dcache_memory(int priority, unsigned int gfp_mask)
+int shrink_dcache_memory(int priority, unsigned int gfp_mask)
 {
 	if (gfp_mask & __GFP_IO) {
 		int count = 0;
@@ -479,7 +413,15 @@
 			count = dentry_stat.nr_unused / priority;
 		prune_dcache(count);
 		unlock_kernel();
+		/* FIXME: kmem_cache_shrink here should tell us
+		   the number of pages freed, and it should
+		   work in a __GFP_DMA/__GFP_BIGMEM behaviour
+		   to free only the interesting pages in
+		   function of the needs of the current allocation. */
+		kmem_cache_shrink(dentry_cache);
 	}
+
+	return 0;
 }
 
 #define NAME_ALLOC_LEN(len)	((len+16) & ~15)
diff -u --recursive --new-file v2.3.19/linux/fs/dquot.c linux/fs/dquot.c
--- v2.3.19/linux/fs/dquot.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/dquot.c	Thu Oct  7 12:47:37 1999
@@ -516,11 +516,10 @@
 	/*
 	 * Try pruning the dcache to free up some dquots ...
 	 */
-	count = select_dcache(128, 0);
 	if (count) {
 		printk(KERN_DEBUG "get_empty_dquot: pruning %d\n", count);
 		prune_dcache(count);
-		free_inode_memory(count);
+		prune_icache(count);
 		goto repeat;
 	}
 
diff -u --recursive --new-file v2.3.19/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.3.19/linux/fs/fat/file.c	Mon Aug  9 11:43:49 1999
+++ linux/fs/fat/file.c	Fri Oct  8 10:07:23 1999
@@ -60,7 +60,7 @@
 	fat_get_block,		/* get_block */
 	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* flushpage */
+	block_flushpage,	/* flushpage */
 	fat_truncate,		/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
@@ -118,7 +118,7 @@
 	unsigned long page_cache = 0;
 	long status;
 
-	pgpos = inode->i_size & PAGE_CACHE_MASK;
+	pgpos = MSDOS_I(inode)->i_realsize & PAGE_CACHE_MASK;
 	while (pgpos < page->offset) {
 		hash = page_hash(inode, pgpos);
 repeat_find:	new_page = __find_lock_page(inode, pgpos, hash);
diff -u --recursive --new-file v2.3.19/linux/fs/inode.c linux/fs/inode.c
--- v2.3.19/linux/fs/inode.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/inode.c	Thu Oct  7 12:47:37 1999
@@ -10,6 +10,7 @@
 #include <linux/dcache.h>
 #include <linux/init.h>
 #include <linux/quotaops.h>
+#include <linux/slab.h>
 
 /*
  * New inode.c implementation.
@@ -21,6 +22,8 @@
  * Famous last words.
  */
 
+/* inode dynamic allocation 1999, Andrea Arcangeli <andrea@suse.de> */
+
 #define INODE_PARANOIA 1
 /* #define INODE_DEBUG 1 */
 
@@ -28,7 +31,7 @@
  * Inode lookup is no longer as critical as it used to be:
  * most of the lookups are going to be through the dcache.
  */
-#define HASH_BITS	8
+#define HASH_BITS	14
 #define HASH_SIZE	(1UL << HASH_BITS)
 #define HASH_MASK	(HASH_SIZE-1)
 
@@ -36,9 +39,9 @@
  * Each inode can be on two separate lists. One is
  * the hash list of the inode, used for lookups. The
  * other linked list is the "type" list:
- *  "in_use" - valid inode, hashed if i_nlink > 0
- *  "dirty"  - valid inode, hashed if i_nlink > 0, dirty.
- *  "unused" - ready to be re-used. Not hashed.
+ *  "in_use" - valid inode, i_count > 0, i_nlink > 0
+ *  "dirty"  - as "in_use" but also dirty
+ *  "unused" - valid inode, i_count = 0
  *
  * A "dirty" list is maintained for each super block,
  * allowing for low-overhead inode sync() operations.
@@ -61,11 +64,36 @@
  */
 struct {
 	int nr_inodes;
-	int nr_free_inodes;
+	int nr_unused;
 	int dummy[5];
 } inodes_stat = {0, 0,};
 
-int max_inodes;
+static kmem_cache_t * inode_cachep;
+
+#define alloc_inode() \
+	 ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
+#define destroy_inode(inode) kmem_cache_free(inode_cachep, (inode))
+
+/*
+ * These are initializations that only need to be done
+ * once, because the fields are idempotent across use
+ * of the inode, so let the slab aware of that.
+ */
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct inode * inode = (struct inode *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+	{
+		memset(inode, 0, sizeof(*inode));
+		init_waitqueue_head(&inode->i_wait);
+		INIT_LIST_HEAD(&inode->i_hash);
+		INIT_LIST_HEAD(&inode->i_dentry);
+		sema_init(&inode->i_sem, 1);
+		spin_lock_init(&inode->i_shared_lock);
+	}
+}
 
 /*
  * Put the inode on the super block's dirty list.
@@ -118,20 +146,6 @@
 		__wait_on_inode(inode);
 }
 
-/*
- * These are initializations that only need to be done
- * once, because the fields are idempotent across use
- * of the inode..
- */
-static inline void init_once(struct inode * inode)
-{
-	memset(inode, 0, sizeof(*inode));
-	init_waitqueue_head(&inode->i_wait);
-	INIT_LIST_HEAD(&inode->i_hash);
-	INIT_LIST_HEAD(&inode->i_dentry);
-	sema_init(&inode->i_sem, 1);
-	spin_lock_init(&inode->i_shared_lock);
-}
 
 static inline void write_inode(struct inode *inode)
 {
@@ -147,7 +161,8 @@
 		spin_lock(&inode_lock);
 	} else {
 		list_del(&inode->i_list);
-		list_add(&inode->i_list, &inode_in_use);
+		list_add(&inode->i_list,
+			 inode->i_count ? &inode_in_use : &inode_unused);
 		/* Set I_LOCK, reset I_DIRTY */
 		inode->i_state ^= I_DIRTY | I_LOCK;
 		spin_unlock(&inode_lock);
@@ -233,6 +248,8 @@
 {
 	if (inode->i_nrpages)
 		BUG();
+	if (!(inode->i_state & I_FREEING))
+		BUG();
 	wait_on_inode(inode);
 	if (IS_QUOTAINIT(inode))
 		DQUOT_DROP(inode);
@@ -243,35 +260,24 @@
 }
 
 /*
- * Dispose-list gets a local list, so it doesn't need to
- * worry about list corruption. It releases the inode lock
- * while clearing the inodes.
+ * Dispose-list gets a local list with local inodes in it, so it doesn't
+ * need to worry about list corruption and SMP locks.
  */
 static void dispose_list(struct list_head * head)
 {
-	struct list_head *next;
-	int count = 0;
+	struct list_head * inode_entry;
+	struct inode * inode;
 
-	spin_unlock(&inode_lock);
-	next = head->next;
-	for (;;) {
-		struct list_head * tmp = next;
-		struct inode * inode;
+	while ((inode_entry = head->next) != head)
+	{
+		list_del(inode_entry);
 
-		next = next->next;
-		if (tmp == head)
-			break;
-		inode = list_entry(tmp, struct inode, i_list);
+		inode = list_entry(inode_entry, struct inode, i_list);
 		if (inode->i_nrpages)
 			truncate_inode_pages(inode, 0);
 		clear_inode(inode);
-		count++;
+		destroy_inode(inode);
 	}
-
-	/* Add them all to the unused list in one fell swoop */
-	spin_lock(&inode_lock);
-	list_splice(head, &inode_unused);
-	inodes_stat.nr_free_inodes += count;
 }
 
 /*
@@ -280,7 +286,7 @@
 static int invalidate_list(struct list_head *head, struct super_block * sb, struct list_head * dispose)
 {
 	struct list_head *next;
-	int busy = 0;
+	int busy = 0, count = 0;
 
 	next = head->next;
 	for (;;) {
@@ -299,10 +305,13 @@
 			list_del(&inode->i_list);
 			list_add(&inode->i_list, dispose);
 			inode->i_state |= I_FREEING;
+			count++;
 			continue;
 		}
 		busy = 1;
 	}
+	/* only unused inodes may be cached with i_count zero */
+	inodes_stat.nr_unused -= count;
 	return busy;
 }
 
@@ -320,10 +329,12 @@
 
 	spin_lock(&inode_lock);
 	busy = invalidate_list(&inode_in_use, sb, &throw_away);
+	busy |= invalidate_list(&inode_unused, sb, &throw_away);
 	busy |= invalidate_list(&sb->s_dirty, sb, &throw_away);
-	dispose_list(&throw_away);
 	spin_unlock(&inode_lock);
 
+	dispose_list(&throw_away);
+
 	return busy;
 }
 
@@ -339,155 +350,84 @@
  *      dispose_list.
  */
 #define CAN_UNUSE(inode) \
-	(((inode)->i_count | (inode)->i_state | (inode)->i_nrpages) == 0)
+	(((inode)->i_state | (inode)->i_nrpages) == 0)
 #define INODE(entry)	(list_entry(entry, struct inode, i_list))
 
-static int free_inodes(void)
+void prune_icache(int goal)
 {
-	struct list_head list, *entry, *freeable = &list;
-	int found = 0;
+	LIST_HEAD(list);
+	struct list_head *entry, *freeable = &list;
+	int count = 0;
+	struct inode * inode;
 
-	INIT_LIST_HEAD(freeable);
-	entry = inode_in_use.next;
-	while (entry != &inode_in_use) {
+	spin_lock(&inode_lock);
+	/* go simple and safe syncing everything before starting */
+	sync_all_inodes();
+
+	entry = inode_unused.prev;
+	while (entry != &inode_unused)
+	{
 		struct list_head *tmp = entry;
 
-		entry = entry->next;
-		if (!CAN_UNUSE(INODE(tmp)))
+		entry = entry->prev;
+		inode = INODE(tmp);
+		if (!CAN_UNUSE(inode))
 			continue;
+		if (inode->i_count)
+			BUG();
 		list_del(tmp);
-		list_del(&INODE(tmp)->i_hash);
-		INIT_LIST_HEAD(&INODE(tmp)->i_hash);
+		list_del(&inode->i_hash);
+		INIT_LIST_HEAD(&inode->i_hash);
 		list_add(tmp, freeable);
-		list_entry(tmp, struct inode, i_list)->i_state = I_FREEING;
-		found = 1;
+		inode->i_state |= I_FREEING;
+		count++;
+		if (!--goal)
+			break;
 	}
+	inodes_stat.nr_unused -= count;
+	spin_unlock(&inode_lock);
 
-	if (found)
-		dispose_list(freeable);
-
-	return found;
+	dispose_list(freeable);
 }
 
-/*
- * Searches the inodes list for freeable inodes,
- * shrinking the dcache before (and possible after,
- * if we're low)
- */
-static void try_to_free_inodes(int goal)
+int shrink_icache_memory(int priority, int gfp_mask)
 {
-	/*
-	 * First stry to just get rid of unused inodes.
-	 *
-	 * If we can't reach our goal that way, we'll have
-	 * to try to shrink the dcache and sync existing
-	 * inodes..
-	 */
-	free_inodes();
-	goal -= inodes_stat.nr_free_inodes;
-	if (goal > 0) {
-		spin_unlock(&inode_lock);
-		select_dcache(goal, 0);
-		prune_dcache(goal);
-		spin_lock(&inode_lock);
-		sync_all_inodes();
-		free_inodes();
+	if (gfp_mask & __GFP_IO)
+	{
+		int count = 0;
+		
+		if (priority)
+			count = inodes_stat.nr_unused / priority;
+		prune_icache(count);
+		/* FIXME: kmem_cache_shrink here should tell us
+		   the number of pages freed, and it should
+		   work in a __GFP_DMA/__GFP_BIGMEM behaviour
+		   to free only the interesting pages in
+		   function of the needs of the current allocation. */
+		kmem_cache_shrink(inode_cachep);
 	}
-}
 
-/*
- * This is the externally visible routine for
- * inode memory management.
- */
-void free_inode_memory(int goal)
-{
-	spin_lock(&inode_lock);
-	free_inodes();
-	spin_unlock(&inode_lock);
+	return 0;
 }
 
-
-/*
- * This is called with the spinlock held, but releases
- * the lock when freeing or allocating inodes.
- * Look out! This returns with the inode lock held if
- * it got an inode..
- *
- * We do inode allocations two pages at a time to reduce
- * fragmentation.
- */
-#define INODE_PAGE_ORDER	1
-#define INODE_ALLOCATION_SIZE	(PAGE_SIZE << INODE_PAGE_ORDER)
-#define INODES_PER_ALLOCATION	(INODE_ALLOCATION_SIZE/sizeof(struct inode))
-
-static struct inode * grow_inodes(void)
+static inline void __iget(struct inode * inode)
 {
-	struct inode * inode;
-
-	/*
-	 * Check whether to restock the unused list.
-	 */
-	if (inodes_stat.nr_inodes > max_inodes) {
-		struct list_head *tmp;
-		try_to_free_inodes(inodes_stat.nr_inodes >> 2);
-		tmp = inode_unused.next;
-		if (tmp != &inode_unused) {
-			inodes_stat.nr_free_inodes--;
-			list_del(tmp);
-			inode = list_entry(tmp, struct inode, i_list);
-			return inode;
-		}
-	}
-		
-	spin_unlock(&inode_lock);
-	inode = (struct inode *)__get_free_pages(GFP_KERNEL,INODE_PAGE_ORDER);
-	if (inode) {
-		int size;
-		struct inode * tmp;
-
-		size = INODE_ALLOCATION_SIZE - 2*sizeof(struct inode);
-		tmp = inode;
-		spin_lock(&inode_lock);
-		do {
-			tmp++;
-			init_once(tmp);
-			list_add(&tmp->i_list, &inode_unused);
-			size -= sizeof(struct inode);
-		} while (size >= 0);
-		init_once(inode);
-		/*
-		 * Update the inode statistics
-		 */
-		inodes_stat.nr_inodes += INODES_PER_ALLOCATION;
-		inodes_stat.nr_free_inodes += INODES_PER_ALLOCATION - 1;
-		return inode;
-	}
-
-	/*
-	 * If the allocation failed, do an extensive pruning of 
-	 * the dcache and then try again to free some inodes.
-	 */
-	prune_dcache(inodes_stat.nr_inodes >> 2);
-
-	spin_lock(&inode_lock);
-	free_inodes();
+	if (!inode->i_count++)
 	{
-		struct list_head *tmp = inode_unused.next;
-		if (tmp != &inode_unused) {
-			inodes_stat.nr_free_inodes--;
-			list_del(tmp);
-			inode = list_entry(tmp, struct inode, i_list);
-			return inode;
+		if (!(inode->i_state & I_DIRTY))
+		{
+			list_del(&inode->i_list);
+			list_add(&inode->i_list, &inode_in_use);
 		}
+		inodes_stat.nr_unused--;
 	}
-	spin_unlock(&inode_lock);
-
-	printk("grow_inodes: allocation failed\n");
-	return NULL;
 }
 
 /*
  * Called with the inode lock held.
+ * NOTE: we are not increasing the inode-refcount, you must call __iget()
+ * by hand after calling find_inode now! This simplify iunique and won't
+ * add any additional branch in the common code.
  */
 static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head)
 {
@@ -505,7 +445,6 @@
 			continue;
 		if (inode->i_ino != ino)
 			continue;
-		inode->i_count++;
 		break;
 	}
 	return inode;
@@ -518,7 +457,7 @@
  * i_sb, i_ino, i_count, i_state and the lists have
  * been initialized elsewhere..
  */
-void clean_inode(struct inode *inode)
+static void clean_inode(struct inode *inode)
 {
 	memset(&inode->u, 0, sizeof(inode->u));
 	inode->i_sock = 0;
@@ -528,7 +467,6 @@
 	inode->i_size = 0;
 	inode->i_generation = 0;
 	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
-	sema_init(&inode->i_sem, 1);
 	inode->i_pipe = NULL;
 }
 
@@ -542,15 +480,11 @@
 {
 	static unsigned long last_ino = 0;
 	struct inode * inode;
-	struct list_head * tmp;
 
-	spin_lock(&inode_lock);
-	tmp = inode_unused.next;
-	if (tmp != &inode_unused) {
-		list_del(tmp);
-		inodes_stat.nr_free_inodes--;
-		inode = list_entry(tmp, struct inode, i_list);
-add_new_inode:
+	inode = alloc_inode();
+	if (inode)
+	{
+		spin_lock(&inode_lock);
 		list_add(&inode->i_list, &inode_in_use);
 		inode->i_sb = NULL;
 		inode->i_dev = 0;
@@ -560,22 +494,12 @@
 		inode->i_state = 0;
 		spin_unlock(&inode_lock);
 		clean_inode(inode);
-		return inode;
 	}
-
-	/*
-	 * Warning: if this succeeded, we will now
-	 * return with the inode lock.
-	 */
-	inode = grow_inodes();
-	if (inode)
-		goto add_new_inode;
-
 	return inode;
 }
 
 /*
- * This is called with the inode lock held.. Be careful.
+ * This is called without the inode lock held.. Be careful.
  *
  * We no longer cache the sb_flags in i_flags - see fs.h
  *	-- rmk@arm.uk.linux.org
@@ -583,56 +507,47 @@
 static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head)
 {
 	struct inode * inode;
-	struct list_head * tmp = inode_unused.next;
 
-	if (tmp != &inode_unused) {
-		list_del(tmp);
-		inodes_stat.nr_free_inodes--;
-		inode = list_entry(tmp, struct inode, i_list);
-add_new_inode:
-		list_add(&inode->i_list, &inode_in_use);
-		list_add(&inode->i_hash, head);
-		inode->i_sb = sb;
-		inode->i_dev = sb->s_dev;
-		inode->i_ino = ino;
-		inode->i_flags = 0;
-		inode->i_count = 1;
-		inode->i_state = I_LOCK;
-		spin_unlock(&inode_lock);
+	inode = alloc_inode();
+	if (inode) {
+		struct inode * old;
 
-		clean_inode(inode);
-		sb->s_op->read_inode(inode);
+		spin_lock(&inode_lock);
+		/* We released the lock, so.. */
+		old = find_inode(sb, ino, head);
+		if (!old)
+		{
+			list_add(&inode->i_list, &inode_in_use);
+			list_add(&inode->i_hash, head);
+			inode->i_sb = sb;
+			inode->i_dev = sb->s_dev;
+			inode->i_ino = ino;
+			inode->i_flags = 0;
+			inode->i_count = 1;
+			inode->i_state = I_LOCK;
+			spin_unlock(&inode_lock);
 
-		/*
-		 * This is special!  We do not need the spinlock
-		 * when clearing I_LOCK, because we're guaranteed
-		 * that nobody else tries to do anything about the
-		 * state of the inode when it is locked, as we
-		 * just created it (so there can be no old holders
-		 * that haven't tested I_LOCK).
-		 */
-		inode->i_state &= ~I_LOCK;
-		wake_up(&inode->i_wait);
+			clean_inode(inode);
+			sb->s_op->read_inode(inode);
 
-		return inode;
-	}
+			/*
+			 * This is special!  We do not need the spinlock
+			 * when clearing I_LOCK, because we're guaranteed
+			 * that nobody else tries to do anything about the
+			 * state of the inode when it is locked, as we
+			 * just created it (so there can be no old holders
+			 * that haven't tested I_LOCK).
+			 */
+			inode->i_state &= ~I_LOCK;
+			wake_up(&inode->i_wait);
 
-	/*
-	 * We need to expand. Note that "grow_inodes()" will
-	 * release the spinlock, but will return with the lock 
-	 * held again if the allocation succeeded.
-	 */
-	inode = grow_inodes();
-	if (inode) {
-		/* We released the lock, so.. */
-		struct inode * old = find_inode(sb, ino, head);
-		if (!old)
-			goto add_new_inode;
-		list_add(&inode->i_list, &inode_unused);
-		inodes_stat.nr_free_inodes++;
+			return inode;
+		}
+		__iget(inode);
 		spin_unlock(&inode_lock);
-		wait_on_inode(old);
-		return old;
+		destroy_inode(inode);
+		inode = old;
+		wait_on_inode(inode);
 	}
 	return inode;
 }
@@ -660,7 +575,6 @@
 			spin_unlock(&inode_lock);
 			return res;
 		}
-		inode->i_count--; /* compensate find_inode() */
 	} else {
 		counter = max_reserved + 1;
 	}
@@ -671,10 +585,10 @@
 struct inode *igrab(struct inode *inode)
 {
 	spin_lock(&inode_lock);
-	if (inode->i_state & I_FREEING)
-		inode = NULL;
+	if (!(inode->i_state & I_FREEING))
+		__iget(inode);
 	else
-		inode->i_count++;
+		inode = NULL;
 	spin_unlock(&inode_lock);
 	if (inode)
 		wait_on_inode(inode);
@@ -689,14 +603,16 @@
 	spin_lock(&inode_lock);
 	inode = find_inode(sb, ino, head);
 	if (inode) {
+		__iget(inode);
 		spin_unlock(&inode_lock);
 		wait_on_inode(inode);
 		return inode;
 	}
+	spin_unlock(&inode_lock);
+
 	/*
-	 * get_new_inode() will do the right thing, releasing
-	 * the inode lock and re-trying the search in case it
-	 * had to block at any point.
+	 * get_new_inode() will do the right thing, re-trying the search
+	 * in case it had to block at any point.
 	 */
 	return get_new_inode(sb, ino, head);
 }
@@ -721,6 +637,7 @@
 {
 	if (inode) {
 		struct super_operations *op = NULL;
+		int destroy = 0;
 
 		if (inode->i_sb && inode->i_sb->s_op)
 			op = inode->i_sb->s_op;
@@ -750,13 +667,17 @@
 				inode->i_state|=I_FREEING;
 				spin_unlock(&inode_lock);
 				clear_inode(inode);
+				destroy = 1;
 				spin_lock(&inode_lock);
-				list_add(&inode->i_list, &inode_unused);
-				inodes_stat.nr_free_inodes++;
 			}
-			else if (!(inode->i_state & I_DIRTY)) {
-				list_del(&inode->i_list);
-				list_add(&inode->i_list, &inode_in_use);
+			else
+			{
+				if (!(inode->i_state & I_DIRTY)) {
+					list_del(&inode->i_list);
+					list_add(&inode->i_list,
+						 &inode_unused);
+				}
+				inodes_stat.nr_unused++;
 			}
 #ifdef INODE_PARANOIA
 if (inode->i_flock)
@@ -778,6 +699,8 @@
 				kdevname(inode->i_dev), inode->i_ino);
 		}
 		spin_unlock(&inode_lock);
+		if (destroy)
+			destroy_inode(inode);
 	}
 }
 
@@ -795,14 +718,11 @@
 }
 
 /*
- * Initialize the hash tables and default
- * value for max inodes
+ * Initialize the hash tables.
  */
-#define MAX_INODE (16384)
-
 void __init inode_init(void)
 {
-	int i, max;
+	int i;
 	struct list_head *head = inode_hashtable;
 
 	i = HASH_SIZE;
@@ -812,11 +732,12 @@
 		i--;
 	} while (i);
 
-	/* Initial guess at reasonable inode number */
-	max = num_physpages >> 1;
-	if (max > MAX_INODE)
-		max = MAX_INODE;
-	max_inodes = max;
+	/* inode slab cache */
+	inode_cachep = kmem_cache_create("inode_cache", sizeof(struct inode),
+					 0, SLAB_HWCACHE_ALIGN, init_once,
+					 NULL);
+	if (!inode_cachep)
+		panic("cannot create inode slab cache");
 }
 
 void update_atime (struct inode *inode)
diff -u --recursive --new-file v2.3.19/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.3.19/linux/fs/isofs/inode.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/isofs/inode.c	Thu Oct  7 10:17:09 1999
@@ -446,6 +446,14 @@
       inode_fake.i_rdev=dev;
       init_waitqueue_head(&inode_fake.i_wait);
       ms_info.addr_format=CDROM_LBA;
+      /* If a minor device was explicitly opened, set session to the
+       * minor number. For instance, if /dev/hdc1 is mounted, session
+       * 1 on the CD-ROM is selected. CD_PART_MAX gives access to
+       * a max of 64 sessions on IDE. SCSI drives must still use
+       * the session option to mount.
+       */
+      if ((MINOR(dev) % CD_PART_MAX) && (MAJOR(dev) != SCSI_CDROM_MAJOR))
+		session = MINOR(dev) % CD_PART_MAX;
       set_fs(KERNEL_DS);
       if(session >= 0 && session <= 99) {
 	      struct cdrom_tocentry Te;
@@ -1042,6 +1050,7 @@
 	struct buffer_head * bh = NULL;
 	int block = 0;
 	int i = 0;
+	int more_entries = 0;
 	void *cpnt;
 	struct iso_directory_record * raw_inode;
 
@@ -1062,7 +1071,6 @@
 				goto out_noread;
 		}
 		pnt = ((unsigned char *) bh->b_data + offset);
-		raw_inode = ((struct iso_directory_record *) pnt);
 		/*
 		 * Note: this is invariant even if the record
 		 * spans buffers and must be copied ...
@@ -1074,6 +1082,7 @@
 			ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE;
 			continue;
 		}
+		raw_inode = ((struct iso_directory_record *) pnt);
 
 		/* Check whether the raw inode spans the buffer ... */	
 		if (offset + reclen > bufsize){
@@ -1095,13 +1104,15 @@
 		inode->i_size += isonum_733 (raw_inode->size);
 		if(i == 1) inode->u.isofs_i.i_next_section_ino = ino;
 
+		more_entries = raw_inode->flags[-high_sierra] & 0x80;
+
 		ino += reclen;
 		if (cpnt)
 			kfree (cpnt);
 		i++;
 		if(i > 100)
 			goto out_toomany;
-	} while(raw_inode->flags[-high_sierra] & 0x80);
+	} while(more_entries);
 out:
 	brelse(bh);
 	return 0;
diff -u --recursive --new-file v2.3.19/linux/fs/ncpfs/Config.in linux/fs/ncpfs/Config.in
--- v2.3.19/linux/fs/ncpfs/Config.in	Tue Apr 20 15:17:20 1999
+++ linux/fs/ncpfs/Config.in	Thu Oct  7 10:17:09 1999
@@ -1,15 +1,15 @@
 #
 # 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 '  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
 if [ "$CONFIG_NCPFS_OS2_NS" = "y" ]; then
-  bool   '      Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS
+   bool '    Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS
 fi
-bool     '   Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR
-# bool     '   NDS interserver authentication support' CONFIG_NCPFS_NDS_DOMAINS
-bool     '   Use Native Language Support' CONFIG_NCPFS_NLS
-bool     '   Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS
+bool '  Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR
+# bool '  NDS interserver authentication support' CONFIG_NCPFS_NDS_DOMAINS
+bool '  Use Native Language Support' CONFIG_NCPFS_NLS
+bool '  Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS
diff -u --recursive --new-file v2.3.19/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.3.19/linux/fs/ncpfs/dir.c	Sat Aug  7 12:59:40 1999
+++ linux/fs/ncpfs/dir.c	Sat Oct  9 11:25:51 1999
@@ -5,6 +5,7 @@
  *  Modified for big endian by J.F. Chadima and David S. Miller
  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
  *  Modified 1998 Wolfram Pienkoss for NLS
+ *  Modified 1999 Wolfram Pienkoss for directory caching
  *
  */
 
@@ -25,24 +26,8 @@
 
 #include "ncplib_kernel.h"
 
-struct ncp_dirent {
-	struct nw_info_struct i;
-	struct nw_search_sequence s;	/* given back for i */
-	unsigned long f_pos;
-};
-
-static kdev_t c_dev = 0;
-static unsigned long c_ino = 0;
-static int c_size;
-static int c_seen_eof;
-static int c_last_returned_index;
-static struct ncp_dirent *c_entry = NULL;
-static DECLARE_MUTEX(c_sem);
-
-static int ncp_read_volume_list(struct ncp_server *, int, int,
-					struct ncp_dirent *);
-static int ncp_do_readdir(struct ncp_server *, struct dentry *, int, int,
-					struct ncp_dirent *);
+static int ncp_read_volume_list(struct file *, void *, filldir_t);
+static int ncp_do_readdir(struct file *, void *, filldir_t);
 
 static ssize_t ncp_dir_read(struct file *, char *, size_t, loff_t *);
 static int ncp_readdir(struct file *, void *, filldir_t);
@@ -198,22 +183,6 @@
 	}
 }
 
-/*
- * Generate a unique inode number.
- */
-ino_t ncp_invent_inos(unsigned long n)
-{
-	static ino_t ino = 2;
-
-	if (ino + 2*n < ino)
-	{
-		/* wrap around */
-		ino = 2;
-	}
-	ino += n;
-	return ino;
-}
-
 static inline int
 ncp_single_volume(struct ncp_server *server)
 {
@@ -226,16 +195,6 @@
 		inode == inode->i_sb->s_root->d_inode);
 }
 
-static inline void ncp_lock_dircache(void)
-{
-	down(&c_sem);
-}
-
-static inline void ncp_unlock_dircache(void)
-{
-	up(&c_sem);
-}
-
 
 /*
  * This is the callback when the dcache has a lookup hit.
@@ -344,67 +303,68 @@
 {
 	struct ncp_server *server;
 	struct inode *dir = dentry->d_parent->d_inode;
-	int down_case = 0;
-	int val = 0,res;
+	int res, val = 0;
 	int len = dentry->d_name.len;      
-	struct ncpfs_inode_info finfo;
+	struct ncp_entry_info finfo;
 	__u8 __name[dentry->d_name.len + 1];
 
 	if (!dentry->d_inode || !dir)
-		return 0;
+		goto finished;
         
 	server = NCP_SERVER(dir);
 
 	if (!ncp_conn_valid(server))
 		goto finished;
 
-	strncpy(__name, dentry->d_name.name, len);
-	__name[len] = '\0';
+	/*
+	 * Inspired by smbfs:
+	 * The default validation is based on dentry age:
+	 * We set the max age at mount time.  (But each
+	 * successful server lookup renews the timestamp.)
+	 */
+	val = NCP_TEST_AGE(server, dentry);
+	if (val)
+		goto finished;
 #ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup_validate: %s, len %d\n", __name, len);
+	printk(KERN_DEBUG "ncp_lookup_validate: %s/%s not valid, age=%ld\n",
+		dentry->d_parent->d_name.name, dentry->d_name.name,
+		NCP_GET_AGE(dentry));
 #endif
 
-	/* If the file is in the dir cache, we do not have to ask the
-	   server. */
-
+	memcpy(__name, dentry->d_name.name, len);
+	__name[len] = '\0';
 #ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup_validate: %s, len %d\n", __name, len);
 printk(KERN_DEBUG "ncp_lookup_validate: server lookup for %s/%s\n",
 dentry->d_parent->d_name.name, __name);
 #endif
-		if (ncp_is_server_root(dir))
-		{
-			io2vol(server, __name, 1);
-			down_case = 1;
-			res = ncp_lookup_volume(server, __name,
-						&(finfo.nw_info.i));
-		} else
-	    	{
-			down_case = !ncp_preserve_case(dir);
-			io2vol(server, __name, down_case);
-			res = ncp_obtain_info(server, dir, __name,
-						&(finfo.nw_info.i));
-		}
+	if (ncp_is_server_root(dir)) {
+		io2vol(server, __name, 1);
+		res = ncp_lookup_volume(server, __name, &(finfo.i));
+	} else {
+		io2vol(server, __name, !ncp_preserve_case(dir));
+		res = ncp_obtain_info(server, dir, __name, &(finfo.i));
+	}
 #ifdef NCPFS_PARANOIA
 printk(KERN_DEBUG "ncp_lookup_validate: looked for %s/%s, res=%d\n",
 dentry->d_parent->d_name.name, __name, res);
 #endif
-		/*
-		 * If we didn't find it, or if it has a different dirEntNum to
-		 * what we remember, it's not valid any more.
-		 */
-	   	if (!res) {
-		  if (finfo.nw_info.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum)
-		    val=1;
+	/*
+	 * If we didn't find it, or if it has a different dirEntNum to
+	 * what we remember, it's not valid any more.
+	 */
+	if (!res) {
+		if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum)
+			val=1;
 #ifdef NCPFS_PARANOIA
-		  else
-		    printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n");
+		else
+			printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n");
 #endif
-		  vol2io(server, finfo.nw_info.i.entryName,
-			 !ncp_preserve_entry_case(dir,
-			 finfo.nw_info.i.NSCreator));
- 		  ncp_update_inode2(dentry->d_inode, &finfo.nw_info);
-		}
-		if (!val) ncp_invalid_dir_cache(dir);
+		vol2io(server, finfo.i.entryName,
+			!ncp_preserve_entry_case(dir, finfo.i.NSCreator));
+		ncp_update_inode2(dentry->d_inode, &finfo);
+		ncp_new_dentry(dentry);
+	}
 
 finished:
 #ifdef NCPFS_PARANOIA
@@ -420,279 +380,341 @@
 	struct dentry *dentry = filp->f_dentry;
 	struct inode *inode = dentry->d_inode;
 	struct ncp_server *server = NCP_SERVER(inode);
-	struct ncp_dirent *entry = NULL;
-	int result, i, index = 0;
+	int entries, result;
 
 	DDPRINTK(KERN_DEBUG "ncp_readdir: reading %s/%s, pos=%d\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(int) filp->f_pos);
-	DDPRINTK(KERN_DEBUG "ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
-		 inode->i_ino, c_ino);
 
 	result = -EIO;
 	if (!ncp_conn_valid(server))
-		goto out;
-
-	ncp_lock_dircache();
-	result = -ENOMEM;
-	if (c_entry == NULL) {
-		i = sizeof(struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
-		c_entry = (struct ncp_dirent *) vmalloc(i);
-		if (c_entry == NULL) {
-			printk(KERN_WARNING "ncp_readdir: no MEMORY for cache\n");
-			goto finished;
-		}
-	}
+		goto finished;
 
 	result = 0;
 	if (filp->f_pos == 0) {
-		ncp_invalid_dir_cache(inode);
-		if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0) {
+		if (filldir(dirent, ".", 1, 0, inode->i_ino))
 			goto finished;
-		}
 		filp->f_pos = 1;
 	}
 	if (filp->f_pos == 1) {
 		if (filldir(dirent, "..", 2, 1,
-				dentry->d_parent->d_inode->i_ino) < 0) {
+				dentry->d_parent->d_inode->i_ino))
 			goto finished;
-		}
 		filp->f_pos = 2;
 	}
 
-	if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino)) {
-		for (i = 0; i < c_size; i++) {
-			if (filp->f_pos == c_entry[i].f_pos) {
-				entry = &c_entry[i];
-				c_last_returned_index = i;
-				index = i;
-				break;
-			}
-		}
-		if ((entry == NULL) && c_seen_eof) {
-			goto finished;
-		}
+	if (ncp_is_server_root(inode)) {
+		entries = ncp_read_volume_list(filp, dirent, filldir);
+		DPRINTK(KERN_DEBUG "ncp_read_volume_list returned %d\n", entries);
+	} else {
+		entries = ncp_do_readdir(filp, dirent, filldir);
+		DPRINTK(KERN_DEBUG "ncp_readdir: returned %d\n", entries);
 	}
-	if (entry == NULL) {
-		int entries;
-		DDPRINTK(KERN_DEBUG "ncp_readdir: Not found in cache.\n");
-
-		if (ncp_is_server_root(inode)) {
-			entries = ncp_read_volume_list(server, filp->f_pos,
-					 NCP_READDIR_CACHE_SIZE, c_entry);
-			DPRINTK(KERN_DEBUG "ncp_read_volume_list returned %d\n", entries);
 
-		} else {
-			entries = ncp_do_readdir(server, dentry, filp->f_pos,
-					 NCP_READDIR_CACHE_SIZE, c_entry);
-			DPRINTK(KERN_DEBUG "ncp_readdir: returned %d\n", entries);
-		}
+	if (entries < 0)
+		result = entries;
 
-		if (entries < 0) {
-			c_dev = 0;
-			c_ino = 0;
-			result = entries;
-			goto finished;
-		}
-		if (entries > 0) {
-			c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
-			c_dev = inode->i_dev;
-			c_ino = inode->i_ino;
-			c_size = entries;
-			entry = c_entry;
-			c_last_returned_index = 0;
-			index = 0;
-
-			for (i = 0; i < c_size; i++)
-			{
-				vol2io(server, c_entry[i].i.entryName,
-					!ncp_preserve_entry_case(inode,
-					c_entry[i].i.NSCreator));
+finished:
+	return result;
+}
+
+static int
+ncp_do_simple_filldir(struct file *filp, char* name, int len,
+		void* dirent, filldir_t filldir)
+{
+	struct dentry *dentry = filp->f_dentry;
+	struct qstr qname;
+	ino_t ino = 0;
+	int result;
+	
+	qname.name = name;
+	qname.len = len;
+	
+	ino = find_inode_number(dentry, &qname);
+
+	if (!ino)
+		ino = iunique(2);
+
+	result = filldir(dirent, name, len, filp->f_pos, ino);
+	if (!result)
+		filp->f_pos += 1;
+
+	return result;
+}	
+	
+static int
+ncp_do_filldir(struct file *filp, struct ncp_entry_info *entry, void *dirent,
+			filldir_t filldir)
+{
+	struct dentry *dentry = filp->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	struct qstr qname;
+	ino_t ino = 0;
+	int result;
+
+	/* For getwd() we have to return the correct inode in d_ino if the
+	 * inode is currently in use. Otherwise the inode number does not
+	 * matter. (You can argue a lot about this..)
+	 */
+	qname.name = entry->i.entryName;
+	qname.len  = entry->i.nameLen;
+
+	{
+		struct dentry *newdent;
+		struct inode *newino;
+
+		qname.hash = full_name_hash(qname.name, qname.len);
+		if (dentry->d_op && dentry->d_op->d_hash)
+			if (dentry->d_op->d_hash(dentry, &qname) != 0)
+				goto end_advance;
+
+		newdent = d_lookup(dentry, &qname);
+
+		if (!newdent) {
+			newdent = d_alloc(dentry, &qname);
+			if (!newdent)
+				goto end_advance;
+		}
+
+		if (!newdent->d_inode) {
+			entry->opened = 0;
+			entry->ino = iunique(2);
+			newino = ncp_iget(inode->i_sb, entry);
+			if (newino) {
+				newdent->d_op = &ncp_dentry_operations;
+				d_add(newdent, newino);
+				ncp_new_dentry(newdent);
 			}
+		} else {
+			ncp_update_inode2(newdent->d_inode, entry);
+			ncp_new_dentry(newdent);
 		}
-	}
-	if (entry == NULL) {
-		/* Nothing found, even from a ncp call */
-		goto finished;
-	}
 
-	while (index < c_size) {
-		ino_t ino;
-		struct qstr qname;
-
-		DDPRINTK(KERN_DEBUG "ncp_readdir: entry->path= %s\n", entry->i.entryName);
-		DDPRINTK(KERN_DEBUG "ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
-
-		/* For getwd() we have to return the correct
-		 * inode in d_ino if the inode is currently in
-		 * use. Otherwise the inode number does not
-		 * matter. (You can argue a lot about this..)
-		 */
-		qname.name = entry->i.entryName;
-		qname.len  = entry->i.nameLen;
+		if (newdent->d_inode)
+			ino = newdent->d_inode->i_ino;
+
+		dput(newdent);
+
+end_advance:
+	}
+	if (!ino)
 		ino = find_inode_number(dentry, &qname);
-		if (!ino)
-			ino = ncp_invent_inos(1);
 
-		if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
-			    entry->f_pos, ino) < 0) {
-			break;
-		}
-		if ((inode->i_dev != c_dev)
-		    || (inode->i_ino != c_ino)
-		    || (entry->f_pos != filp->f_pos)) {
-			/* Someone has destroyed the cache while we slept
-			   in filldir */
-			break;
-		}
+	if (!ino)
+		ino = iunique(2);
+
+	result = filldir(dirent, entry->i.entryName, entry->i.nameLen,
+				filp->f_pos, ino);
+	if (!result)
 		filp->f_pos += 1;
-		index += 1;
-		entry += 1;
-	}
-      finished:
-	ncp_unlock_dircache();
-out:
+
 	return result;
 }
 
 static int 
-ncp_read_volume_list(struct ncp_server *server, int fpos,
-			 int cache_size, struct ncp_dirent *entry)
+ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir)
 {
-	int i, total_count = 2;
+	struct dentry *dentry = filp->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	struct ncp_server *server = NCP_SERVER(inode);
 	struct ncp_volume_info info;
+	struct ncp_entry_info entry;
+	unsigned long total_count = 2, fpos = filp->f_pos;
+	int i;
 
-	DPRINTK(KERN_DEBUG "ncp_read_volume_list: pos=%d\n", fpos);
-#if 1
-	if (fpos < 2) {
-		printk(KERN_ERR "OOPS, we expect fpos >= 2");
-		fpos = 2;
-	}
-#endif
+	DPRINTK(KERN_DEBUG "ncp_read_volume_list: pos=%ld\n", fpos);
 
 	for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
 
 		if (ncp_get_volume_info_with_number(server, i, &info) != 0)
-			goto out;
+			break;
 		if (!strlen(info.volume_name))
 			continue;
 
 		if (total_count < fpos) {
 			DPRINTK(KERN_DEBUG "ncp_read_volume_list: skipped vol: %s\n",
 				info.volume_name);
-		} else if (total_count >= fpos + cache_size) {
-			goto out;
 		} else {
 			DPRINTK(KERN_DEBUG "ncp_read_volume_list: found vol: %s\n",
 				info.volume_name);
 
 			if (ncp_lookup_volume(server, info.volume_name,
-					      &(entry->i)) != 0) {
+						&entry.i)) {
 				DPRINTK(KERN_DEBUG "ncpfs: could not lookup vol %s\n",
 					info.volume_name);
 				continue;
 			}
-			entry->f_pos = total_count;
-			entry += 1;
+			vol2io(server, entry.i.entryName,
+				!ncp_preserve_entry_case(inode, entry.i.NSCreator));
+			if (ncp_do_filldir(filp, &entry, dirent, filldir))
+				break;
 		}
 		total_count += 1;
 	}
-out:
+
 	return (total_count - fpos);
 }
 
-static int ncp_do_readdir(struct ncp_server *server, struct dentry *dentry,
-			int fpos, int cache_size, struct ncp_dirent *entry)
+static int ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
+	struct dentry *dentry = filp->f_dentry;
 	struct inode *dir = dentry->d_inode;
-	static struct inode *last_dir;
-	static int total_count;
-	static struct nw_search_sequence seq;
+	struct ncp_server *server = NCP_SERVER(dir);
+	struct ncp_seq_cache *cache = NULL;
+	struct ncp_cache_control ctl;
+	struct ncp_entry_info entry;
+	struct page *page, **hash;
+	unsigned long total_count = 0, fpos = filp->f_pos;
 	int err;
 
-#if 1
-	if (fpos < 2) {
-		printk(KERN_ERR "OOPS, we expect fpos >= 2");
-		fpos = 2;
-	}
-#endif
-	DPRINTK(KERN_DEBUG "ncp_do_readdir: %s/%s, fpos=%d\n",
+	DPRINTK(KERN_DEBUG "ncp_do_readdir: %s/%s, fpos=%ld\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name, fpos);
 
-	if (fpos == 2) {
-		last_dir = NULL;
-		total_count = 2;
+#ifdef NCPFS_DEBUG_VERBOSE
+printk("ncp_do_readdir: finding cache for %s/%s\n",
+	dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+
+	/* cache using inspired by smbfs and nfs */
+	hash = page_hash(dir, 0);
+
+	page = __find_lock_page(dir, 0, hash);
+
+	if (!page) {
+		unsigned long page_cache;
+
+		page_cache = page_cache_alloc();
+		if (page_cache) {
+			page = page_cache_entry(page_cache);
+			if (add_to_page_cache_unique(page, dir, 0, hash)) {
+				page_cache_release(page);
+				page = NULL;
+				page_cache_free(page_cache);
+			}
+		}
 	}
-	if ((fpos != total_count) || (dir != last_dir))
+
+	if (!page)
+		goto start_search;
+
+	cache = (struct ncp_seq_cache *) page_address(page);
+	ctl = cache->ctl;
+
+	if (!Page_Uptodate(page))
+		ctl.currentpos = NCP_FPOS_EMPTY;
+
+	if ((fpos == 2) || (fpos < ctl.firstcache))
+		ctl.currentpos = NCP_FPOS_EMPTY;
+
+	if (ctl.currentpos == NCP_FPOS_EMPTY)
+		goto start_search;
+
 	{
-		total_count = 2;
-		last_dir = dir;
+		int fetchpos = ctl.cachehead;
+		int readpos = ctl.firstcache;
 		
+		while (readpos < fpos) {
+			fetchpos += cache->cache[fetchpos] + 1;
+			readpos++;
+		}
+		while (fpos < ctl.currentpos) {
+			err = ncp_do_simple_filldir(filp, 
+				(char*)(cache->cache+fetchpos+1), 
+				cache->cache[fetchpos], 
+				dirent, filldir);
+			if (err)
+				goto out;
+			fetchpos += cache->cache[fetchpos] + 1;
+			fpos++;
+			total_count++;
+		}
+	}
+	
+start_search:
+
+	DDPRINTK(KERN_DEBUG "ncp_do_readdir: %s: f_pos=%ld,total_count=%ld\n",
+			dentry->d_name.name, fpos, total_count);
+
+	if (ctl.currentpos == NCP_FPOS_EMPTY) {
 #ifdef NCPFS_PARANOIA
 printk(KERN_DEBUG "ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
 dentry->d_name.name, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
 #endif
-		err = ncp_initialize_search(server, dir, &seq); 
-		if (err)
-		{
+		err = ncp_initialize_search(server, dir, &ctl.seq); 
+		if (err) {
 			DPRINTK(KERN_DEBUG "ncp_do_readdir: init failed, err=%d\n", err);
 			goto out;
 		}
-	}
+		ctl.eof = 0;
+		ctl.cachehead = ctl.cachetail = 0;
+		ctl.firstcache = ctl.currentpos = 2;
+	} else
+		DDPRINTK(KERN_DEBUG "ncp_do_readdir: reused seq for %s, fpos=%li\n",
+				dentry->d_name.name, total_count);
 
-	while (total_count < fpos + cache_size) {
-		err = ncp_search_for_file_or_subdir(server, &seq, &(entry->i));
+	for (;;) {
+		err = ncp_search_for_file_or_subdir(server, &ctl.seq,
+						    &entry.i);
 		if (err) {
 			DPRINTK(KERN_DEBUG "ncp_do_readdir: search failed, err=%d\n", err);
-			goto out;
+			ctl.eof = 1;
+			break;
 		}
-		if (total_count < fpos) {
+
+		ctl.currentpos++;
+		
+		vol2io(server, entry.i.entryName,
+			!ncp_preserve_entry_case(dir, entry.i.NSCreator));
+			
+		if (page) {
+			int tlen = ctl.cachetail + entry.i.nameLen + 1;
+			
+			if (tlen > NCP_DIRCACHE_SIZE) {
+				int ofs = ctl.cachehead;
+				
+				while (tlen - ofs > NCP_DIRCACHE_SIZE) {
+					ofs += cache->cache[ofs] + 1;
+					ctl.firstcache++;
+				}
+				ctl.cachetail -= ofs;
+				memmove(cache->cache+0,
+					cache->cache+ofs,
+					ctl.cachetail);
+			}
+			cache->cache[ctl.cachetail++] = entry.i.nameLen;
+			memcpy(cache->cache+ctl.cachetail, 
+			       entry.i.entryName, entry.i.nameLen);
+			ctl.cachetail += entry.i.nameLen;
+		}
+		if (ctl.currentpos < fpos) {
 			DPRINTK(KERN_DEBUG "ncp_do_readdir: skipped file: %s/%s\n",
-				dentry->d_name.name, entry->i.entryName);
+				dentry->d_name.name, entry.i.entryName);
 		} else {
-			DDPRINTK(KERN_DEBUG "ncp_do_r: file: %s, f_pos=%d,total_count=%d",
-				entry->i.entryName, fpos, total_count);
-			entry->s = seq;
-			entry->f_pos = total_count;
-			entry += 1;
+			DDPRINTK(KERN_DEBUG "ncp_do_r: file: %s, f_pos=%ld,total_count=%ld",
+				entry.i.entryName, fpos, total_count);
+			if (ncp_do_filldir(filp, &entry, dirent, filldir))
+				break;
 		}
-		total_count += 1;
+		total_count++;
+		fpos++;
 	}
 out:
-	return (total_count - fpos);
-}
-
-void ncp_init_dir_cache(void)
-{
-	c_dev = 0;
-	c_ino = 0;
-	c_entry = NULL;
-}
-
-void ncp_invalid_dir_cache(struct inode *ino)
-{
-	if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino)) {
-		c_dev = 0;
-		c_ino = 0;
-		c_seen_eof = 0;
-	}
-}
-
-void ncp_free_dir_cache(void)
-{
-	DPRINTK(KERN_DEBUG "ncp_free_dir_cache: enter\n");
-
-	if (c_entry == NULL) {
-		return;
+	if (page) {
+		cache->ctl = ctl;
+		SetPageUptodate(page);
+		UnlockPage(page);
+		page_cache_release(page);
 	}
-	vfree(c_entry);
-	c_entry = NULL;
 
-	DPRINTK(KERN_DEBUG "ncp_free_dir_cache: exit\n");
+	DDPRINTK(KERN_DEBUG "ncp_do_readdir: %s: return=%ld\n",
+			dentry->d_name.name, total_count);
+	return total_count;
 }
 
-int ncp_conn_logged_in(struct ncp_server *server)
+int ncp_conn_logged_in(struct super_block *sb)
 {
+	struct ncp_server* server = NCP_SBP(sb);
+	struct nw_info_struct i;
 	int result;
 
 	if (ncp_single_volume(server)) {
@@ -700,26 +722,25 @@
 
 		result = -ENOENT;
 		io2vol(server, server->m.mounted_vol, 1);
-		if (ncp_lookup_volume(server, server->m.mounted_vol,
-				      &(server->root.finfo.i)) != 0) {
+		if (ncp_lookup_volume(server, server->m.mounted_vol, &i)) {
 #ifdef NCPFS_PARANOIA
 printk(KERN_DEBUG "ncp_conn_logged_in: %s not found\n", server->m.mounted_vol);
 #endif
 			goto out;
 		}
-		vol2io(server, server->root.finfo.i.entryName, 1);
-		dent = server->root_dentry;
+		vol2io(server, i.entryName, 1);
+		dent = sb->s_root;
 		if (dent) {
 			struct inode* ino = dent->d_inode;
 			if (ino) {
-				NCP_FINFO(ino)->volNumber = server->root.finfo.i.volNumber;
-				NCP_FINFO(ino)->dirEntNum = server->root.finfo.i.dirEntNum;
-				NCP_FINFO(ino)->DosDirNum = server->root.finfo.i.DosDirNum;
+				NCP_FINFO(ino)->volNumber = i.volNumber;
+				NCP_FINFO(ino)->dirEntNum = i.dirEntNum;
+				NCP_FINFO(ino)->DosDirNum = i.DosDirNum;
 			} else {
-				DPRINTK(KERN_DEBUG "ncpfs: sb->root_dentry->d_inode == NULL!\n");
+				DPRINTK(KERN_DEBUG "ncpfs: sb->s_root->d_inode == NULL!\n");
 			}
 		} else {
-			DPRINTK(KERN_DEBUG "ncpfs: sb->root_dentry == NULL!\n");
+			DPRINTK(KERN_DEBUG "ncpfs: sb->s_root == NULL!\n");
 		}
 	}
 	result = 0;
@@ -732,10 +753,8 @@
 {
 	struct ncp_server *server;
 	struct inode *inode = NULL;
-	int found_in_cache, down_case = 0;
-	int error;
-	int len = dentry->d_name.len;      
-	struct ncpfs_inode_info finfo;
+	int error, res, len = dentry->d_name.len;
+	struct ncp_entry_info finfo;
 	__u8 __name[dentry->d_name.len + 1];
 
 	server = NCP_SERVER(dir);
@@ -744,88 +763,46 @@
 	if (!ncp_conn_valid(server))
 		goto finished;
 
-	strncpy(__name, dentry->d_name.name, len);
+	memcpy(__name, dentry->d_name.name, len);
 	__name[len] = '\0';
 #ifdef NCPFS_PARANOIA
 printk(KERN_DEBUG "ncp_lookup: %s, len %d\n", __name, len);
-#endif
-
-	/* If the file is in the dir cache, we do not have to ask the
-	   server. */
-
-	found_in_cache = 0;
-	ncp_lock_dircache();
-
-	if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
-	{
-		int first = c_last_returned_index;
-		int i;
-	    
-		i = first;
-		do {
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup: trying index: %d, name: %s\n", i, c_entry[i].i.entryName);
-#endif
-			if (strcmp(c_entry[i].i.entryName, __name) == 0) {
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup: found in cache!\n");
-#endif
-				finfo.nw_info.i = c_entry[i].i;
-				found_in_cache = 1;
-				break;
-			}
-			i = (i + 1) % c_size;
-		} while (i != first);
-	}
-	ncp_unlock_dircache();
-
-	if (found_in_cache == 0)
-	{
-		int res;
-	    
-#ifdef NCPFS_PARANOIA
 printk(KERN_DEBUG "ncp_lookup: server lookup for %s/%s\n",
 dentry->d_parent->d_name.name, __name);
 #endif
-		if (ncp_is_server_root(dir))
-		{
-			io2vol(server, __name, 1);
-			down_case = 1;
-			res = ncp_lookup_volume(server, __name,
-						&(finfo.nw_info.i));
-		} else
-	    	{
-			down_case = !ncp_preserve_case(dir);
-			io2vol(server, __name, down_case);
-			res = ncp_obtain_info(server, dir, __name,
-						&(finfo.nw_info.i));
-		}
+	if (ncp_is_server_root(dir)) {
+		io2vol(server, __name, 1);
+		res = ncp_lookup_volume(server, __name, &(finfo.i));
+	} else {
+		io2vol(server, __name, !ncp_preserve_case(dir));
+		res = ncp_obtain_info(server, dir, __name, &(finfo.i));
+	}
 #ifdef NCPFS_PARANOIA
 printk(KERN_DEBUG "ncp_lookup: looked for %s/%s, res=%d\n",
 dentry->d_parent->d_name.name, __name, res);
 #endif
-		/*
-		 * If we didn't find an entry, make a negative dentry.
-		 */
-	   	if (res != 0) {
-			goto add_entry;
-		} else vol2io(server, finfo.nw_info.i.entryName,
-			      !ncp_preserve_entry_case(dir,
-			      finfo.nw_info.i.NSCreator));
-	}
+	/*
+	 * If we didn't find an entry, make a negative dentry.
+	 */
+	if (res)
+		goto add_entry;
+
+	vol2io(server, finfo.i.entryName,
+		!ncp_preserve_entry_case(dir, finfo.i.NSCreator));
 
 	/*
 	 * Create an inode for the entry.
 	 */
-	finfo.nw_info.opened = 0;
-	finfo.ino = ncp_invent_inos(1);
+	finfo.opened = 0;
+	finfo.ino = iunique(2);
 	error = -EACCES;
 	inode = ncp_iget(dir->i_sb, &finfo);
-	if (inode)
-	{
-	add_entry:
+
+	if (inode) {
+add_entry:
 		dentry->d_op = &ncp_dentry_operations;
 		d_add(dentry, inode);
+		ncp_new_dentry(dentry);
 		error = 0;
 	}
 
@@ -840,14 +817,12 @@
  * This code is common to create, mkdir, and mknod.
  */
 static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
-			struct ncpfs_inode_info *finfo)
+			struct ncp_entry_info *finfo)
 {
 	struct inode *inode;
 	int error = -EINVAL;
 
-	ncp_invalid_dir_cache(dir);
-
-	finfo->ino = ncp_invent_inos(1);
+	finfo->ino = iunique(2);
 	inode = ncp_iget(dir->i_sb, finfo);
 	if (!inode)
 		goto out_close;
@@ -861,7 +836,7 @@
 printk(KERN_DEBUG "ncp_instantiate: %s/%s failed, closing file\n",
 dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
-	ncp_close_file(NCP_SERVER(dir), finfo->nw_info.file_handle);
+	ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
 	goto out;
 }
 
@@ -869,7 +844,8 @@
 		int attributes)
 {
 	int error, result;
-	struct ncpfs_inode_info finfo;
+	struct ncp_entry_info finfo;
+	struct ncp_server *server = NCP_SERVER(dir);
 	__u8 _name[dentry->d_name.len + 1];
 	
 #ifdef NCPFS_PARANOIA
@@ -877,20 +853,22 @@
 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
 #endif
 	error = -EIO;
-	if (!ncp_conn_valid(NCP_SERVER(dir)))
+	if (!ncp_conn_valid(server))
 		goto out;
 
-	strncpy(_name, dentry->d_name.name, dentry->d_name.len);
+	ncp_age_dentry(server, dentry);
+
+	memcpy(_name, dentry->d_name.name, dentry->d_name.len);
 	_name[dentry->d_name.len] = '\0';
 
-	io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
+	io2vol(server, _name, !ncp_preserve_case(dir));
 
 	error = -EACCES;
-	result = ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
+	result = ncp_open_create_file_or_subdir(server, dir, _name,
 			   OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
-			   attributes, AR_READ | AR_WRITE, &finfo.nw_info);
+			   attributes, AR_READ | AR_WRITE, &finfo);
 	if (!result) {
-		finfo.nw_info.access = O_RDWR;
+		finfo.access = O_RDWR;
 		error = ncp_instantiate(dir, dentry, &finfo);
 	} else {
 		if (result == 0x87) error = -ENAMETOOLONG;
@@ -910,23 +888,26 @@
 static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	int error;
-	struct ncpfs_inode_info finfo;
+	struct ncp_entry_info finfo;
+	struct ncp_server *server = NCP_SERVER(dir);
 	__u8 _name[dentry->d_name.len + 1];
 
 	DPRINTK(KERN_DEBUG "ncp_mkdir: making %s/%s\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 	error = -EIO;
-	if (!ncp_conn_valid(NCP_SERVER(dir)))
+	if (!ncp_conn_valid(server))
 		goto out;
 
-	strncpy(_name, dentry->d_name.name, dentry->d_name.len);
+	ncp_age_dentry(server, dentry);
+
+	memcpy(_name, dentry->d_name.name, dentry->d_name.len);
 	_name[dentry->d_name.len] = '\0';
-	io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
+	io2vol(server, _name, !ncp_preserve_case(dir));
 
 	error = -EACCES;
-	if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
+	if (ncp_open_create_file_or_subdir(server, dir, _name,
 					   OC_MODE_CREATE, aDIR, 0xffff,
-					   &finfo.nw_info) == 0)
+					   &finfo) == 0)
 	{
 		error = ncp_instantiate(dir, dentry, &finfo);
 	}
@@ -937,27 +918,27 @@
 static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	int error, result;
+	struct ncp_server *server = NCP_SERVER(dir);
 	__u8 _name[dentry->d_name.len + 1];
 
 	DPRINTK(KERN_DEBUG "ncp_rmdir: removing %s/%s\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
 	error = -EIO;
-	if (!ncp_conn_valid(NCP_SERVER(dir)))
+	if (!ncp_conn_valid(server))
 		goto out;
 
 	error = -EBUSY;
 	if (!list_empty(&dentry->d_hash))
 		goto out;
 
-	strncpy(_name, dentry->d_name.name, dentry->d_name.len);
+	memcpy(_name, dentry->d_name.name, dentry->d_name.len);
 	_name[dentry->d_name.len] = '\0';
 	    
-	io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
-	result = ncp_del_file_or_subdir(NCP_SERVER(dir), dir, _name);
+	io2vol(server, _name, !ncp_preserve_case(dir));
+	result = ncp_del_file_or_subdir(server, dir, _name);
 	switch (result) {
 		case 0x00:
-   			ncp_invalid_dir_cache(dir);
 			error = 0;
 			break;
 		case 0x85:	/* unauthorized to delete file */
@@ -988,13 +969,14 @@
 static int ncp_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
+	struct ncp_server *server = NCP_SERVER(dir);
 	int error;
 
 	DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 	
 	error = -EIO;
-	if (!ncp_conn_valid(NCP_SERVER(dir)))
+	if (!ncp_conn_valid(server))
 		goto out;
 
 	/*
@@ -1007,11 +989,11 @@
 		ncp_make_closed(inode);
 	}
 
-	error = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
+	error = ncp_del_file_or_subdir2(server, dentry);
 #ifdef CONFIG_NCPFS_STRONG
 	/* 9C is Invalid path.. It should be 8F, 90 - read only, but
 	   it is not :-( */
-	if (error == 0x9C && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) { /* R/O */
+	if (error == 0x9C && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
 		error = ncp_force_unlink(dir, dentry);
 	}
 #endif
@@ -1019,7 +1001,6 @@
 		case 0x00:
 			DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n",
 				dentry->d_parent->d_name.name, dentry->d_name.name);
-			ncp_invalid_dir_cache(dir);
 			d_delete(dentry);
 			break;
 		case 0x85:
@@ -1064,11 +1045,14 @@
 	if (!ncp_conn_valid(NCP_SERVER(old_dir)))
 		goto out;
 
-	strncpy(_old_name, old_dentry->d_name.name, old_len);
+	ncp_age_dentry(NCP_SERVER(old_dir), old_dentry);
+	ncp_age_dentry(NCP_SERVER(new_dir), new_dentry);
+
+	memcpy(_old_name, old_dentry->d_name.name, old_len);
 	_old_name[old_len] = '\0';
 	io2vol(NCP_SERVER(old_dir), _old_name, !ncp_preserve_case(old_dir));
 
-	strncpy(_new_name, new_dentry->d_name.name, new_len);
+	memcpy(_new_name, new_dentry->d_name.name, new_len);
 	_new_name[new_len] = '\0';
 	io2vol(NCP_SERVER(new_dir), _new_name, !ncp_preserve_case(new_dir));
 
@@ -1085,8 +1069,6 @@
 		case 0x00:
                	        DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n",
                                 old_dentry->d_name.name,new_dentry->d_name.name);
-       	                ncp_invalid_dir_cache(old_dir);
-               	        ncp_invalid_dir_cache(new_dir);
 			/* d_move(old_dentry, new_dentry); */
 			break;
 		case 0x9E:
diff -u --recursive --new-file v2.3.19/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c
--- v2.3.19/linux/fs/ncpfs/file.c	Sun Jun 27 10:10:41 1999
+++ linux/fs/ncpfs/file.c	Thu Oct  7 10:17:09 1999
@@ -38,7 +38,7 @@
 {
 	int error, result;
 	int access;
-	struct nw_file_info finfo;
+	struct ncp_entry_info finfo;
 
 	error = -EINVAL;
 	if (!inode) {
@@ -259,7 +259,6 @@
 
 	if (pos > inode->i_size) {
 		inode->i_size = pos;
-		ncp_invalid_dir_cache(dentry->d_parent->d_inode);
 	}
 	DPRINTK(KERN_DEBUG "ncp_file_write: exit %s/%s\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
diff -u --recursive --new-file v2.3.19/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.3.19/linux/fs/ncpfs/inode.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/ncpfs/inode.c	Sat Oct  9 11:25:51 1999
@@ -31,7 +31,6 @@
 
 #include "ncplib_kernel.h"
 
-static void ncp_read_inode(struct inode *);
 static void ncp_put_inode(struct inode *);
 static void ncp_delete_inode(struct inode *);
 static void ncp_put_super(struct super_block *);
@@ -39,7 +38,7 @@
 
 static struct super_operations ncp_sops =
 {
-	ncp_read_inode,		/* read inode */
+	NULL,			/* read inode */
 	NULL,			/* write inode */
 	ncp_put_inode,		/* put inode */
 	ncp_delete_inode,       /* delete inode */
@@ -56,21 +55,15 @@
 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
 #endif
 
-static struct nw_file_info *read_nwinfo = NULL;
-static DECLARE_MUTEX(read_sem);
-
 /*
  * Fill in the ncpfs-specific information in the inode.
  */
-void ncp_update_inode(struct inode *inode, struct nw_file_info *nwinfo)
+void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
 {
 	NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
 	NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
 	NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
 
-#ifdef CONFIG_NCPFS_SMALLDOS
-	NCP_FINFO(inode)->origNS = nwinfo->i.NSCreator;
-#endif
 #ifdef CONFIG_NCPFS_STRONG
 	NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
 #endif
@@ -85,7 +78,7 @@
 #endif
 }
 
-void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo)
+void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
 {
 	struct nw_info_struct *nwi = &nwinfo->i;
 	struct ncp_server *server = NCP_SERVER(inode);
@@ -96,7 +89,7 @@
 #endif
 		if (nwi->attributes & aDIR) {
 			inode->i_mode = server->m.dir_mode;
-			inode->i_size = 512;
+			inode->i_size = NCP_BLOCK_SIZE;
 		} else {
 			inode->i_mode = server->m.file_mode;
 			inode->i_size = le32_to_cpu(nwi->dataStreamSize);
@@ -105,8 +98,8 @@
 				switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
 					case aHIDDEN:
 						if (server->m.flags & NCP_MOUNT_SYMLINKS) {
-							if ((inode->i_size >= NCP_MIN_SYMLINK_SIZE)
-							 && (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
+							if ( /* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
+							 && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
 								inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
 								break;
 							}
@@ -149,9 +142,9 @@
 }
 
 /*
- * Fill in the inode based on the nw_file_info structure.
+ * Fill in the inode based on the ncp_entry_info structure.
  */
-static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo)
+static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
 {
 	struct nw_info_struct *nwi = &nwinfo->i;
 	struct ncp_server *server = NCP_SERVER(inode);
@@ -160,7 +153,7 @@
 		inode->i_mode = server->m.dir_mode;
 		/* for directories dataStreamSize seems to be some
 		   Object ID ??? */
-		inode->i_size = 512;
+		inode->i_size = NCP_BLOCK_SIZE;
 	} else {
 		inode->i_mode = server->m.file_mode;
 		inode->i_size = le32_to_cpu(nwi->dataStreamSize);
@@ -200,7 +193,7 @@
 	inode->i_nlink = 1;
 	inode->i_uid = server->m.uid;
 	inode->i_gid = server->m.gid;
-	inode->i_blksize = 512;
+	inode->i_blksize = NCP_BLOCK_SIZE;
 	inode->i_rdev = 0;
 
 	inode->i_blocks = 0;
@@ -219,36 +212,10 @@
 }
 
 /*
- * This is called from iget() with the read semaphore held. 
- * The global ncpfs_file_info structure has been set up by ncp_iget.
- */
-static void ncp_read_inode(struct inode *inode)
-{
-	if (read_nwinfo == NULL) {
-		printk(KERN_ERR "ncp_read_inode: invalid call\n");
-		return;
-	}
-
-	ncp_set_attr(inode, read_nwinfo);
-
-	if (S_ISREG(inode->i_mode)) {
-		inode->i_op = &ncp_file_inode_operations;
-	} else if (S_ISDIR(inode->i_mode)) {
-		inode->i_op = &ncp_dir_inode_operations;
-#ifdef CONFIG_NCPFS_EXTRAS
-	} else if (S_ISLNK(inode->i_mode)) {
-		inode->i_op = &ncp_symlink_inode_operations;
-#endif
-	} else {
-		inode->i_op = NULL;
-	}
-}
-
-/*
- * Set up the ncpfs_inode_info pointer and get a new inode.
+ * Get a new inode.
  */
 struct inode * 
-ncp_iget(struct super_block *sb, struct ncpfs_inode_info *info)
+ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
 {
 	struct inode *inode;
 
@@ -257,12 +224,23 @@
 		return NULL;
 	}
 
-	down(&read_sem);
-	read_nwinfo = &info->nw_info;
-	inode = iget(sb, info->ino);
-	read_nwinfo = NULL;
-	up(&read_sem);
-	if (!inode)
+	inode = get_empty_inode();
+	if (inode) {
+		inode->i_sb = sb;
+		inode->i_dev = sb->s_dev;
+		inode->i_ino = info->ino;
+		ncp_set_attr(inode, info);
+		if (S_ISREG(inode->i_mode)) {
+			inode->i_op = &ncp_file_inode_operations;
+		} else if (S_ISDIR(inode->i_mode)) {
+			inode->i_op = &ncp_dir_inode_operations;
+#ifdef CONFIG_NCPFS_EXTRAS
+		} else if (S_ISLNK(inode->i_mode)) {
+			inode->i_op = &ncp_symlink_inode_operations;
+#endif
+		}
+		insert_inode_hash(inode);
+	} else
 		printk(KERN_ERR "ncp_iget: iget failed!\n");
 	return inode;
 }
@@ -278,7 +256,6 @@
 {
 	if (S_ISDIR(inode->i_mode)) {
 		DDPRINTK(KERN_DEBUG "ncp_delete_inode: put directory %ld\n", inode->i_ino);
-		ncp_invalid_dir_cache(inode);
 	}
 
 	if (NCP_FINFO(inode)->opened && ncp_make_closed(inode) != 0) {
@@ -288,34 +265,6 @@
 	clear_inode(inode);
 }
 
-static void ncp_init_root(struct ncp_server *server,
-			struct ncpfs_inode_info *info)
-{
-	struct ncp_inode_info *root = &(server->root);
-	struct nw_info_struct *i = &(root->finfo.i);
-
-	DPRINTK(KERN_DEBUG "ncp_init_root: i = %x\n", (int) i);
-
-	i->attributes	 = aDIR;
-	i->dataStreamSize= 1024;
-	i->dirEntNum	 = 0;
-	i->DosDirNum	 = 0;
-#ifdef CONFIG_NCPFS_SMALLDOS
-	i->NSCreator	 = NW_NS_DOS;
-#endif
-	i->volNumber	 = NCP_NUMBER_OF_VOLUMES + 1;	/* illegal volnum */
-	/* set dates of mountpoint to Jan 1, 1986; 00:00 */
-	i->creationTime = i->modifyTime = cpu_to_le16(0x0000);
-	i->creationDate = i->modifyDate = i->lastAccessDate = cpu_to_le16(0x0C21);
-	i->nameLen	 = 0;
-	i->entryName[0]  = '\0';
-
-	root->finfo.opened= 0;
-	info->ino = 2; /* tradition */
-	info->nw_info = root->finfo;
-	return;
-}
-
 struct super_block *
 ncp_read_super(struct super_block *sb, void *raw_data, int silent)
 {
@@ -328,7 +277,7 @@
 #ifdef CONFIG_NCPFS_PACKET_SIGNING
 	int options;
 #endif
-	struct ncpfs_inode_info finfo;
+	struct ncp_entry_info finfo;
 
 	MOD_INC_USE_COUNT;
 	if (data == NULL)
@@ -349,13 +298,8 @@
 	sb->s_dev = dev;
 	sb->s_op = &ncp_sops;
 
-	/* We must malloc our own super-block info */
-	server = (struct ncp_server *) ncp_kmalloc(sizeof(struct ncp_server),
-						   GFP_KERNEL);
-	if (server == NULL)
-		goto out_no_server;
+	server = NCP_SBP(sb);
 	memset(server, 0, sizeof(*server));
-	NCP_SBP(sb) = server;
 
 	server->ncp_filp = ncp_filp;
 /*	server->lock = 0;	*/
@@ -390,12 +334,12 @@
 
 #ifdef CONFIG_NCPFS_NLS
 	/* load the default NLS charsets */
-	server->nls_charsets.codepage[0] = 0;
-	server->nls_charsets.iocharset[0] = 0;
 	server->nls_vol = load_nls_default();
 	server->nls_io = load_nls_default();
 #endif /* CONFIG_NCPFS_NLS */
 
+	server->dentry_ttl = 0;	/* no caching */
+
 	server->packet_size = NCP_PACKET_SIZE;
 	server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
 	if (server->packet == NULL)
@@ -433,16 +377,36 @@
 		goto out_no_bufsize;
 	DPRINTK(KERN_DEBUG "ncpfs: bufsize = %d\n", server->buffer_size);
 
-	ncp_init_root(server, &finfo);
-	server->name_space[finfo.nw_info.i.volNumber] = NW_NS_DOS;
+	memset(&finfo, 0, sizeof(finfo));
+	finfo.i.attributes	= aDIR;
+	finfo.i.dataStreamSize	= NCP_BLOCK_SIZE;
+	finfo.i.dirEntNum	= 0;
+	finfo.i.DosDirNum	= 0;
+#ifdef CONFIG_NCPFS_SMALLDOS
+	finfo.i.NSCreator	= NW_NS_DOS;
+#endif
+	finfo.i.volNumber	= NCP_NUMBER_OF_VOLUMES + 1;	/* illegal volnum */
+	/* set dates of mountpoint to Jan 1, 1986; 00:00 */
+	finfo.i.creationTime	= finfo.i.modifyTime
+				= cpu_to_le16(0x0000);
+	finfo.i.creationDate	= finfo.i.modifyDate
+				= finfo.i.lastAccessDate
+				= cpu_to_le16(0x0C21);
+	finfo.i.nameLen		= 0;
+	finfo.i.entryName[0]	= '\0';
+
+	finfo.opened		= 0;
+	finfo.ino		= 2;	/* tradition */
+
+	server->name_space[finfo.i.volNumber] = NW_NS_DOS;
         root_inode = ncp_iget(sb, &finfo);
         if (!root_inode)
 		goto out_no_root;
 	DPRINTK(KERN_DEBUG "ncp_read_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
-        server->root_dentry = sb->s_root = d_alloc_root(root_inode);
+	sb->s_root = d_alloc_root(root_inode);
         if (!sb->s_root)
 		goto out_no_root;
-	server->root_dentry->d_op = &ncp_dentry_operations;
+	sb->s_root->d_op = &ncp_dentry_operations;
 	unlock_super(sb);
 	return sb;
 
@@ -469,11 +433,6 @@
 	unload_nls(server->nls_io);
 	unload_nls(server->nls_vol);
 #endif
-	ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
-	goto out_unlock;
-out_no_server:
-	printk(KERN_ERR "ncp_read_super: could not alloc ncp_server\n");
-out_unlock:
 	/* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
 	 * 
 	 * The previously used put_filp(ncp_filp); was bogous, since
@@ -531,8 +490,6 @@
 		ncp_kfree_s(server->auth.object_name, server->auth.object_name_len);
 	ncp_kfree_s(server->packet, server->packet_size);
 
-	ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
-
 	MOD_DEC_USE_COUNT;
 }
 
@@ -547,7 +504,7 @@
 	   here is to err conservatively. */
 
 	tmp.f_type = NCP_SUPER_MAGIC;
-	tmp.f_bsize = 512;
+	tmp.f_bsize = NCP_BLOCK_SIZE;
 	tmp.f_blocks = 0;
 	tmp.f_bfree = 0;
 	tmp.f_bavail = 0;
@@ -571,6 +528,9 @@
 	if ((!server) || !ncp_conn_valid(server))
 		goto out;
 
+	/* ageing the dentry to force validation */
+	ncp_age_dentry(server, dentry);
+
 	result = inode_change_ok(inode, attr);
 	if (result < 0)
 		goto out;
@@ -703,7 +663,6 @@
 		   closing the file */
 		result = ncp_make_closed(inode);
 	}
-	ncp_invalid_dir_cache(dentry->d_parent->d_inode);
 out:
 	return result;
 }
@@ -732,22 +691,16 @@
 {
 	DPRINTK(KERN_DEBUG "ncpfs: init_module called\n");
 
-	init_MUTEX(&read_sem);
-	read_nwinfo = NULL;
-
 #ifdef DEBUG_NCP_MALLOC
 	ncp_malloced = 0;
 	ncp_current_malloced = 0;
 #endif
-	ncp_init_dir_cache();
-
 	return init_ncp_fs();
 }
 
 void cleanup_module(void)
 {
 	DPRINTK(KERN_DEBUG "ncpfs: cleanup_module called\n");
-	ncp_free_dir_cache();
 	unregister_filesystem(&ncp_fs_type);
 #ifdef DEBUG_NCP_MALLOC
 	printk(KERN_DEBUG "ncp_malloced: %d\n", ncp_malloced);
diff -u --recursive --new-file v2.3.19/linux/fs/ncpfs/ioctl.c linux/fs/ncpfs/ioctl.c
--- v2.3.19/linux/fs/ncpfs/ioctl.c	Wed May 26 09:27:16 1999
+++ linux/fs/ncpfs/ioctl.c	Thu Oct  7 10:17:09 1999
@@ -16,7 +16,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 
-#include <linux/ncp.h>
 #include <linux/ncp_fs.h>
 
 #include "ncplib_kernel.h"
@@ -110,7 +109,7 @@
 		}
 		if (server->root_setuped) return -EBUSY;
 		server->root_setuped = 1;
-		return ncp_conn_logged_in(server);
+		return ncp_conn_logged_in(inode->i_sb);
 
 	case NCP_IOC_GET_FS_INFO:
 
@@ -162,9 +161,19 @@
 				return -EACCES;
 			}
 			if (server->m.mounted_vol[0]) {
-				sr.volNumber = server->root.finfo.i.volNumber;
-				sr.dirEntNum = server->root.finfo.i.dirEntNum;
-				sr.namespace = server->name_space[sr.volNumber];
+				struct dentry* dentry = inode->i_sb->s_root;
+
+				if (dentry) {
+					struct inode* inode = dentry->d_inode;
+				
+					if (inode) {
+						sr.volNumber = NCP_FINFO(inode)->volNumber;
+						sr.dirEntNum = NCP_FINFO(inode)->dirEntNum;
+						sr.namespace = server->name_space[sr.volNumber];
+					} else
+						DPRINTK(KERN_DEBUG "ncpfs: s_root->d_inode==NULL\n");
+				} else
+					DPRINTK(KERN_DEBUG "ncpfs: s_root==NULL\n");
 			} else {
 				sr.volNumber = -1;
 				sr.namespace = 0;
@@ -178,6 +187,7 @@
 	case NCP_IOC_SETROOT:
 		{
 			struct ncp_setroot_ioctl sr;
+			struct nw_info_struct i;
 			struct dentry* dentry;
 
 			if (   (permission(inode, MAY_WRITE) != 0)
@@ -191,31 +201,30 @@
 					   sizeof(sr))) return -EFAULT;
 			if (sr.volNumber < 0) {
 				server->m.mounted_vol[0] = 0;
-				server->root.finfo.i.volNumber = NCP_NUMBER_OF_VOLUMES + 1;
-				server->root.finfo.i.dirEntNum = 0;
-				server->root.finfo.i.DosDirNum = 0;
+				i.volNumber = NCP_NUMBER_OF_VOLUMES + 1;
+				i.dirEntNum = 0;
+				i.DosDirNum = 0;
 			} else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) {
 				return -EINVAL;
-			} else {
-				if (ncp_mount_subdir(server, sr.volNumber, sr.namespace, sr.dirEntNum)) {
+			} else
+				if (ncp_mount_subdir(server, &i, sr.volNumber,
+						sr.namespace, sr.dirEntNum))
 					return -ENOENT;
-				}
-			}
-			dentry = server->root_dentry;
+
+			dentry = inode->i_sb->s_root;
 			server->root_setuped = 1;
 			if (dentry) {
 				struct inode* inode = dentry->d_inode;
 				
 				if (inode) {
-					NCP_FINFO(inode)->volNumber = server->root.finfo.i.volNumber;
-					NCP_FINFO(inode)->dirEntNum = server->root.finfo.i.dirEntNum;
-					NCP_FINFO(inode)->DosDirNum = server->root.finfo.i.DosDirNum;
-				} else {
-					DPRINTK(KERN_DEBUG "ncpfs: root_dentry->d_inode==NULL\n");
-				}
-			} else {
-				DPRINTK(KERN_DEBUG "ncpfs: root_dentry==NULL\n");
-			}
+					NCP_FINFO(inode)->volNumber = i.volNumber;
+					NCP_FINFO(inode)->dirEntNum = i.dirEntNum;
+					NCP_FINFO(inode)->DosDirNum = i.DosDirNum;
+				} else
+					DPRINTK(KERN_DEBUG "ncpfs: s_root->d_inode==NULL\n");
+			} else
+				DPRINTK(KERN_DEBUG "ncpfs: s_root==NULL\n");
+
 			return 0;
 		}
 #endif	/* CONFIG_NCPFS_MOUNT_SUBDIR */
@@ -503,12 +512,12 @@
  * Thanks Petr Vandrovec for idea and many hints.
  */
 	case NCP_IOC_SETCHARSETS:
-		if (   (permission(inode, MAY_WRITE) != 0)
-		    && (current->uid != server->m.mounted_uid))
-		{
+		if ((permission(inode, MAY_WRITE) != 0) &&
+				 (current->uid != server->m.mounted_uid))
 			return -EACCES;
-		}
-		if (server->root_setuped) return -EBUSY;
+		if (server->root_setuped)
+			return -EBUSY;
+
 		{
 			struct ncp_nls_ioctl user;
 			struct nls_table *codepage;
@@ -516,28 +525,28 @@
 			struct nls_table *oldset_io;
 			struct nls_table *oldset_cp;
 			
-			if (copy_from_user(&user, 
-					   (struct ncp_nls_ioctl*)arg,
-					    sizeof(user))) return -EFAULT;
+			if (copy_from_user(&user, (struct ncp_nls_ioctl*)arg,
+					sizeof(user)))
+				return -EFAULT;
 
 			codepage = NULL;
-			if (!user.codepage[0]) {
+			user.codepage[NCP_IOCSNAME_LEN] = 0;
+			if (!user.codepage[0])
 				codepage = load_nls_default();
-			}
 			else {
 				codepage = load_nls(user.codepage);
-				if (! codepage) {
+				if (!codepage) {
 					return -EBADRQC;
 				}
 			}
 
 			iocharset = NULL;
-			if (user.iocharset[0] == 0) {
+			user.iocharset[NCP_IOCSNAME_LEN] = 0;
+			if (user.iocharset[0] == 0)
 				iocharset = load_nls_default();
-			}
 			else {
 				iocharset = load_nls(user.iocharset);
-				if (! iocharset) {
+				if (!iocharset) {
 					unload_nls(codepage);
 					return -EBADRQC;
 				}
@@ -547,18 +556,80 @@
 			server->nls_vol = codepage;
 			oldset_io = server->nls_io;
 			server->nls_io = iocharset;
-			server->nls_charsets = user;
-			if (oldset_cp) unload_nls(oldset_cp);
-			if (oldset_io) unload_nls(oldset_io);
+
+			if (oldset_cp)
+				unload_nls(oldset_cp);
+			if (oldset_io)
+				unload_nls(oldset_io);
+
 			return 0;
 		}
 		
 	case NCP_IOC_GETCHARSETS: /* not tested */
-		if (copy_to_user((struct ncp_nls_ioctl*)arg,
-				&(server->nls_charsets),
-				sizeof(server->nls_charsets))) return -EFAULT;
-		return 0;
+		{
+			struct ncp_nls_ioctl user;
+
+			memset(&user, 0, sizeof(user));
+			if (server->nls_vol)
+				if (server->nls_vol->charset) {
+					strncpy(user.codepage,
+						server->nls_vol->charset,
+						NCP_IOCSNAME_LEN);
+					user.codepage[NCP_IOCSNAME_LEN] = 0;
+					if (!strcmp(user.codepage, "default"))
+						/* unfortunately, we cannot set
+						   'default' charset... maybe
+						   we should change load_nls()?
+						   It is easy, do not initialize
+						   'tables' in fs/nls/nls_base.c
+						   with NULL, but with
+						   'default_table'... */
+						memset(user.codepage, 0,
+							sizeof(user.codepage));
+				}
+
+			if (server->nls_io)
+				if (server->nls_io->charset) {
+					strncpy(user.iocharset,
+						server->nls_io->charset,
+						NCP_IOCSNAME_LEN);
+					user.iocharset[NCP_IOCSNAME_LEN] = 0;
+					if (!strcmp(user.iocharset, "default"))
+						memset(user.iocharset, 0,
+							sizeof(user.iocharset));
+				}
+
+			if (copy_to_user((struct ncp_nls_ioctl*)arg, &user,
+					sizeof(user)))
+				return -EFAULT;
+
+			return 0;
+		}
 #endif /* CONFIG_NCPFS_NLS */
+	case NCP_IOC_SETDENTRYTTL:
+		if ((permission(inode, MAY_WRITE) != 0) &&
+				 (current->uid != server->m.mounted_uid))
+			return -EACCES;
+		{
+			u_int32_t user;
+
+			if (copy_from_user(&user, (u_int32_t*)arg, sizeof(user)))
+				return -EFAULT;
+			/* 20 secs at most... */
+			if (user > 20000)
+				return -EINVAL;
+			user = (user * HZ) / 1000;
+			server->dentry_ttl = user;
+			return 0;
+		}
+		
+	case NCP_IOC_GETDENTRYTTL:
+		{
+			u_int32_t user = (server->dentry_ttl * 1000) / HZ;
+			if (copy_to_user((u_int32_t*)arg, &user, sizeof(user)))
+				return -EFAULT;
+			return 0;
+		}
 
 	default:
 		return -EINVAL;
diff -u --recursive --new-file v2.3.19/linux/fs/ncpfs/ncplib_kernel.c linux/fs/ncpfs/ncplib_kernel.c
--- v2.3.19/linux/fs/ncpfs/ncplib_kernel.c	Fri May 14 12:43:00 1999
+++ linux/fs/ncpfs/ncplib_kernel.c	Thu Oct  7 10:17:09 1999
@@ -148,7 +148,7 @@
 	int result;
 
 	/* there is minimum */
-	if (size < 512) size = 512;
+	if (size < NCP_BLOCK_SIZE) size = NCP_BLOCK_SIZE;
 
 	ncp_init_request(server);
 	ncp_add_word(server, htons(size));
@@ -162,7 +162,7 @@
 
 	/* NCP over UDP returns 0 (!!!) */
 	result = ntohs(ncp_reply_word(server, 0));
-	if (result >= 512) size=min(result, size);
+	if (result >= NCP_BLOCK_SIZE) size=min(result, size);
 	*ret_size = size;
 	*ret_options = ncp_reply_byte(server, 4);
 
@@ -264,7 +264,7 @@
 	memcpy(target, structure, info_struct_size);
 	name_len = structure + info_struct_size;
 	target->nameLen = *name_len;
-	strncpy(target->entryName, name_len + 1, *name_len);
+	memcpy(target->entryName, name_len + 1, *name_len);
 	target->entryName[*name_len] = '\0';
 	return;
 }
@@ -406,9 +406,8 @@
 }
 
 int
-ncp_mount_subdir(struct ncp_server *server,
-		__u8 volNumber,
-		__u8 srcNS, __u32 dirEntNum)
+ncp_mount_subdir(struct ncp_server *server, struct nw_info_struct *i,
+			__u8 volNumber, __u8 srcNS, __u32 dirEntNum)
 {
 	int dstNS;
 	int result;
@@ -422,9 +421,9 @@
 		return result;
 	}
 	server->name_space[volNumber] = dstNS;
-	server->root.finfo.i.volNumber = volNumber;
-	server->root.finfo.i.dirEntNum = newDirEnt;
-	server->root.finfo.i.DosDirNum = newDosEnt;
+	i->volNumber = volNumber;
+	i->dirEntNum = newDirEnt;
+	i->DosDirNum = newDosEnt;
 	server->m.mounted_vol[1] = 0;
 	server->m.mounted_vol[0] = 'X';
 	return 0;
@@ -467,7 +466,7 @@
 		volnum, server->name_space[volnum]);
 
 	target->nameLen = strlen(volname);
-	strcpy(target->entryName, volname);
+	memcpy(target->entryName, volname, target->nameLen+1);
 	target->attributes = aDIR;
 	/* set dates to Jan 1, 1986  00:00 */
 	target->creationTime = target->modifyTime = cpu_to_le16(0x0000);
@@ -583,7 +582,7 @@
 				   int open_create_mode,
 				   __u32 create_attributes,
 				   int desired_acc_rights,
-				   struct nw_file_info *target)
+				   struct ncp_entry_info *target)
 {
 	__u16 search_attribs = ntohs(0x0600);
 	__u8  volnum = target->i.volNumber;
diff -u --recursive --new-file v2.3.19/linux/fs/ncpfs/ncplib_kernel.h linux/fs/ncpfs/ncplib_kernel.h
--- v2.3.19/linux/fs/ncpfs/ncplib_kernel.h	Fri May 14 12:43:00 1999
+++ linux/fs/ncpfs/ncplib_kernel.h	Thu Oct  7 10:17:09 1999
@@ -5,6 +5,7 @@
  *  Modified for big endian by J.F. Chadima and David S. Miller
  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
  *  Modified 1998 Wolfram Pienkoss for NLS
+ *  Modified 1999 Wolfram Pienkoss for directory caching
  *
  */
 
@@ -19,6 +20,8 @@
 #include <linux/malloc.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
+#include <linux/pagemap.h>
+
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
@@ -28,13 +31,13 @@
 #include <linux/nls.h>
 #endif
 
-#include <linux/ncp.h>
 #include <linux/ncp_fs.h>
-#include <linux/ncp_fs_sb.h>
 
 #define NCP_MIN_SYMLINK_SIZE	8
 #define NCP_MAX_SYMLINK_SIZE	512
 
+#define NCP_BLOCK_SIZE		512
+
 int ncp_negotiate_buffersize(struct ncp_server *, int, int *);
 int ncp_negotiate_size_and_options(struct ncp_server *server, int size,
   			  int options, int *ret_size, int *ret_options);
@@ -62,7 +65,7 @@
 int ncp_del_file_or_subdir2(struct ncp_server *, struct dentry*);
 int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, char *);
 int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, char *,
-			       int, __u32, int, struct nw_file_info *);
+				int, __u32, int, struct ncp_entry_info *);
 
 int ncp_initialize_search(struct ncp_server *, struct inode *,
 		      struct nw_search_sequence *target);
@@ -88,8 +91,8 @@
 
 #ifdef CONFIG_NCPFS_MOUNT_SUBDIR
 int
-ncp_mount_subdir(struct ncp_server* server, __u8 volNumber, 
-		 __u8 srcNS, __u32 srcDirEntNum);
+ncp_mount_subdir(struct ncp_server *, struct nw_info_struct *,
+			__u8, __u8, __u32);
 #endif	/* CONFIG_NCPFS_MOUNT_SUBDIR */
 
 #ifdef CONFIG_NCPFS_NLS
@@ -169,5 +172,37 @@
 
 #endif /* CONFIG_NCPFS_NLS */
 
-#endif /* _NCPLIB_H */
+#define NCP_GET_AGE(dentry)	(jiffies - (dentry)->d_time)
+#define NCP_MAX_AGE		(server->dentry_ttl)
+#define NCP_TEST_AGE(server,dentry)	(NCP_GET_AGE(dentry) < NCP_MAX_AGE)
 
+static inline void
+ncp_age_dentry(struct ncp_server* server, struct dentry* dentry)
+{
+	dentry->d_time = jiffies - server->dentry_ttl;
+}
+
+static inline void
+ncp_new_dentry(struct dentry* dentry)
+{
+	dentry->d_time = jiffies;
+}
+
+#define NCP_FPOS_EMPTY	0	/* init value for fpos variables. */
+
+struct ncp_cache_control {
+	struct nw_search_sequence seq;
+	int		firstcache;
+	int		currentpos;
+	int		cachehead;
+	int		cachetail;
+	int		eof;
+};
+
+#define NCP_DIRCACHE_SIZE	(PAGE_CACHE_SIZE-sizeof(struct ncp_cache_control))
+struct ncp_seq_cache {
+	struct ncp_cache_control ctl;
+	unsigned char cache[NCP_DIRCACHE_SIZE];
+};
+
+#endif /* _NCPLIB_H */
diff -u --recursive --new-file v2.3.19/linux/fs/ncpfs/ncpsign_kernel.h linux/fs/ncpfs/ncpsign_kernel.h
--- v2.3.19/linux/fs/ncpfs/ncpsign_kernel.h	Tue Mar 17 11:53:16 1998
+++ linux/fs/ncpfs/ncpsign_kernel.h	Thu Oct  7 10:17:09 1999
@@ -9,7 +9,6 @@
 #define _NCPSIGN_KERNEL_H
 
 #include <linux/ncp_fs.h>
-#include <linux/ncp_fs_sb.h>
 
 void sign_packet(struct ncp_server *server, int *size);
 
diff -u --recursive --new-file v2.3.19/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v2.3.19/linux/fs/ncpfs/sock.c	Tue Sep  7 12:14:07 1999
+++ linux/fs/ncpfs/sock.c	Thu Oct  7 10:17:09 1999
@@ -27,9 +27,7 @@
 #include <linux/poll.h>
 #include <linux/file.h>
 
-#include <linux/ncp.h>
 #include <linux/ncp_fs.h>
-#include <linux/ncp_fs_sb.h>
 
 #ifdef CONFIG_NCPFS_PACKET_SIGNING
 #include "ncpsign_kernel.h"
diff -u --recursive --new-file v2.3.19/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- v2.3.19/linux/fs/nfsd/nfsfh.c	Tue Jun  8 10:47:58 1999
+++ linux/fs/nfsd/nfsfh.c	Thu Oct  7 10:17:09 1999
@@ -824,7 +824,7 @@
 printk("lookup_by_inode: found %s\n", dirent.name);
 #endif
 
-	dentry = lookup_dentry(dirent.name, dget(parent), 0);
+	dentry = lookup_dentry(dirent.name, parent, 0);
 	if (!IS_ERR(dentry)) {
 		if (dentry->d_inode && dentry->d_inode->i_ino == ino)
 			goto out;
@@ -1007,7 +1007,7 @@
 		/*
 		 * ... then search for the inode in the parent directory.
 		 */
-		dentry = lookup_by_inode(parent, u32_to_ino_t(fh->fh_ino));
+		dentry = lookup_by_inode(dget(parent), u32_to_ino_t(fh->fh_ino));
 		dput(parent);
 		if (dentry)
 			goto out;
diff -u --recursive --new-file v2.3.19/linux/fs/open.c linux/fs/open.c
--- v2.3.19/linux/fs/open.c	Thu Aug 26 13:05:40 1999
+++ linux/fs/open.c	Thu Oct  7 10:17:09 1999
@@ -526,10 +526,13 @@
 	 * non-root user, remove the setuid bit.
 	 * 19981026	David C Niemi <niemi@tux.org>
 	 *
+	 * Changed this to apply to all users, including root, to avoid
+	 * some races. This is the behavior we had in 2.0. The check for
+	 * non-root was definitely wrong for 2.2 anyway, as it should
+	 * have been using CAP_FSETID rather than fsuid -- 19990830 SD.
 	 */
 	if ((inode->i_mode & S_ISUID) == S_ISUID &&
-		!S_ISDIR(inode->i_mode)
-		&& current->fsuid) 
+		!S_ISDIR(inode->i_mode))
 	{
 		newattrs.ia_mode &= ~S_ISUID;
 		newattrs.ia_valid |= ATTR_MODE;
@@ -539,9 +542,11 @@
 	 * by a non-root user, remove the setgid bit UNLESS there is no group
 	 * execute bit (this would be a file marked for mandatory locking).
 	 * 19981026	David C Niemi <niemi@tux.org>
+	 *
+	 * Removed the fsuid check (see the comment above) -- 19990830 SD.
 	 */
 	if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) 
-		&& !S_ISDIR(inode->i_mode) && current->fsuid) 
+		&& !S_ISDIR(inode->i_mode))
 	{
 		newattrs.ia_mode &= ~S_ISGID;
 		newattrs.ia_valid |= ATTR_MODE;
diff -u --recursive --new-file v2.3.19/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.3.19/linux/fs/sysv/inode.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/sysv/inode.c	Thu Oct  7 10:17:09 1999
@@ -517,6 +517,9 @@
 		unlock_super(sb);
 		return NULL;
 	}
+#ifndef CONFIG_SYSV_FS_WRITE
+	sb->s_flags |= MS_RDONLY;
+#endif
 	unlock_super(sb);
 	sb->s_dirt = 1;
 	/* brelse(bh);  resp.  brelse(bh1); brelse(bh2);
@@ -912,15 +915,15 @@
 	return err;
 
 abort_negative:
-	printk("sysv_getblk: block < 0\n");
+	printk("sysv_get_block: block < 0\n");
 	goto abort;
 
 abort_too_big:
-	printk("sysv_getblk: block > big\n");
+	printk("sysv_get_block: block > big\n");
 	goto abort;
 }
 
-struct buffer_head *sysv_getblk(struct inode *inode, unsigned int block, int create)
+static struct buffer_head *sysv_getblk(struct inode *inode, unsigned int block, int create)
 {
 	struct buffer_head dummy;
 	int error;
@@ -930,9 +933,9 @@
 	error = sysv_get_block(inode, block, &dummy, create);
 	if (!error && buffer_mapped(&dummy)) {
 		struct buffer_head *bh;
-		bh = getblk(dummy.b_dev, dummy.b_blocknr, BLOCK_SIZE);
+		bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->sv_block_size);
 		if (buffer_new(&dummy)) {
-			memset(bh->b_data, 0, BLOCK_SIZE);
+			memset(bh->b_data, 0, inode->i_sb->sv_block_size);
 			mark_buffer_uptodate(bh, 1);
 			mark_buffer_dirty(bh, 1);
 		}
@@ -1168,18 +1171,16 @@
 
 /* Every kernel module contains stuff like this. */
 
-static struct file_system_type sysv_fs_type[3] = {
-	{"xenix",    FS_REQUIRES_DEV, sysv_read_super, NULL},
-	{"sysv",     FS_REQUIRES_DEV, sysv_read_super, NULL},
-	{"coherent", FS_REQUIRES_DEV, sysv_read_super, NULL}
+static struct file_system_type sysv_fs_type[] = {
+	{"sysv",     FS_REQUIRES_DEV, sysv_read_super, NULL}
 };
 
 int __init init_sysv_fs(void)
 {
 	int i;
-	int ouch;
+	int ouch = 0;
 
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < sizeof(sysv_fs_type)/sizeof(sysv_fs_type[0]); i++) {
 		if ((ouch = register_filesystem(&sysv_fs_type[i])) != 0)
 			break;
 	}
@@ -1198,7 +1199,7 @@
 {
 	int i;
 
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < sizeof(sysv_fs_type)/sizeof(sysv_fs_type[0]); i++)
 		/* No error message if this breaks... that's OK... */
 		unregister_filesystem(&sysv_fs_type[i]);
 }
diff -u --recursive --new-file v2.3.19/linux/fs/udf/inode.c linux/fs/udf/inode.c
--- v2.3.19/linux/fs/udf/inode.c	Tue Sep  7 12:14:07 1999
+++ linux/fs/udf/inode.c	Thu Oct  7 10:17:09 1999
@@ -917,7 +917,7 @@
 	
 	inode->i_size = le64_to_cpu(fe->informationLength);
 #if BITS_PER_LONG < 64
-	if (le64_to_cpu(fe->informationLength) & 0xFFFFFFFF00000000)
+	if (le64_to_cpu(fe->informationLength) & 0xFFFFFFFF00000000ULL)
 		inode->i_size = (Uint32)-1;
 #endif
 
diff -u --recursive --new-file v2.3.19/linux/include/asm-i386/apic.h linux/include/asm-i386/apic.h
--- v2.3.19/linux/include/asm-i386/apic.h	Sun Jul 25 10:26:01 1999
+++ linux/include/asm-i386/apic.h	Thu Oct  7 10:17:09 1999
@@ -10,7 +10,10 @@
  
 #define		APIC_ID		0x20
 #define			GET_APIC_ID(x)		(((x)>>24)&0x0F)
-#define		APIC_VERSION	0x30
+#define		APIC_LVR	0x30
+#define			GET_APIC_VERSION(x)	((x)&0xFF)
+#define			GET_APIC_MAXLVT(x)	(((x)>>16)&0x0F)
+#define			APIC_INTEGRATED(x)	((x)&0xF0)
 #define		APIC_TASKPRI	0x80
 #define			APIC_TPRI_MASK		0xFF
 #define		APIC_ARBPRI	0x90
@@ -23,6 +26,7 @@
 #define			APIC_LDR_MASK		(0xFF<<24)
 #define			GET_APIC_LOGICAL_ID(x)	(((x)>>24)&0xFF)
 #define			SET_APIC_LOGICAL_ID(x)	(((x)<<24))
+#define			APIC_ALL_CPUS		0xFF
 #define		APIC_DFR	0xE0
 #define			GET_APIC_DFR(x)		(((x)>>28)&0x0F)
 #define			SET_APIC_DFR(x)		((x)<<28)
@@ -62,7 +66,14 @@
 #define			GET_APIC_DEST_FIELD(x)	(((x)>>24)&0xFF)
 #define			SET_APIC_DEST_FIELD(x)	((x)<<24)
 #define		APIC_LVTT	0x320
+#define		APIC_LVTPC	0x340
 #define		APIC_LVT0	0x350
+#define			APIC_LVT_TIMER_BASE_MASK	(0x3<<18)
+#define			GET_APIC_TIMER_BASE(x)		(((x)>>18)&0x3)
+#define			SET_APIC_TIMER_BASE(x)		(((x)<<18))
+#define			APIC_TIMER_BASE_CLKIN		0x0
+#define			APIC_TIMER_BASE_TMBASE		0x1
+#define			APIC_TIMER_BASE_DIV		0x2
 #define			APIC_LVT_TIMER_PERIODIC		(1<<17)
 #define			APIC_LVT_MASKED			(1<<16)
 #define			APIC_LVT_LEVEL_TRIGGER		(1<<15)
@@ -75,10 +86,11 @@
 #define				APIC_MODE_NMI		0x4
 #define				APIC_MODE_EXINT		0x7
 #define 	APIC_LVT1	0x360
-#define		APIC_LVERR	0x370
+#define		APIC_LVTERR	0x370
 #define		APIC_TMICT	0x380
 #define		APIC_TMCCT	0x390
 #define		APIC_TDCR	0x3E0
+#define			APIC_TDR_DIV_TMBASE	(1<<2)
 #define			APIC_TDR_DIV_1		0xB
 #define			APIC_TDR_DIV_2		0x0
 #define			APIC_TDR_DIV_4		0x1
@@ -91,5 +103,256 @@
 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
 
 #define MAX_IO_APICS 8
+
+/*
+ * the local APIC register structure, memory mapped. Not terribly well
+ * tested, but we might eventually use this one in the future - the
+ * problem why we cannot use it right now is the P5 APIC, it has an
+ * errata which cannot take 8-bit reads and writes, only 32-bit ones ...
+ */
+#define u32 unsigned int
+
+#define lapic ((volatile struct local_apic *)APIC_BASE)
+
+struct local_apic {
+
+/*000*/	struct { u32 __reserved[4]; } __reserved_01;
+
+/*010*/	struct { u32 __reserved[4]; } __reserved_02;
+
+/*020*/	struct { /* APIC ID Register */
+		u32   __reserved_1	: 24,
+			phys_apic_id	:  4,
+			__reserved_2	:  4;
+		u32 __reserved[3];
+	} id;
+
+/*030*/	const
+	struct { /* APIC Version Register */
+		u32   version		:  8,
+			__reserved_1	:  8,
+			max_lvt		:  8,
+			__reserved_2	:  8;
+		u32 __reserved[3];
+	} version;
+
+/*040*/	struct { u32 __reserved[4]; } __reserved_03;
+
+/*050*/	struct { u32 __reserved[4]; } __reserved_04;
+
+/*060*/	struct { u32 __reserved[4]; } __reserved_05;
+
+/*070*/	struct { u32 __reserved[4]; } __reserved_06;
+
+/*080*/	struct { /* Task Priority Register */
+		u32   priority	:  8,
+			__reserved_1	: 24;
+		u32 __reserved_2[3];
+	} tpr;
+
+/*090*/	const
+	struct { /* Arbitration Priority Register */
+		u32   priority	:  8,
+			__reserved_1	: 24;
+		u32 __reserved_2[3];
+	} apr;
+
+/*0A0*/	const
+	struct { /* Processor Priority Register */
+		u32   priority	:  8,
+			__reserved_1	: 24;
+		u32 __reserved_2[3];
+	} ppr;
+
+/*0B0*/	struct { /* End Of Interrupt Register */
+		u32   eoi;
+		u32 __reserved[3];
+	} eoi;
+
+/*0C0*/	struct { u32 __reserved[4]; } __reserved_07;
+
+/*0D0*/	struct { /* Logical Destination Register */
+		u32   __reserved_1	: 24,
+			logical_dest	:  8;
+		u32 __reserved_2[3];
+	} ldr;
+
+/*0E0*/	struct { /* Destination Format Register */
+		u32   __reserved_1	: 28,
+			model		:  4;
+		u32 __reserved_2[3];
+	} dfr;
+
+/*0F0*/	struct { /* Spurious Interrupt Vector Register */
+		u32	spurious_vector	:  8,
+			apic_enabled	:  1,
+			focus_cpu	:  1,
+			__reserved_2	: 22;
+		u32 __reserved_3[3];
+	} svr;
+
+/*100*/	struct { /* In Service Register */
+/*170*/		u32 bitfield;
+		u32 __reserved[3];
+	} isr [8];
+
+/*180*/	struct { /* Trigger Mode Register */
+/*1F0*/		u32 bitfield;
+		u32 __reserved[3];
+	} tmr [8];
+
+/*200*/	struct { /* Interrupt Request Register */
+/*270*/		u32 bitfield;
+		u32 __reserved[3];
+	} irr [8];
+
+/*280*/	union { /* Error Status Register */
+		struct {
+			u32   send_cs_error			:  1,
+				receive_cs_error		:  1,
+				send_accept_error		:  1,
+				receive_accept_error		:  1,
+				__reserved_1			:  1,
+				send_illegal_vector		:  1,
+				receive_illegal_vector		:  1,
+				illegal_register_address	:  1,
+				__reserved_2			: 24;
+			u32 __reserved_3[3];
+		} error_bits;
+		struct {
+			u32 errors;
+			u32 __reserved_3[3];
+		} all_errors;
+	} esr;
+
+/*290*/	struct { u32 __reserved[4]; } __reserved_08;
+
+/*2A0*/	struct { u32 __reserved[4]; } __reserved_09;
+
+/*2B0*/	struct { u32 __reserved[4]; } __reserved_10;
+
+/*2C0*/	struct { u32 __reserved[4]; } __reserved_11;
+
+/*2D0*/	struct { u32 __reserved[4]; } __reserved_12;
+
+/*2E0*/	struct { u32 __reserved[4]; } __reserved_13;
+
+/*2F0*/	struct { u32 __reserved[4]; } __reserved_14;
+
+/*300*/	struct { /* Interrupt Command Register 1 */
+		u32   vector			:  8,
+			delivery_mode		:  3,
+			destination_mode	:  1,
+			delivery_status		:  1,
+			__reserved_1		:  1,
+			level			:  1,
+			trigger			:  1,
+			__reserved_2		:  2,
+			shorthand		:  2,
+			__reserved_3		:  12;
+		u32 __reserved_4[3];
+	} icr1;
+
+/*310*/	struct { /* Interrupt Command Register 2 */
+		union {
+			u32   __reserved_1	: 24,
+				phys_dest	:  4,
+				__reserved_2	:  4;
+			u32   __reserved_3	: 24,
+				logical_dest	:  8;
+		} dest;
+		u32 __reserved_4[3];
+	} icr2;
+
+/*320*/	struct { /* LVT - Timer */
+		u32   vector		:  8,
+			__reserved_1	:  4,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			timer_mode	:  1,
+			__reserved_3	: 14;
+		u32 __reserved_4[3];
+	} lvt_timer;
+
+/*330*/	struct { u32 __reserved[4]; } __reserved_15;
+
+/*340*/	struct { /* LVT - Performance Counter */
+		u32   vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			__reserved_3	: 15;
+		u32 __reserved_4[3];
+	} lvt_pc;
+
+/*350*/	struct { /* LVT - LINT0 */
+		u32   vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			polarity	:  1,
+			remote_irr	:  1,
+			trigger		:  1,
+			mask		:  1,
+			__reserved_2	: 15;
+		u32 __reserved_3[3];
+	} lvt_lint0;
+
+/*360*/	struct { /* LVT - LINT1 */
+		u32   vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			polarity	:  1,
+			remote_irr	:  1,
+			trigger		:  1,
+			mask		:  1,
+			__reserved_2	: 15;
+		u32 __reserved_3[3];
+	} lvt_lint1;
+
+/*370*/	struct { /* LVT - Error */
+		u32   vector		:  8,
+			__reserved_1	:  4,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			__reserved_3	: 15;
+		u32 __reserved_4[3];
+	} lvt_error;
+
+/*380*/	struct { /* Timer Initial Count Register */
+		u32   initial_count;
+		u32 __reserved_2[3];
+	} timer_icr;
+
+/*390*/	const
+	struct { /* Timer Current Count Register */
+		u32   curr_count;
+		u32 __reserved_2[3];
+	} timer_ccr;
+
+/*3A0*/	struct { u32 __reserved[4]; } __reserved_16;
+
+/*3B0*/	struct { u32 __reserved[4]; } __reserved_17;
+
+/*3C0*/	struct { u32 __reserved[4]; } __reserved_18;
+
+/*3D0*/	struct { u32 __reserved[4]; } __reserved_19;
+
+/*3E0*/	struct { /* Timer Divide Configuration Register */
+		u32   divisor		:  4,
+			__reserved_1	: 28;
+		u32 __reserved_2[3];
+	} timer_dcr;
+
+/*3F0*/	struct { u32 __reserved[4]; } __reserved_20;
+
+} __attribute__ ((packed));
+
+#undef u32
 
 #endif
diff -u --recursive --new-file v2.3.19/linux/include/asm-i386/hw_irq.h linux/include/asm-i386/hw_irq.h
--- v2.3.19/linux/include/asm-i386/hw_irq.h	Wed Aug 18 16:45:10 1999
+++ linux/include/asm-i386/hw_irq.h	Fri Oct  8 10:27:11 1999
@@ -27,33 +27,40 @@
  */
 
 /*
- * Special IRQ vectors used by the SMP architecture:
+ * Special IRQ vectors used by the SMP architecture, 0x30-0x4f
  *
- * (some of the following vectors are 'rare', they are merged
- *  into a single vector (FUNCTION_VECTOR) to save vector space.
- *  TLB, reschedule and local APIC vectors are performance-critical.)
- */
-#define RESCHEDULE_VECTOR	0x30
-#define INVALIDATE_TLB_VECTOR	0x31
-#define STOP_CPU_VECTOR		0x40
-#define LOCAL_TIMER_VECTOR	0x41
-#define CALL_FUNCTION_VECTOR	0x50
+ *  some of the following vectors are 'rare', they are merged
+ *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
+ *  TLB, reschedule and local APIC vectors are performance-critical.
+ */
+#define INVALIDATE_TLB_VECTOR	0x30
+#define LOCAL_TIMER_VECTOR	0x31
+#define RESCHEDULE_VECTOR	0x40
+
+/* 'rare' vectors: */
+#define CALL_FUNCTION_VECTOR	0x41
 
 /*
- * First APIC vector available to drivers: (vectors 0x51-0xfe)
+ * These IRQs should never really happen on perfect hardware running
+ * a perfect kernel, but we nevertheless print a message to catch the
+ * rest ;) Subtle, the APIC architecture mandates the spurious vector
+ * to have bits 0-3 set to 1. Note that these vectors do not occur
+ * normally, so we violate the 'only 2 vectors per priority level'
+ * rule here.
  */
-#define IRQ0_TRAP_VECTOR	0x51
+#define SPURIOUS_APIC_VECTOR	0x3f
+#define ERROR_APIC_VECTOR	0x43
 
 /*
- * This IRQ should never happen, but we print a message nevertheless.
+ * First APIC vector available to drivers: (vectors 0x51-0xfe)
+ * we start at 0x51 to spread out vectors between priority levels
+ * evenly. (note that 0x80 is the syscall vector)
  */
-#define SPURIOUS_APIC_VECTOR	0xff
+#define IRQ0_TRAP_VECTOR	0x51
 
 extern int irq_vector[NR_IRQS];
 #define IO_APIC_VECTOR(irq)	irq_vector[irq]
 
-extern void init_IRQ_SMP(void);
-
 /*
  * Various low-level irq details needed by irq.c, process.c,
  * time.c, io_apic.c and smp.c
@@ -65,18 +72,20 @@
 extern void mask_irq(unsigned int irq);
 extern void unmask_irq(unsigned int irq);
 extern void disable_8259A_irq(unsigned int irq);
+extern void enable_8259A_irq(unsigned int irq);
 extern int i8259A_irq_pending(unsigned int irq);
-extern void ack_APIC_irq(void);
+extern void make_8259A_irq(unsigned int irq);
+extern void init_8259A(int aeoi);
 extern void FASTCALL(send_IPI_self(int vector));
 extern void init_VISWS_APIC_irqs(void);
 extern void setup_IO_APIC(void);
 extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
-extern void make_8259A_irq(unsigned int irq);
 extern void send_IPI(int dest, int vector);
 extern void init_pic_mode(void);
 extern void print_IO_APIC(void);
 
 extern unsigned long io_apic_irqs;
+extern volatile unsigned long irq_err_count;
 
 extern char _stext, _etext;
 
@@ -214,6 +223,7 @@
 
 #ifdef __SMP__ /*more of this file should probably be ifdefed SMP */
 static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
+	if (IO_APIC_IRQ(i))
 		send_IPI_self(IO_APIC_VECTOR(i));
 }
 #else
diff -u --recursive --new-file v2.3.19/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h
--- v2.3.19/linux/include/asm-i386/irq.h	Thu May  6 14:02:34 1999
+++ linux/include/asm-i386/irq.h	Thu Oct  7 10:17:09 1999
@@ -13,7 +13,7 @@
 #define TIMER_IRQ 0
 
 /*
- * 16 8259A IRQ's, 240 potential APIC interrupt sources.
+ * 16 8259A IRQ's, 208 potential APIC interrupt sources.
  * Right now the APIC is mostly only used for SMP.
  * 256 vectors is an architectural limit. (we can have
  * more than 256 devices theoretically, but they will
diff -u --recursive --new-file v2.3.19/linux/include/asm-i386/msr.h linux/include/asm-i386/msr.h
--- v2.3.19/linux/include/asm-i386/msr.h	Thu Apr 29 11:53:41 1999
+++ linux/include/asm-i386/msr.h	Thu Oct  7 10:17:09 1999
@@ -23,6 +23,8 @@
 #define rdtscll(val) \
      __asm__ __volatile__ ("rdtsc" : "=A" (val))
 
+#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
+
 #define rdpmc(counter,low,high) \
      __asm__ __volatile__("rdpmc" \
 			  : "=a" (low), "=d" (high) \
diff -u --recursive --new-file v2.3.19/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.3.19/linux/include/asm-i386/processor.h	Wed Aug 18 16:43:30 1999
+++ linux/include/asm-i386/processor.h	Fri Oct  8 10:25:18 1999
@@ -106,6 +106,9 @@
 #define current_cpu_data boot_cpu_data
 #endif
 
+#define cpu_has_tsc \
+		(cpu_data[smp_processor_id()].x86_capability & X86_FEATURE_TSC)
+
 extern char ignore_irq13;
 
 extern void identify_cpu(struct cpuinfo_x86 *);
diff -u --recursive --new-file v2.3.19/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.3.19/linux/include/asm-i386/smp.h	Wed Aug 18 16:43:30 1999
+++ linux/include/asm-i386/smp.h	Fri Oct  8 10:25:18 1999
@@ -123,17 +123,19 @@
 	unsigned char mpc_dstirq;
 };
 
-#define MP_INT_VECTORED		0
-#define MP_INT_NMI		1
-#define MP_INT_SMI		2
-#define MP_INT_EXTINT		3
+enum mp_irq_source_types {
+	mp_INT = 0,
+	mp_NMI = 1,
+	mp_SMI = 2,
+	mp_ExtINT = 3
+};
 
 #define MP_IRQDIR_DEFAULT	0
 #define MP_IRQDIR_HIGH		1
 #define MP_IRQDIR_LOW		3
 
 
-struct mpc_config_intlocal
+struct mpc_config_lintsrc
 {
 	unsigned char mpc_type;
 	unsigned char mpc_irqtype;
@@ -150,7 +152,7 @@
  *	Default configurations
  *
  *	1	2 CPU ISA 82489DX
- *	2	2 CPU EISA 82489DX no IRQ 8 or timer chaining
+ *	2	2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining
  *	3	2 CPU EISA 82489DX
  *	4	2 CPU MCA 82489DX
  *	5	2 CPU ISA+PCI
@@ -165,21 +167,19 @@
 extern int smp_found_config;
 extern void init_smp_config(void);
 extern unsigned long smp_alloc_memory(unsigned long mem_base);
-extern unsigned char boot_cpu_id;
 extern unsigned long cpu_present_map;
 extern unsigned long cpu_online_map;
-extern volatile int cpu_number_map[NR_CPUS];
 extern volatile unsigned long smp_invalidate_needed;
+extern int pic_mode;
 extern void smp_flush_tlb(void);
-
-extern volatile unsigned long cpu_callin_map[NR_CPUS];
+extern int get_maxlvt(void);
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
 extern void smp_send_reschedule(int cpu);
-extern unsigned long ipi_count;
 extern void smp_invalidate_rcv(void);		/* Process an NMI */
 extern void smp_local_timer_interrupt(struct pt_regs * regs);
 extern void (*mtrr_hook) (void);
-extern void setup_APIC_clock (void);
+extern void setup_APIC_clocks(void);
+extern volatile int cpu_number_map[NR_CPUS];
 extern volatile int __cpu_logical_map[NR_CPUS];
 extern inline int cpu_logical_map(int cpu)
 {
@@ -196,12 +196,35 @@
 	return *((volatile unsigned long *)(APIC_BASE+reg));
 }
 
+extern unsigned int apic_timer_irqs [NR_CPUS];
+
+#ifdef CONFIG_X86_GOOD_APIC
+# define FORCE_READ_AROUND_WRITE 0
+# define apic_readaround(x)
+#else
+# define FORCE_READ_AROUND_WRITE 1
+# define apic_readaround(x) apic_read(x)
+#endif
+
+#define apic_write_around(x,y) \
+		do { apic_readaround(x); apic_write(x,y); } while (0)
+
+extern inline void ack_APIC_irq(void)
+{
+        /* Clear the IPI */
+
+	apic_readaround(APIC_EOI);
+	/*
+	 * on P6+ cores (CONFIG_X86_GOOD_APIC) ack_APIC_irq() actually
+	 * gets compiled as a single instruction ... yummie.
+	 */
+        apic_write(APIC_EOI, 0); /* Docs say use 0 for future compatibility */
+}
 
 /*
  *	General functions that each host system must provide.
  */
  
-extern void smp_callin(void);
 extern void smp_boot_cpus(void);
 extern void smp_store_cpu_info(int id);		/* Store per CPU info (like the initial udelay numbers */
 
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/adb.h linux/include/asm-ppc/adb.h
--- v2.3.19/linux/include/asm-ppc/adb.h	Thu Apr 29 12:39:01 1999
+++ linux/include/asm-ppc/adb.h	Wed Dec 31 16:00:00 1969
@@ -1,100 +0,0 @@
-/*
- * Definitions for ADB (Apple Desktop Bus) support.
- */
-#ifndef __PPC_ADB_H
-#define __PPC_ADB_H
-
-/* ADB commands */
-#define ADB_BUSRESET		0
-#define ADB_FLUSH(id)		(1 + ((id) << 4))
-#define ADB_WRITEREG(id, reg)	(8 + (reg) + ((id) << 4))
-#define ADB_READREG(id, reg)	(0xc + (reg) + ((id) << 4))
-
-/* ADB default device IDs (upper 4 bits of ADB command byte) */
-#define ADB_DONGLE	1	/* "software execution control" devices */
-#define ADB_KEYBOARD	2
-#define ADB_MOUSE	3
-#define ADB_TABLET	4
-#define ADB_MODEM	5
-#define ADB_MISC	7	/* maybe a monitor */
-
-#define ADB_RET_OK	0
-#define ADB_RET_TIMEOUT	3
-
-/* The kind of ADB request. The controller may emulate some
-   of all of those CUDA/PMU packet kinds */
-#define ADB_PACKET	0
-#define CUDA_PACKET	1
-#define ERROR_PACKET	2
-#define TIMER_PACKET	3
-#define POWER_PACKET	4
-#define MACIIC_PACKET	5
-#define PMU_PACKET	6
-
-#ifdef __KERNEL__
-
-struct adb_request {
-    unsigned char data[32];
-    int nbytes;
-    unsigned char reply[32];
-    int reply_len;
-    unsigned char reply_expected;
-    unsigned char sent;
-    unsigned char complete;
-    void (*done)(struct adb_request *);
-    void *arg;
-    struct adb_request *next;
-};
-
-struct adb_ids {
-    int nids;
-    unsigned char id[16];
-};
-
-/* Messages sent thru the client_list notifier. You should NOT stop
-   the operation, at least not with this version */
-enum adb_message {
-    ADB_MSG_POWERDOWN,	/* Currently called before sleep only */
-    ADB_MSG_PRE_RESET,	/* Called before resetting the bus */
-    ADB_MSG_POST_RESET	/* Called after resetting the bus (re-do init & register) */
-};
-extern struct notifier_block *adb_client_list;
-
-/* Kind of ADB controller */
-enum adb_hw {
-    ADB_NONE, ADB_VIACUDA, ADB_VIAPMU, ADB_MACIO, ADB_UNKNOWN
-};
-
-/* Definition of a controller */
-extern struct adb_controller {
-    enum adb_hw		kind;
-	
-    int		(*send_request)(struct adb_request *req, int sync);
-    int		(*autopoll)(int devs);
-    int		(*reset_bus)(void);
-    void	(*poll)(void);
-} *adb_controller;
-extern enum adb_hw adb_hardware;
-
-/* Values for adb_request flags */
-#define ADBREQ_REPLY	1	/* expect reply */
-#define ADBREQ_SYNC	2	/* poll until done */
-
-void adb_init(void);
-
-int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
-		int flags, int nbytes, ...);
-int adb_register(int default_id,int handler_id,struct adb_ids *ids,
-		 void (*handler)(unsigned char *, int, struct pt_regs *, int));
-void adb_input(unsigned char *, int, struct pt_regs *, int);
-
-int adb_try_handler_change(int address, int new_id);
-int adb_get_infos(int address, int *original_address, int *handler_id);
-
-int adb_reset_bus(void);
-
-void adb_poll(void);
-
-#endif /* __KERNEL__ */
-
-#endif /* __PPC_ADB_H */
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/adb_mouse.h linux/include/asm-ppc/adb_mouse.h
--- v2.3.19/linux/include/asm-ppc/adb_mouse.h	Sat May 15 15:05:37 1999
+++ linux/include/asm-ppc/adb_mouse.h	Wed Dec 31 16:00:00 1969
@@ -1,23 +0,0 @@
-#ifndef _LINUX_ADB_MOUSE_H
-#define _LINUX_ADB_MOUSE_H
-
-/*
- * linux/include/linux/mac_mouse.h
- * header file for Macintosh ADB mouse driver
- * 27-10-97 Michael Schmitz
- * copied from:
- * header file for Atari Mouse driver
- * by Robert de Vries (robert@and.nl) on 19Jul93
- */
-
-struct mouse_status {
-	char		buttons;
-	short		dx;
-	short		dy;
-	int		ready;
-	int		active;
-	wait_queue_head_t wait;
-	struct fasync_struct *fasyncptr;
-};
-
-#endif
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/amigahw.h linux/include/asm-ppc/amigahw.h
--- v2.3.19/linux/include/asm-ppc/amigahw.h	Tue Aug  4 16:06:36 1998
+++ linux/include/asm-ppc/amigahw.h	Thu Oct  7 10:17:09 1999
@@ -1 +1,15 @@
+#ifndef __ASMPPC_AMIGAHW_H
+#define __ASMPPC_AMIGAHW_H
+
+#include <linux/config.h>
 #include <asm-m68k/amigahw.h>
+
+#undef CHIP_PHYSADDR
+#ifdef CONFIG_APUS_FAST_EXCEPT
+#define CHIP_PHYSADDR      (0x000000)
+#else
+#define CHIP_PHYSADDR      (0x004000)
+#endif
+
+
+#endif /* __ASMPPC_AMIGAHW_H */
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/amigappc.h linux/include/asm-ppc/amigappc.h
--- v2.3.19/linux/include/asm-ppc/amigappc.h	Mon Dec 21 08:37:24 1998
+++ linux/include/asm-ppc/amigappc.h	Thu Oct  7 10:17:09 1999
@@ -16,30 +16,24 @@
 
 #ifndef __ASSEMBLY__
 
-#ifndef iobarrier_rw /* Don't include io.h - avoid circular dependency */
-#define iobarrier_rw() eieio()
-#endif
+/* #include <asm/system.h> */
+#define mb()  __asm__ __volatile__ ("sync" : : : "memory")
 
 #define APUS_WRITE(_a_, _v_)				\
 do {							\
 	(*((volatile unsigned char *)(_a_)) = (_v_));	\
-	iobarrier_rw ();				\
+	mb();						\
 } while (0)
 
-#define APUS_READ(_a_, _v_) 				\
+#define APUS_READ(_a_, _v_)				\
 do {							\
 	(_v_) = (*((volatile unsigned char *)(_a_)));	\
-	iobarrier_rw ();				\
+	mb();						\
 } while (0)
 #endif /* ndef __ASSEMBLY__ */
 
 /* Maybe add a [#ifdef WANT_ZTWOBASE] condition to amigahw.h? */
 #define zTwoBase (0x80000000)
-
-/* At CYBERBASEp we find the following sum:
- * -KERNELBASE+CyberStormMemoryBase
- */
-#define CYBERBASEp (0xfff00000)
 
 #define APUS_IPL_BASE   	(zTwoBase + 0x00f60000)
 #define APUS_REG_RESET    	(APUS_IPL_BASE + 0x00)
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/amigayle.h linux/include/asm-ppc/amigayle.h
--- v2.3.19/linux/include/asm-ppc/amigayle.h	Wed Sep 30 10:14:33 1998
+++ linux/include/asm-ppc/amigayle.h	Thu Oct  7 10:17:09 1999
@@ -1 +1 @@
-#include "../asm-m68k/amigayle.h"
+#include <asm-m68k/amigayle.h>
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/amipcmcia.h linux/include/asm-ppc/amipcmcia.h
--- v2.3.19/linux/include/asm-ppc/amipcmcia.h	Wed Sep 30 10:14:33 1998
+++ linux/include/asm-ppc/amipcmcia.h	Thu Oct  7 10:17:09 1999
@@ -1 +1 @@
-#include "../asm-m68k/amipcmcia.h"
+#include <asm-m68k/amipcmcia.h>
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/bootx.h linux/include/asm-ppc/bootx.h
--- v2.3.19/linux/include/asm-ppc/bootx.h	Wed Mar 10 21:30:32 1999
+++ linux/include/asm-ppc/bootx.h	Thu Oct  7 10:17:09 1999
@@ -11,6 +11,7 @@
 
 #ifdef macintosh
 #include <Types.h>
+#include "linux_type_defs.h"
 #endif
 
 #ifdef macintosh
@@ -18,66 +19,118 @@
 #pragma options align=power
 #endif
 
-/* On boostrap entry:
+/* On kernel entry:
  *
- * r3 = 0x426f6f58	('BooX')
+ * r3 = 0x426f6f58    ('BooX')
  * r4 = pointer to boot_infos
  * r5 = NULL
+ *
+ * Data and instruction translation disabled, interrupts
+ * disabled, kernel loaded at physical 0x00000000 on PCI
+ * machines (will be different on NuBus).
+ */
+
+#define BOOT_INFO_VERSION               5
+#define BOOT_INFO_COMPATIBLE_VERSION    1
+
+/* Bit in the architecture flag mask. More to be defined in
+   future versions. Note that either BOOT_ARCH_PCI or
+   BOOT_ARCH_NUBUS is set. The other BOOT_ARCH_NUBUS_xxx are
+   set additionally when BOOT_ARCH_NUBUS is set.
  */
+#define BOOT_ARCH_PCI                   0x00000001UL
+#define BOOT_ARCH_NUBUS                 0x00000002UL
+#define BOOT_ARCH_NUBUS_PDM             0x00000010UL
+#define BOOT_ARCH_NUBUS_PERFORMA        0x00000020UL
+#define BOOT_ARCH_NUBUS_POWERBOOK       0x00000040UL
+
+/*  Maximum number of ranges in phys memory map */
+#define MAX_MEM_MAP_SIZE				26
+
+/* This is the format of an element in the physical memory map. Note that
+   the map is optional and current BootX will only build it for pre-PCI
+   machines */
+typedef struct boot_info_map_entry
+{
+    __u32       physAddr;                /* Physical starting address */
+    __u32       size;                    /* Size in bytes */
+} boot_info_map_entry_t;
 
-#define BOOT_INFO_VERSION		2
-#define BOOT_INFO_COMPATIBLE_VERSION	1
 
 /* Here are the boot informations that are passed to the bootstrap
  * Note that the kernel arguments and the device tree are appended
  * at the end of this structure. */
 typedef struct boot_infos
 {
-	/* Version of this structure */
-	unsigned long	version;
-	/* backward compatible down to version: */
-	unsigned long	compatible_version;
-	
-	/* NEW (vers. 2) this holds the current _logical_ base addr of
-	   the frame buffer (for use by early boot message) */
-	unsigned char*	logicalDisplayBase;
-
-	/* Set to 0 by current BootX */
-	unsigned long	unused[2];
-	
-	/* The device tree (internal addresses relative to the beginning of the tree,
-	 * device tree offset relative to the beginning of this structure). */
-	unsigned long	deviceTreeOffset;	/* Device tree offset */
-	unsigned long	deviceTreeSize;		/* Size of the device tree */
-		
-	/* Some infos about the current MacOS display */
-	unsigned long	dispDeviceRect[4];	/* left,top,right,bottom */
-	unsigned long	dispDeviceDepth;	/* (8, 16 or 32) */
-	unsigned char*	dispDeviceBase;		/* base address (physical) */
-	unsigned long	dispDeviceRowBytes;	/* rowbytes (in bytes) */
-	unsigned long	dispDeviceColorsOffset;	/* Colormap (8 bits only) or 0 (*) */
-	/* Optional offset in the registry to the current
-	 * MacOS display. (Can be 0 when not detected) */
- 	unsigned long	dispDeviceRegEntryOffset;
-
-	/* Optional pointer to boot ramdisk (offset from this structure) */
-	unsigned long	ramDisk;
-	unsigned long	ramDiskSize;		/* size of ramdisk image */
-	
-	/* Kernel command line arguments (offset from this structure) */
-	unsigned long	kernelParamsOffset;
-		
+    /* Version of this structure */
+    __u32       version;
+    /* backward compatible down to version: */
+    __u32       compatible_version;
+    
+    /* NEW (vers. 2) this holds the current _logical_ base addr of
+       the frame buffer (for use by early boot message) */
+    __u8*       logicalDisplayBase;
+
+    /* NEW (vers. 4) Apple's machine identification */
+    __u32       machineID;
+
+    /* NEW (vers. 4) Detected hw architecture */
+    __u32       architecture;
+    
+    /* The device tree (internal addresses relative to the beginning of the tree,
+     * device tree offset relative to the beginning of this structure).
+     * On pre-PCI macintosh (BOOT_ARCH_PCI bit set to 0 in architecture), this
+     * field is 0.
+     */
+    __u32       deviceTreeOffset;        /* Device tree offset */
+    __u32       deviceTreeSize;          /* Size of the device tree */
+        
+    /* Some infos about the current MacOS display */
+    __u32       dispDeviceRect[4];       /* left,top,right,bottom */
+    __u32       dispDeviceDepth;         /* (8, 16 or 32) */
+    __u8*       dispDeviceBase;          /* base address (physical) */
+    __u32       dispDeviceRowBytes;      /* rowbytes (in bytes) */
+    __u32       dispDeviceColorsOffset;  /* Colormap (8 bits only) or 0 (*) */
+    /* Optional offset in the registry to the current
+     * MacOS display. (Can be 0 when not detected) */
+     __u32      dispDeviceRegEntryOffset;
+
+    /* Optional pointer to boot ramdisk (offset from this structure) */
+    __u32       ramDisk;
+    __u32       ramDiskSize;             /* size of ramdisk image */
+    
+    /* Kernel command line arguments (offset from this structure) */
+    __u32       kernelParamsOffset;
+    
+    /* ALL BELOW NEW (vers. 4) */
+    
+    /* This defines the physical memory. Valid with BOOT_ARCH_NUBUS flag
+       (non-PCI) only. On PCI, memory is contiguous and it's size is in the
+       device-tree. */
+    boot_info_map_entry_t
+    	        physMemoryMap[MAX_MEM_MAP_SIZE]; /* Where the phys memory is */
+    __u32       physMemoryMapSize;               /* How many entries in map */
+    
+				
+    /* The framebuffer size (optional, currently 0) */
+    __u32       frameBufferSize;         /* Represents a max size, can be 0. */
+    
+    /* NEW (vers. 5) */
+
+    /* Total params size (args + colormap + device tree + ramdisk) */
+    __u32       totalParamsSize;
+
 } boot_infos_t;
 
 /* (*) The format of the colormap is 256 * 3 * 2 bytes. Each color index is represented
  * by 3 short words containing a 16 bits (unsigned) color component.
  * Later versions may contain the gamma table for direct-color devices here.
  */
-#define BOOTX_COLORTABLE_SIZE	(256UL*3UL*2UL)
+#define BOOTX_COLORTABLE_SIZE    (256UL*3UL*2UL)
 
 #ifdef macintosh
 #pragma options align=reset
 #endif
 
 #endif
-
+    
\ No newline at end of file
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/bseip.h linux/include/asm-ppc/bseip.h
--- v2.3.19/linux/include/asm-ppc/bseip.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/bseip.h	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,41 @@
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifndef __MACH_BSEIP_DEFS
+#define __MACH_BSEIP_DEFS
+
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * All we need to get started is the IMMR.
+ */
+#define IMAP_ADDR		((uint)0xff000000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define PCMCIA_MEM_ADDR		((uint)0x04000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+/* Machine type
+*/
+#define _MACH_8xx (_MACH_bseip)
+
+#endif
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/cuda.h linux/include/asm-ppc/cuda.h
--- v2.3.19/linux/include/asm-ppc/cuda.h	Thu Apr 29 12:39:01 1999
+++ linux/include/asm-ppc/cuda.h	Wed Dec 31 16:00:00 1969
@@ -1,38 +0,0 @@
-/*
- * Definitions for talking to the CUDA.  The CUDA is a microcontroller
- * which controls the ADB, system power, RTC, and various other things.
- *
- * Copyright (C) 1996 Paul Mackerras.
- */
-
-/* CUDA commands (2nd byte) */
-#define CUDA_WARM_START		0
-#define CUDA_AUTOPOLL		1
-#define CUDA_GET_6805_ADDR	2
-#define CUDA_GET_TIME		3
-#define CUDA_GET_PRAM		7
-#define CUDA_SET_6805_ADDR	8
-#define CUDA_SET_TIME		9
-#define CUDA_POWERDOWN		0xa
-#define CUDA_POWERUP_TIME	0xb
-#define CUDA_SET_PRAM		0xc
-#define CUDA_MS_RESET		0xd
-#define CUDA_SEND_DFAC		0xe
-#define CUDA_RESET_SYSTEM	0x11
-#define CUDA_SET_IPL		0x12
-#define CUDA_SET_AUTO_RATE	0x14
-#define CUDA_GET_AUTO_RATE	0x16
-#define CUDA_SET_DEVICE_LIST	0x19
-#define CUDA_GET_DEVICE_LIST	0x1a
-#define CUDA_GET_SET_IIC	0x22
-
-#ifdef __KERNEL__
-
-void find_via_cuda(void);
-void via_cuda_init(void);
-int cuda_request(struct adb_request *req,
-		 void (*done)(struct adb_request *), int nbytes, ...);
-void cuda_poll(void);
-int cuda_present(void);
-
-#endif	/* __KERNEL */
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/feature.h linux/include/asm-ppc/feature.h
--- v2.3.19/linux/include/asm-ppc/feature.h	Wed Mar 10 21:30:32 1999
+++ linux/include/asm-ppc/feature.h	Thu Oct  7 10:17:09 1999
@@ -36,6 +36,8 @@
 	FEATURE_BMac_reset,
 	FEATURE_BMac_IO_enable,
 	FEATURE_Modem_Reset,
+	FEATURE_IDE_DiskPower,
+	FEATURE_IDE_Reset,
 	FEATURE_last,
 };
 
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.3.19/linux/include/asm-ppc/ide.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/ide.h	Thu Oct  7 10:17:09 1999
@@ -178,7 +178,11 @@
 /*
  * The following are not needed for the non-m68k ports
  */
+#ifdef CONFIG_APUS
+#define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
+#else
 #define ide_ack_intr(hwif)		(1)
+#endif
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/init.h linux/include/asm-ppc/init.h
--- v2.3.19/linux/include/asm-ppc/init.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-ppc/init.h	Thu Oct  7 10:17:09 1999
@@ -11,7 +11,7 @@
 	__argpmac
 	
 #define __prep __attribute__ ((__section__ (".text.prep")))
-#define __prepdata /* __attribute__ ((__section__ (".data.prep")))*/
+#define __prepdata __attribute__ ((__section__ (".data.prep")))
 #define __prepfunc(__argprep) \
 	__argprep __prep; \
 	__argprep
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/io.h linux/include/asm-ppc/io.h
--- v2.3.19/linux/include/asm-ppc/io.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/io.h	Thu Oct  7 10:17:09 1999
@@ -19,11 +19,9 @@
 #define PREP_ISA_MEM_BASE 	0xc0000000
 #define PREP_PCI_DRAM_OFFSET 	0x80000000
 
-#ifdef CONFIG_MBX
-#define _IO_BASE        0x80000000
-#define _ISA_MEM_BASE   0
-#define PCI_DRAM_OFFSET 0x80000000
-#else /* CONFIG_MBX8xx */
+#ifdef CONFIG_8xx
+#include <asm/mpc8xx.h>
+#else
 #ifdef CONFIG_APUS
 #define _IO_BASE 0
 #define _ISA_MEM_BASE 0
@@ -36,7 +34,7 @@
 #define _ISA_MEM_BASE	isa_mem_base
 #define PCI_DRAM_OFFSET	pci_dram_offset
 #endif /* CONFIG_APUS */
-#endif /* CONFIG_MBX8xx */
+#endif /* CONFIG_8xx */
 
 #define readb(addr) in_8((volatile unsigned char *)(addr))
 #define writeb(b,addr) out_8((volatile unsigned char *)(addr), (b))
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- v2.3.19/linux/include/asm-ppc/irq.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/irq.h	Thu Oct  7 10:17:09 1999
@@ -59,27 +59,42 @@
  * from such devices as CPM, PCMCIA, RTC, PIT, TimeBase and Decrementer.
  * There are eight external interrupts (IRQs) that can be configured
  * as either level or edge sensitive. 
- * On the MBX implementation, there is also the possibility of an 8259
+ *
+ * The 82xx can have up to 64 interrupts on the internal controller.
+ *
+ * On some implementations, there is also the possibility of an 8259
  * through the PCI and PCI-ISA bridges.
  */
-#define NR_IRQS	(16+16) /* 8259 has 16, too -- Cort */
+#ifdef CONFIG_82xx
+#define NR_SIU_INTS	64
+#else
+#define NR_SIU_INTS	16
+#endif
+
+#define NR_IRQS	(NR_SIU_INTS + NR_8259_INTS)
 
-#define	SIU_IRQ0	(0+16)	/* Highest priority */
-#define	SIU_LEVEL0	(1+16)
-#define	SIU_IRQ1	(2+16)
-#define	SIU_LEVEL1	(3+16)
-#define	SIU_IRQ2	(4+16)
-#define	SIU_LEVEL2	(5+16)
-#define	SIU_IRQ3	(6+16)
-#define	SIU_LEVEL3	(7+16)
-#define	SIU_IRQ4	(8+16)
-#define	SIU_LEVEL4	(9+16)
-#define	SIU_IRQ5	(10+16)
-#define	SIU_LEVEL5	(11+16)
-#define	SIU_IRQ6	(12+16)
-#define	SIU_LEVEL6	(13+16)
-#define	SIU_IRQ7	(14+16)
-#define	SIU_LEVEL7	(15+16)
+/* These values must be zero-based and map 1:1 with the SIU configuration.
+ * They are used throughout the 8xx/82xx I/O subsystem to generate
+ * interrupt masks, flags, and other control patterns.  This is why the
+ * current kernel assumption of the 8259 as the base controller is such
+ * a pain in the butt.
+ */
+#define	SIU_IRQ0	(0)	/* Highest priority */
+#define	SIU_LEVEL0	(1)
+#define	SIU_IRQ1	(2)
+#define	SIU_LEVEL1	(3)
+#define	SIU_IRQ2	(4)
+#define	SIU_LEVEL2	(5)
+#define	SIU_IRQ3	(6)
+#define	SIU_LEVEL3	(7)
+#define	SIU_IRQ4	(8)
+#define	SIU_LEVEL4	(9)
+#define	SIU_IRQ5	(10)
+#define	SIU_LEVEL5	(11)
+#define	SIU_IRQ6	(12)
+#define	SIU_LEVEL6	(13)
+#define	SIU_IRQ7	(14)
+#define	SIU_LEVEL7	(15)
 
 /* The internal interrupts we can configure as we see fit.
  * My personal preference is CPM at level 2, which puts it above the
@@ -95,21 +110,11 @@
  */
 #define	mk_int_int_mask(IL) (1 << (7 - (IL/2)))
 
-#ifdef CONFIG_MBX
-/* These are defined (and fixed) by the MBX hardware implementation.*/
-#define POWER_FAIL_INT	SIU_IRQ0	/* Power fail */
-#define TEMP_HILO_INT	SIU_IRQ1	/* Temperature sensor */
-#define QSPAN_INT	SIU_IRQ2	/* PCI Bridge (DMA CTLR?) */
-#define ISA_BRIDGE_INT	SIU_IRQ3	/* All those PC things */
-#define COMM_L_INT	SIU_IRQ6	/* MBX Comm expansion connector pin */
-#define STOP_ABRT_INT	SIU_IRQ7	/* Stop/Abort header pin */
-#endif /* CONFIG_MBX */
-
-#ifdef CONFIG_FADS
-#define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
-#endif
+/* Now include the board configuration specific associations.
+*/
+#include <asm/mpc8xx.h>
 
-/* always the same on MBX -- Cort */
+/* always the same on 8xx -- Cort */
 static __inline__ int irq_cannonicalize(int irq)
 {
 	return irq;
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/irq_control.h linux/include/asm-ppc/irq_control.h
--- v2.3.19/linux/include/asm-ppc/irq_control.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/irq_control.h	Thu Oct  7 10:17:09 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: irq_control.h,v 1.2 1999/07/17 20:23:58 cort Exp $
+ * $Id: irq_control.h,v 1.8 1999/09/15 23:58:48 cort Exp $
  *
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
  */
@@ -11,74 +11,52 @@
 #include <asm/irq.h>
 #include <asm/atomic.h>
 
-extern void do_lost_interrupts(unsigned long);
-extern atomic_t ppc_n_lost_interrupts;
+/* Structure describing interrupts */
+struct hw_interrupt_type {
+	const char * typename;
+	void (*startup)(unsigned int irq);
+	void (*shutdown)(unsigned int irq);
+	void (*enable)(unsigned int irq);
+	void (*disable)(unsigned int irq);
+	void (*mask_and_ack)(unsigned int irq);
+	int irq_offset;
+};
+
+struct irqdesc {
+	struct irqaction *action;
+	struct hw_interrupt_type *ctl;
+};
 
-#define __no_use_save_flags(flags) \
-	({__asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
-
-extern __inline__ void __no_use_restore_flags(unsigned long flags)
-{
-        if ((flags & MSR_EE) && atomic_read(&ppc_n_lost_interrupts) != 0) {
-                do_lost_interrupts(flags);
-        } else {
-                __asm__ __volatile__ ("sync; mtmsr %0; isync"
-                              : : "r" (flags) : "memory");
-        }
-}
+extern struct irqdesc irq_desc[NR_IRQS];
 
-extern __inline__ void __no_use_sti(void)
+struct int_control_struct
 {
-	unsigned long flags;
+	void (*int_cli)(void);
+	void (*int_sti)(void);
+	void (*int_restore_flags)(unsigned long);
+	void (*int_save_flags)(unsigned long *);
+};
+extern struct int_control_struct int_control;
+extern unsigned long timer_interrupt_intercept;
+extern unsigned long do_IRQ_intercept;
+void timer_interrupt(struct pt_regs *);
+
+extern void __no_use_sti(void);
+extern void __no_use_cli(void);
+extern void __no_use_restore_flags(unsigned long);
+extern void __no_use_save_flags(unsigned long *);
+
+#define __cli() int_control.int_cli()
+#define __sti() int_control.int_sti()
+#define __save_flags(flags) int_control.int_save_flags(&flags)
+#define __restore_flags(flags) int_control.int_restore_flags(flags)
+#define __save_and_cli(flags) ({__save_flags(flags);__cli();})
 
-	__asm__ __volatile__ ("mfmsr %0": "=r" (flags));
-	flags |= MSR_EE;
-	if ( atomic_read(&ppc_n_lost_interrupts) )
-		do_lost_interrupts(flags);
-	__asm__ __volatile__ ("sync; mtmsr %0; isync":: "r" (flags));
-}
-
-extern __inline__ void __no_use_cli(void)
-{
-	unsigned long flags;
-	__asm__ __volatile__ ("mfmsr %0": "=r" (flags));
-	flags &= ~MSR_EE;
-	__asm__ __volatile__ ("sync; mtmsr %0; isync":: "r" (flags));
-}
-
-#define __no_use_mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);})
-#define __no_use_unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);})
-#define __no_use_mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);})
-
-#ifdef CONFIG_RTL
-
-/* the rtl system provides these -- Cort */
-extern void __sti(void);
-extern void __cli(void);
-extern void __restore_flags(unsigned int);
-extern unsigned int __return_flags(void);
-#define __save_flags(flags) (flags = __return_flags())
-
-#define rtl_hard_cli __no_use_cli
-#define rtl_hard_sti __no_use_sti
-#define rtl_hard_save_flags(flags) __no_use_save_flags(flags)
-#define rtl_hard_restore_flags(flags) __no_use_restore_flags(flags)
-
-#define rtl_hard_mask_irq(irq) __no_use_mask_irq(irq)
-#define rtl_hard_unmask_irq(irq) __no_use_unmask_irq(irq)
-#define rtl_hard_mask_and_ack_irq(irq) __no_use_mask_and_ack_irq(irq)
-
-#else /* CONFIG_RTL */
-
-#define __cli __no_use_cli
-#define __sti __no_use_sti
-#define __save_flags(flags) __no_use_save_flags(flags)
-#define __restore_flags(flags) __no_use_restore_flags(flags)
-
-#define mask_irq(irq) __no_use_mask_irq(irq)
-#define unmask_irq(irq) __no_use_unmask_irq(irq)
-#define mask_and_ack_irq(irq) __no_use_mask_and_ack_irq(irq)
+extern void do_lost_interrupts(unsigned long);
+extern atomic_t ppc_n_lost_interrupts;
 
-#endif /* CONFIG_RTL */
+#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);})
+#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);})
+#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);})
 
 #endif /* _PPC_IRQ_CONTROL_H */
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- v2.3.19/linux/include/asm-ppc/keyboard.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-ppc/keyboard.h	Thu Oct  7 10:17:09 1999
@@ -16,11 +16,8 @@
 #ifdef __KERNEL__
 
 #include <linux/config.h>
-#include <asm/adb.h>
+#include <linux/adb.h>
 #include <asm/machdep.h>
-#ifdef CONFIG_APUS
-#include <asm-m68k/keyboard.h>
-#else
 
 #define KEYBOARD_IRQ			1
 #define DISABLE_KBD_DURING_INTERRUPTS	0
@@ -74,8 +71,6 @@
 #define kbd_sysrq_xlate	(ppc_md.ppc_kbd_sysrq_xlate)
 
 extern unsigned long SYSRQ_KEY;
-
-#endif /* CONFIG_APUS */
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/linux_logo.h linux/include/asm-ppc/linux_logo.h
--- v2.3.19/linux/include/asm-ppc/linux_logo.h	Wed Sep 30 10:14:33 1998
+++ linux/include/asm-ppc/linux_logo.h	Thu Oct  7 10:17:09 1999
@@ -12,14 +12,6 @@
  */
  
 #include <linux/config.h>
-#ifdef CONFIG_APUS
-#include <asm-m68k/linux_logo.h>
-
-#undef linux_logo_banner
-#define linux_logo_banner "Linux/PPC version " UTS_RELEASE
-
-#else
-
 #include <linux/init.h>
 
 #define linux_logo_banner "Linux/PPC version " UTS_RELEASE
@@ -48,4 +40,3 @@
 extern unsigned char linux_logo16[];
 
 #endif
-#endif /* CONFIG_APUS */
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h
--- v2.3.19/linux/include/asm-ppc/machdep.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-ppc/machdep.h	Thu Oct  7 10:17:09 1999
@@ -9,6 +9,7 @@
 #endif
 
 struct pt_regs;
+struct pci_bus;	
 
 struct machdep_calls {
 	void		(*setup_arch)(unsigned long * memory_start_p,
@@ -20,8 +21,9 @@
 	/* Optional, may be NULL. */
 	unsigned int	(*irq_cannonicalize)(unsigned int irq);
 	void		(*init_IRQ)(void);
-	void		(*do_IRQ)(struct pt_regs *regs, int cpu, int isfake);
-
+	int		(*get_irq)(struct pt_regs *);
+	void		(*post_irq)( int );
+	
 	/* A general init function, called by ppc_init in init/main.c.
 	   May be NULL. */
 	void		(*init)(void);
@@ -72,8 +74,9 @@
 	int (*pcibios_write_config_dword)(unsigned char bus,
 		unsigned char dev_fn, unsigned char offset, unsigned int val);
 	void (*pcibios_fixup)(void);
-struct pci_bus;	
 	void (*pcibios_fixup_bus)(struct pci_bus *);
+	/* this is for modules, since _machine can be a define -- Cort */
+	int ppc_machine;
 };
 
 extern struct machdep_calls ppc_md;
@@ -89,7 +92,7 @@
 	unsigned long magic_start;
 	char cmd_line[256];
 	char boot_loader[128];
-	int _machine;
+	int _machine_type;
 	unsigned long initrd_start, initrd_size;
 	unsigned long systemmap_start, systemmap_size;
 	unsigned long prom_entry;
@@ -97,4 +100,14 @@
 	unsigned long magic_end;
 };
 struct boot_info *binfo;
+
+/*
+ * Power macintoshes have either a CUDA or a PMU controlling
+ * system reset, power, NVRAM, RTC.
+ */
+enum sys_ctrler_kind {
+	SYS_CTRLER_CUDA = 1,
+	SYS_CTRLER_PMU = 2,
+} sys_ctrler;
+
 #endif /* _PPC_MACHDEP_H */
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/mbx.h linux/include/asm-ppc/mbx.h
--- v2.3.19/linux/include/asm-ppc/mbx.h	Wed Sep 30 10:14:33 1998
+++ linux/include/asm-ppc/mbx.h	Thu Oct  7 10:17:09 1999
@@ -39,9 +39,10 @@
  * NVRAM, Status/Control registers, CPM Dual Port RAM, and the PCI
  * Bridge CSRs 1:1 into the kernel address space.
  */
-#define PCI_ISA_IO_ADDR		((uint)0x80000000)
+#define PCI_ISA_IO_ADDR		((unsigned)0x80000000)
 #define PCI_ISA_IO_SIZE		((uint)(512 * 1024 * 1024))
-#define PCI_ISA_MEM_ADDR	((uint)0xc0000000)
+#define PCI_IDE_ADDR		((unsigned)0x81000000)
+#define PCI_ISA_MEM_ADDR	((unsigned)0xc0000000)
 #define PCI_ISA_MEM_SIZE	((uint)(512 * 1024 * 1024))
 #define PCMCIA_MEM_ADDR		((uint)0xe0000000)
 #define PCMCIA_MEM_SIZE		((uint)(64 * 1024 * 1024))
@@ -59,4 +60,29 @@
 #define IMAP_SIZE		((uint)(64 * 1024))
 #define PCI_CSR_ADDR		((uint)0xfa210000)
 #define PCI_CSR_SIZE		((uint)(64 * 1024))
+
+/* Map additional physical space into well known virtual addresses.  Due
+ * to virtual address mapping, these physical addresses are not accessible
+ * in a 1:1 virtual to physical mapping.
+ */
+#define ISA_IO_VIRT_ADDR	((uint)0xfa220000)
+#define ISA_IO_VIRT_SIZE	((uint)64 * 1024)
+
+/* Interrupt assignments.
+ * These are defined (and fixed) by the MBX hardware implementation.
+ */
+#define POWER_FAIL_INT	SIU_IRQ0	/* Power fail */
+#define TEMP_HILO_INT	SIU_IRQ1	/* Temperature sensor */
+#define QSPAN_INT	SIU_IRQ2	/* PCI Bridge (DMA CTLR?) */
+#define ISA_BRIDGE_INT	SIU_IRQ3	/* All those PC things */
+#define COMM_L_INT	SIU_IRQ6	/* MBX Comm expansion connector pin */
+#define STOP_ABRT_INT	SIU_IRQ7	/* Stop/Abort header pin */
+
+/* The MBX uses the 8259.
+*/
+#define NR_8259_INTS	16
+
+/* Generic 8xx type
+*/
+#define _MACH_8xx (_MACH_mbx)
 #endif
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/mpc8xx.h linux/include/asm-ppc/mpc8xx.h
--- v2.3.19/linux/include/asm-ppc/mpc8xx.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/mpc8xx.h	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,71 @@
+
+/* This is the single file included by all MPC8xx build options.
+ * Since there are many different boards and no standard configuration,
+ * we have a unique include file for each.  Rather than change every
+ * file that has to include MPC8xx configuration, they all include
+ * this one and the configuration switching is done here.
+ */
+#ifndef __CONFIG_8xx_DEFS
+#define __CONFIG_8xx_DEFS
+
+#ifdef CONFIG_8xx
+
+#ifdef CONFIG_MBX
+#include <asm/mbx.h>
+#endif
+
+#ifdef CONFIG_FADS
+#include <asm/fads.h>
+#endif
+
+#ifdef CONFIG_RPXLITE
+#include <asm/rpxlite.h>
+#endif
+
+#ifdef CONFIG_BSEIP
+#include <asm/bseip.h>
+#endif
+
+#ifdef CONFIG_RPXCLASSIC
+#include <asm/rpxclassic.h>
+#endif
+
+/* I need this to get pt_regs.......
+*/
+#include <asm/ptrace.h>
+
+/* Currently, all 8xx boards that support a processor to PCI/ISA bridge
+ * use the same memory map.
+ */
+#if 0
+#if defined(CONFIG_PCI) && defined(PCI_ISA_IO_ADDR)
+#define	_IO_BASE PCI_ISA_IO_ADDR
+#define	_ISA_MEM_BASE PCI_ISA_MEM_ADDR
+#define PCI_DRAM_OFFSET 0x80000000
+#else
+#define _IO_BASE        0
+#define _ISA_MEM_BASE   0
+#define PCI_DRAM_OFFSET 0
+#endif
+#else
+#define _IO_BASE        0
+#define _ISA_MEM_BASE   0
+#define PCI_DRAM_OFFSET 0
+#endif
+
+extern unsigned long isa_io_base;
+extern unsigned long isa_mem_base;
+extern unsigned long pci_dram_offset;
+
+/* The "residual" data board information structure the boot loader
+ * hands to us.
+ */
+extern unsigned char __res[];
+
+extern int request_8xxirq(unsigned int irq,
+		       void (*handler)(int, void *, struct pt_regs *),
+		       unsigned long flags, 
+		       const char *device,
+		       void *dev_id);
+#endif /* CONFIG_8xx */
+#endif
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/ohare.h linux/include/asm-ppc/ohare.h
--- v2.3.19/linux/include/asm-ppc/ohare.h	Wed Mar 10 21:30:32 1999
+++ linux/include/asm-ppc/ohare.h	Thu Oct  7 10:17:09 1999
@@ -18,7 +18,9 @@
 #define OH_BAY_IDE_ENABLE	8
 #define OH_BAY_FLOPPY_ENABLE	0x10
 #define OH_IDE_ENABLE		0x20
+#define OH_IDE_POWER		0x40	/* a guess */
 #define OH_BAY_ENABLE		0x80
+#define OH_IDE_RESET		0x100	/* 0-based, a guess */
 #define OH_SCC_ENABLE		0x200
 #define OH_MESH_ENABLE		0x400
 #define OH_FLOPPY_ENABLE	0x800
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.3.19/linux/include/asm-ppc/pgtable.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/pgtable.h	Thu Oct  7 10:17:09 1999
@@ -9,11 +9,28 @@
 #include <asm/mmu.h>
 #include <asm/page.h>
 
+#ifndef CONFIG_8xx
 extern void local_flush_tlb_all(void);
 extern void local_flush_tlb_mm(struct mm_struct *mm);
 extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
 extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
 			    unsigned long end);
+#else /* CONFIG_8xx */
+#define __tlbia()	asm volatile ("tlbia" : : )
+
+extern inline void local_flush_tlb_all(void)
+	{ __tlbia(); }
+extern inline void local_flush_tlb_mm(struct mm_struct *mm)
+	{ __tlbia(); }
+extern inline void local_flush_tlb_page(struct vm_area_struct *vma,
+				unsigned long vmaddr)
+	{ __tlbia(); }
+extern inline void local_flush_tlb_range(struct mm_struct *mm,
+				unsigned long start, unsigned long end)
+	{ __tlbia(); }
+extern inline void flush_hash_page(unsigned context, unsigned long va)
+	{ }
+#endif
 
 #define flush_tlb_all local_flush_tlb_all
 #define flush_tlb_mm local_flush_tlb_mm
@@ -636,22 +653,6 @@
 
 #define io_remap_page_range remap_page_range 
 
-#ifdef CONFIG_8xx
-#define __tlbia()	asm volatile ("tlbia" : : )
-
-extern inline void local_flush_tlb_all(void)
-	{ __tlbia(); }
-extern inline void local_flush_tlb_mm(struct mm_struct *mm)
-	{ __tlbia(); }
-extern inline void local_flush_tlb_page(struct vm_area_struct *vma,
-				unsigned long vmaddr)
-	{ __tlbia(); }
-extern inline void local_flush_tlb_range(struct mm_struct *mm,
-				unsigned long start, unsigned long end)
-	{ __tlbia(); }
-extern inline void flush_hash_page(unsigned context, unsigned long va)
-	{ }
-#endif
 
 #endif __ASSEMBLY__
 #endif /* _PPC_PGTABLE_H */
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/pmu.h linux/include/asm-ppc/pmu.h
--- v2.3.19/linux/include/asm-ppc/pmu.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-ppc/pmu.h	Wed Dec 31 16:00:00 1969
@@ -1,97 +0,0 @@
-/*
- * Definitions for talking to the PMU.  The PMU is a microcontroller
- * which controls battery charging and system power on PowerBook 3400
- * and 2400 models as well as the RTC and various other things.
- *
- * Copyright (C) 1998 Paul Mackerras.
- */
-
-/*
- * PMU commands
- */
-#define PMU_POWER_CTRL		0x11	/* control power of some devices */
-#define PMU_ADB_CMD		0x20	/* send ADB packet */
-#define PMU_ADB_POLL_OFF	0x21	/* disable ADB auto-poll */
-#define PMU_WRITE_NVRAM		0x33	/* write non-volatile RAM */
-#define PMU_READ_NVRAM		0x3b	/* read non-volatile RAM */
-#define PMU_SET_RTC		0x30	/* set real-time clock */
-#define PMU_READ_RTC		0x38	/* read real-time clock */
-#define PMU_SET_VOLBUTTON	0x40	/* set volume up/down position */
-#define PMU_BACKLIGHT_BRIGHT	0x41	/* set backlight brightness */
-#define PMU_GET_VOLBUTTON	0x48	/* get volume up/down position */
-#define PMU_PCEJECT		0x4c	/* eject PC-card from slot */
-#define PMU_BATTERY_STATE	0x6b	/* report battery state etc. */
-#define PMU_SET_INTR_MASK	0x70	/* set PMU interrupt mask */
-#define PMU_INT_ACK		0x78	/* read interrupt bits */
-#define PMU_SHUTDOWN		0x7e	/* turn power off */
-#define PMU_SLEEP		0x7f	/* put CPU to sleep */
-#define PMU_RESET		0xd0	/* reset CPU */
-#define PMU_GET_BRIGHTBUTTON	0xd9	/* report brightness up/down pos */
-#define PMU_GET_COVER		0xdc	/* report cover open/closed */
-
-/* Bits to use with the PMU_POWER_CTRL command */
-#define PMU_POW_ON		0x80	/* OR this to power ON the device */
-#define PMU_POW_OFF		0x00	/* leave bit 7 to 0 to power it OFF */
-#define PMU_POW_BACKLIGHT	0x01	/* backlight power */
-#define PMU_POW_IRLED		0x04	/* IR led power (on wallstreet) ??? */
-
-/* Bits in PMU interrupt and interrupt mask bytes */
-#define PMU_INT_ADB_AUTO	0x04	/* ADB autopoll, when PMU_INT_ADB */
-#define PMU_INT_PCEJECT		0x04	/* PC-card eject buttons */
-#define PMU_INT_SNDBRT		0x08	/* sound/brightness up/down buttons */
-#define PMU_INT_ADB		0x10	/* ADB autopoll or reply data */
-#define PMU_INT_TICK		0x80	/* 1-second tick interrupt */
-
-/* Kind of PMU (model) */
-enum {
-  PMU_UNKNOWN,
-  PMU_OHARE_BASED,
-  PMU_HEATHROW_BASED
-};
-
-/*
- * Ioctl commands for the /dev/pmu device
- */
-#include <linux/ioctl.h>
-
-/* no param */
-#define PMU_IOC_SLEEP		_IO('B', 0)
-/* out param: u32*	backlight value: 0 to 31 */
-#define PMU_IOC_GET_BACKLIGHT	_IOR('B', 1, sizeof(__u32*))
-/* in param: u32	backlight value: 0 to 31 */
-#define PMU_IOC_SET_BACKLIGHT	_IOW('B', 2, sizeof(__u32))
-/* out param: u32*	backlight value: 0 to 31 */
-#define PMU_IOC_GET_MODEL	_IOR('B', 3, sizeof(__u32*))
-
-#ifdef __KERNEL__
-
-void find_via_pmu(void);
-void via_pmu_init(void);
-
-int pmu_request(struct adb_request *req,
-		void (*done)(struct adb_request *), int nbytes, ...);
-void pmu_poll(void);
-
-void pmu_enable_backlight(int on);
-void pmu_set_brightness(int level);
-
-void pmu_enable_irled(int on);
-
-void pmu_restart(void);
-void pmu_shutdown(void);
-
-int pmu_present(void);
-int pmu_get_model(void);
-
-/*
- * Stuff for putting the powerbook to sleep and waking it again.
- */
-#include <linux/notifier.h>
-
-extern struct notifier_block *sleep_notifier_list;
-
-/* code values for calling sleep/wakeup handlers */
-#define PBOOK_SLEEP	1
-#define PBOOK_WAKE	2
-
-#endif	/* __KERNEL */
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.3.19/linux/include/asm-ppc/processor.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/processor.h	Thu Oct  7 10:17:09 1999
@@ -34,7 +34,7 @@
 #define MSR_RI		(1<<1)		/* Recoverable Exception */
 #define MSR_LE		(1<<0)		/* Little-Endian enable */
 
-#ifdef CONFIG_APUS
+#ifdef CONFIG_APUS_FAST_EXCEPT
 #define MSR_		MSR_ME|MSR_IP|MSR_RI
 #else
 #define MSR_		MSR_ME|MSR_RI
@@ -104,6 +104,7 @@
 #define _MACH_bseip   128 /* Bright Star Engineering ip-Engine */
 #define _MACH_yk      256 /* Motorola Yellowknife */
 #define _MACH_gemini  512 /* Synergy Microsystems gemini board */
+#define _MACH_classic 1024  /* RPCG RPX-Classic 8xx board */
 
 /* see residual.h for these */
 #define _PREP_Motorola 0x01  /* motorola prep */
@@ -212,13 +213,12 @@
 #define SR15	15
 
 #ifndef __ASSEMBLY__
+#ifndef CONFIG_MACH_SPECIFIC
 extern int _machine;
-
-/* Temporary hacks until we can clean things up better - Corey */
 extern int have_of;
-extern int is_prep;
 extern int is_chrp;
 extern int is_powerplus;
+#endif /* CONFIG_MACH_SPECIFIC */
 
 /* what kind of prep workstation we are */
 extern int _prep_type;
@@ -331,5 +331,28 @@
 
 #endif /* ndef ASSEMBLY*/
 
-  
+#ifdef CONFIG_MACH_SPECIFIC
+#if defined(CONFIG_PREP)
+#define _machine _MACH_prep
+#define have_of 0
+#elif defined(CONFIG_CHRP)
+#define _machine _MACH_chrp
+#define have_of 1
+#elif defined(CONFIG_PMAC)
+#define _machine _MACH_Pmac
+#define have_of 1
+#elif defined(CONFIG_8xx)
+#define _machine _MACH_8xx
+#define have_of 0
+#elif defined(CONFIG_APUS)
+#define _machine _MACH_apus
+#define have_of 0
+#elif defined(CONFIG_GEMINI)
+#define _machine _MACH_gemini
+#define have_of 0
+#else
+#error "Machine not defined correctly"
+#endif
+#endif /* CONFIG_MACH_SPECIFIC */
+
 #endif /* __ASM_PPC_PROCESSOR_H */
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/prom.h linux/include/asm-ppc/prom.h
--- v2.3.19/linux/include/asm-ppc/prom.h	Sun Nov 15 10:51:50 1998
+++ linux/include/asm-ppc/prom.h	Thu Oct  7 10:17:09 1999
@@ -65,6 +65,7 @@
 extern void abort(void);
 extern void prom_init(int, int, prom_entry);
 extern void prom_print(const char *msg);
+extern void relocate_nodes(void);
 extern void finish_device_tree(void);
 extern struct device_node *find_devices(const char *name);
 extern struct device_node *find_type_devices(const char *type);
@@ -72,7 +73,8 @@
 extern struct device_node *find_compatible_devices(const char *type,
 						   const char *compat);
 extern struct device_node *find_phandle(phandle);
-extern int device_is_compatible(struct device_node *device, const char* compat);
+extern int device_is_compatible(struct device_node *device, const char *);
+extern int machine_is_compatible(const char *compat);
 extern unsigned char *get_property(struct device_node *node, const char *name,
 				   int *lenp);
 extern void print_properties(struct device_node *node);
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/rpxclassic.h linux/include/asm-ppc/rpxclassic.h
--- v2.3.19/linux/include/asm-ppc/rpxclassic.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/rpxclassic.h	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,67 @@
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the RPCG RPX-Classic board.  Copied from the RPX-Lite stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifndef __MACH_RPX_DEFS
+#define __MACH_RPX_DEFS
+
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need.  The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define PCMCIA_MEM_ADDR		((uint)0x04000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+#define PCI_ISA_IO_ADDR		((unsigned)0x80000000)
+#define PCI_ISA_IO_SIZE		((uint)(512 * 1024 * 1024))
+#define PCI_ISA_MEM_ADDR	((unsigned)0xc0000000)
+#define PCI_ISA_MEM_SIZE	((uint)(512 * 1024 * 1024))
+#define RPX_CSR_ADDR		((uint)0xfa400000)
+#define RPX_CSR_SIZE		((uint)(4 * 1024))
+#define IMAP_ADDR		((uint)0xfa200000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define PCI_CSR_ADDR		((uint)0x80000000)
+#define PCI_CSR_SIZE		((uint)(64 * 1024))
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_ETHEN		((uint)0x80000000)
+#define BCSR0_ETHLPBK		((uint)0x40000000)
+#define BCSR0_COLTESTDIS	((uint)0x20000000)
+#define BCSR0_FULLDPLXDIS	((uint)0x10000000)
+#define BCSR0_ENFLSHSEL		((uint)0x04000000)
+#define BCSR0_FLASH_SEL		((uint)0x02000000)
+#define BCSR0_ENMONXCVR		((uint)0x01000000)
+
+#define BCSR2_EN232XCVR		((uint)0x00008000)
+#define BCSR2_QSPACESEL		((uint)0x00004000)
+
+/* Interrupt level assignments.
+*/
+#define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+/* Machine type
+*/
+#define _MACH_8xx (_MACH_rpxclassic)
+
+#endif
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/rpxlite.h linux/include/asm-ppc/rpxlite.h
--- v2.3.19/linux/include/asm-ppc/rpxlite.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/rpxlite.h	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,67 @@
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the RPCG RPX-Lite board.  Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifndef __MACH_RPX_DEFS
+#define __MACH_RPX_DEFS
+
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need.  The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define RPX_CSR_ADDR		((uint)0xfa400000)
+#define RPX_CSR_SIZE		((uint)(4 * 1024))
+#define IMAP_ADDR		((uint)0xfa200000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define HIOX_CSR_ADDR		((uint)0xfac00000)
+#define HIOX_CSR_SIZE		((uint)(4 * 1024))
+#define PCMCIA_MEM_ADDR		((uint)0x04000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+#define PCMCIA_IO_ADDR		((uint)0x04400000)
+#define PCMCIA_IO_SIZE		((uint)(4 * 1024))
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_ETHEN		((uint)0x80000000)
+#define BCSR0_ETHLPBK		((uint)0x40000000)
+#define BCSR0_COLTESTDIS	((uint)0x20000000)
+#define BCSR0_FULLDPLXDIS	((uint)0x10000000)
+#define BCSR0_LEDOFF		((uint)0x08000000)
+#define BCSR0_USBDISABLE	((uint)0x04000000)
+#define BCSR0_USBHISPEED	((uint)0x02000000)
+#define BCSR0_USBPWREN		((uint)0x01000000)
+#define BCSR0_PCMCIAVOLT	((uint)0x000f0000)
+#define BCSR0_PCMCIA3VOLT	((uint)0x000a0000)
+#define BCSR0_PCMCIA5VOLT	((uint)0x00060000)
+
+/* HIO Expansion card.
+*/
+#define HIOX_CSR_ENAUDIO	((uint)0x00000200)
+#define HIOX_CSR_RSTAUDIO	((uint)0x00000100)	/* 0 == reset */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+/* Machine type
+*/
+#define _MACH_8xx (_MACH_rpxlite)
+
+#endif
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/serial.h linux/include/asm-ppc/serial.h
--- v2.3.19/linux/include/asm-ppc/serial.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-ppc/serial.h	Thu Oct  7 10:17:09 1999
@@ -4,9 +4,6 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_APUS
-#include <asm-m68k/serial.h>
-#else
 #ifdef CONFIG_GEMINI
 #include <asm/gemini_serial.h>
 #else
@@ -20,20 +17,18 @@
  */
 #define BASE_BAUD ( 1843200 / 16 )
 
-#ifdef CONFIG_PMAC
-/*
- * Auto-probing will cause machine checks on powermacs.
- */
-#define SERIAL_PORT_DFNS
-  
 #ifdef CONFIG_SERIAL_MANY_PORTS
 #define RS_TABLE_SIZE  64
 #else
 #define RS_TABLE_SIZE  4
 #endif
 
-#else
+#ifdef CONFIG_PMAC
+/*
+ * Auto-probing will cause machine checks on powermacs.
+ */
 #define SERIAL_PORT_DFNS
+#else
 /*
  * PReP, CHRP, etc.
  */
@@ -143,4 +138,3 @@
 
 #endif /* CONFIG_PMAC */
 #endif /* CONFIG_GEMINI */
-#endif /* CONFIG_APUS */
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/shmparam.h linux/include/asm-ppc/shmparam.h
--- v2.3.19/linux/include/asm-ppc/shmparam.h	Sat Nov 25 09:49:06 1995
+++ linux/include/asm-ppc/shmparam.h	Thu Oct  7 10:17:09 1999
@@ -33,7 +33,7 @@
  * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS).
  */
 
-#define SHMMAX 0x3fa000			/* max shared seg size (bytes) */
+#define SHMMAX 0x2000000		/* max shared seg size (bytes) */
 #define SHMMIN 1 /* really PAGE_SIZE */	/* min shared seg size (bytes) */
 #define SHMMNI (1<<_SHM_ID_BITS)	/* max num of segs system wide */
 #define SHMALL				/* max shm system wide (pages) */ \
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/smp.h linux/include/asm-ppc/smp.h
--- v2.3.19/linux/include/asm-ppc/smp.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/smp.h	Thu Oct  7 10:17:09 1999
@@ -21,7 +21,6 @@
 };
 extern struct cpuinfo_PPC cpu_data[NR_CPUS];
 
-extern int first_cpu_booted;
 extern unsigned long smp_proc_in_lock[NR_CPUS];
 
 extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/spinlock.h linux/include/asm-ppc/spinlock.h
--- v2.3.19/linux/include/asm-ppc/spinlock.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-ppc/spinlock.h	Thu Oct  7 10:17:09 1999
@@ -1,10 +1,8 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
-/* Simple spin lock operations.  There are two variants, one clears IRQ's
- * on the local processor, one does not.
- *
- * We make no fairness assumptions. They have a cost.
+/*
+ * Simple spin lock operations.
  */
 
 typedef struct {
@@ -23,19 +21,6 @@
 
 #define spin_lock(lp)			_spin_lock(lp)
 #define spin_unlock(lp)			_spin_unlock(lp)
-
-#define spin_lock_irq(lock) \
-	do { __cli(); spin_lock(lock); } while (0)
-#define spin_lock_bh(___lk) do { local_bh_disable(); spin_lock(___lk); } while(0)
-
-#define spin_unlock_irq(lock) \
-	do { spin_unlock(lock); __sti(); } while (0)
-#define spin_unlock_bh(___lk) do { spin_unlock(___lk); local_bh_enable(); } while(0)
-
-#define spin_lock_irqsave(lock, flags) \
-	do { __save_flags(flags); __cli(); spin_lock(lock); } while (0)
-#define spin_unlock_irqrestore(lock, flags) \
-	do { spin_unlock(lock); __restore_flags(flags); } while (0)
 
 extern unsigned long __spin_trylock(volatile unsigned long *lock);
 
diff -u --recursive --new-file v2.3.19/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.3.19/linux/include/asm-ppc/system.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-ppc/system.h	Thu Oct  7 10:17:09 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: system.h,v 1.48 1999/09/05 11:56:40 paulus Exp $
+ * $Id: system.h,v 1.49 1999/09/11 18:37:54 cort Exp $
  *
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
  */
@@ -103,6 +103,11 @@
 #define restore_flags(x) __global_restore_flags(x)
 
 #endif /* !__SMP__ */
+
+#define local_irq_disable()		__cli()
+#define local_irq_enable()		__sti()
+#define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_restore(flags)	__restore_flags(flags)
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
diff -u --recursive --new-file v2.3.19/linux/include/linux/acpi.h linux/include/linux/acpi.h
--- v2.3.19/linux/include/linux/acpi.h	Mon Oct  4 15:49:30 1999
+++ linux/include/linux/acpi.h	Fri Oct  8 13:37:00 1999
@@ -38,21 +38,14 @@
 #define ACPI_FACP_SIG  0x50434146 /* 'FACP' */
 #define ACPI_DSDT_SIG  0x54445344 /* 'DSDT' */
 
-/* PM1_STS flags */
-#define ACPI_TMR_STS    0x0001
-#define ACPI_BM_STS     0x0010
-#define ACPI_GBL_STS    0x0020
-#define ACPI_PWRBTN_STS 0x0100
-#define ACPI_SLPBTN_STS 0x0200
-#define ACPI_RTC_STS    0x0400
-#define ACPI_WAK_STS    0x8000
-
-/* PM1_EN flags */
-#define ACPI_TMR_EN    0x0001
-#define ACPI_GBL_EN    0x0020
-#define ACPI_PWRBTN_EN 0x0100
-#define ACPI_SLPBTN_EN 0x0200
-#define ACPI_RTC_EN    0x0400
+/* PM1_STS/EN flags */
+#define ACPI_TMR    0x0001
+#define ACPI_BM     0x0010
+#define ACPI_GBL    0x0020
+#define ACPI_PWRBTN 0x0100
+#define ACPI_SLPBTN 0x0200
+#define ACPI_RTC    0x0400
+#define ACPI_WAK    0x8000
 
 /* PM1_CNT flags */
 #define ACPI_SCI_EN   0x0001
@@ -64,8 +57,12 @@
 #define ACPI_SLP_EN   0x2000
 
 /* PM_TMR masks */
-#define ACPI_TMR_VAL_MASK   0x00ffffff
-#define ACPI_E_TMR_VAL_MASK 0xff000000
+#define ACPI_TMR_MASK   0x00ffffff
+#define ACPI_TMR_HZ	3580000 /* 3.58 MHz */
+
+/* strangess to avoid integer overflow */
+#define ACPI_uS_TO_TMR_TICKS(val) \
+  (((val) * (ACPI_TMR_HZ / 10000)) / 100)
 
 /* PM2_CNT flags */
 #define ACPI_ARB_DIS 0x01
@@ -146,11 +143,29 @@
 };
 
 #define ACPI_FIND_TABLES	_IOR('A', 1, struct acpi_find_tables)
-#define ACPI_WAIT_EVENT		_IO('A', 2)
+#define ACPI_ENABLE_EVENT	_IOW('A', 2, struct acpi_enable_event)
+#define ACPI_WAIT_EVENT		_IOR('A', 3, struct acpi_wait_event)
 
 struct acpi_find_tables {
-	unsigned long facp;
-	unsigned long dsdt;
+	unsigned long facp; /* FACP physical address */
+	unsigned long dsdt; /* DSDT physical address */
+};
+
+struct acpi_enable_event {
+        __u32 pm1_enable; /* fixed events */
+        __u32 gpe_enable; /* general-purpose events (GPEs) */
+        __u32 gpe_level;  /* level-triggered GPEs */
+};
+
+struct acpi_wait_event {
+        __u32 pm1_status; /* fixed events */
+        __u32 gpe_status; /* general-purpose events */
 };
+
+#ifdef __KERNEL__
+
+extern void (*acpi_idle)(void);
+
+#endif
 
 #endif /* _LINUX_ACPI_H */
diff -u --recursive --new-file v2.3.19/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.3.19/linux/include/linux/dcache.h	Tue Jun  8 10:47:58 1999
+++ linux/include/linux/dcache.h	Thu Oct  7 12:47:37 1999
@@ -131,7 +131,6 @@
 
 /* allocate/de-allocate */
 extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
-extern void prune_dcache(int);
 extern void shrink_dcache_sb(struct super_block *);
 extern void shrink_dcache_parent(struct dentry *);
 extern int d_invalidate(struct dentry *);
@@ -139,10 +138,12 @@
 #define shrink_dcache() prune_dcache(0)
 
 /* dcache memory management */
-extern int  select_dcache(int, int);
-extern void shrink_dcache_memory(int, unsigned int);
-extern void check_dcache_memory(void);
-extern void free_inode_memory(int);	/* defined in fs/inode.c */
+extern int shrink_dcache_memory(int, unsigned int);
+extern void prune_dcache(int);
+
+/* icache memory management (defined in linux/fs/inode.c) */
+extern int shrink_icache_memory(int, int);
+extern void prune_icache(int);
 
 /* only used at mount-time */
 extern struct dentry * d_alloc_root(struct inode *);
diff -u --recursive --new-file v2.3.19/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.19/linux/include/linux/fs.h	Tue Sep  7 12:14:07 1999
+++ linux/include/linux/fs.h	Fri Oct  8 10:25:24 1999
@@ -45,7 +45,6 @@
 #define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
 
 /* And dynamically-tunable limits and defaults: */
-extern int max_inodes;
 extern int max_files, nr_files, nr_free_files;
 extern int max_super_blocks, nr_super_blocks;
 
@@ -270,6 +269,7 @@
 #include <linux/adfs_fs_i.h>
 #include <linux/qnx4_fs_i.h>
 #include <linux/udf_fs_i.h>
+#include <linux/ncp_fs_i.h>
 
 /*
  * Attribute flags.  These should be or-ed together to figure out what
@@ -383,6 +383,7 @@
 		struct adfs_inode_info		adfs_i;
 		struct qnx4_inode_info		qnx4_i;
 		struct udf_inode_info		udf_i;
+		struct ncp_inode_info		ncpfs_i;
 		struct socket			socket_i;
 		void				*generic_ip;
 	} u;
@@ -513,6 +514,7 @@
 #include <linux/adfs_fs_sb.h>
 #include <linux/qnx4_fs_sb.h>
 #include <linux/udf_fs_sb.h>
+#include <linux/ncp_fs_sb.h>
 
 extern struct list_head super_blocks;
 
@@ -558,6 +560,7 @@
 		struct adfs_sb_info	adfs_sb;
 		struct qnx4_sb_info	qnx4_sb;
 		struct udf_sb_info	udf_sb;
+		struct ncp_sb_info	ncpfs_sb;
 		void			*generic_sbp;
 	} u;
 	/*
diff -u --recursive --new-file v2.3.19/linux/include/linux/msg.h linux/include/linux/msg.h
--- v2.3.19/linux/include/linux/msg.h	Tue Aug 31 17:29:14 1999
+++ linux/include/linux/msg.h	Thu Oct  7 10:17:09 1999
@@ -11,31 +11,10 @@
 #define MSG_NOERROR     010000  /* no error if message is too big */
 #define MSG_EXCEPT      020000  /* recv any msg except of specified type.*/
 
-#ifdef __KERNEL__
-
-/* one msqid structure for each queue on the system */
-struct msqid_ds_kern {
-	struct ipc_perm msg_perm;
-	struct msg *msg_first;		/* first message on queue */
-	struct msg *msg_last;		/* last message in queue */
-	__kernel_time_t msg_stime;	/* last msgsnd time */
-	__kernel_time_t msg_rtime;	/* last msgrcv time */
-	__kernel_time_t msg_ctime;	/* last change time */
-	wait_queue_head_t wwait;
-	wait_queue_head_t rwait;
-	unsigned short msg_cbytes;	/* current number of bytes on queue */
-	unsigned short msg_qnum;	/* number of messages in queue */
-	unsigned short msg_qbytes;	/* max number of bytes on queue */
-	__kernel_ipc_pid_t msg_lspid;	/* pid of last msgsnd */
-	__kernel_ipc_pid_t msg_lrpid;	/* last receive pid */
-};
-
-#endif
-
 struct msqid_ds {
 	struct ipc_perm msg_perm;
-	struct msg *msg_first;		/* first message on queue */
-	struct msg *msg_last;		/* last message in queue */
+	struct msg *msg_first;		/* first message on queue,unused  */
+	struct msg *msg_last;		/* last message in queue,unused */
 	__kernel_time_t msg_stime;	/* last msgsnd time */
 	__kernel_time_t msg_rtime;	/* last msgrcv time */
 	__kernel_time_t msg_ctime;	/* last change time */
@@ -66,9 +45,9 @@
 	unsigned short  msgseg; 
 };
 
-#define MSGMNI   128   /* <= 1K */     /* max # of msg queue identifiers */
-#define MSGMAX  4056   /* <= 4056 */   /* max size of message (bytes) */
-#define MSGMNB 16384   /* ? */        /* default max size of a message queue */
+#define MSGMNI   128   /* <= 32768 */     /* max # of msg queue identifiers */
+#define MSGMAX  4056   /* <= 4056 (?)*/   /* max size of message (bytes) */
+#define MSGMNB 16384   /* <= MAX_INT */   /* default max size of a message queue */
 
 /* unused */
 #define MSGPOOL (MSGMNI*MSGMNB/1024)  /* size in kilobytes of message pool */
@@ -79,15 +58,6 @@
 #define MSGSEG (__MSGSEG <= 0xffff ? __MSGSEG : 0xffff)
 
 #ifdef __KERNEL__
-
-/* one msg structure for each message */
-struct msg {
-	struct msg *msg_next;   /* next message on queue */
-	long  msg_type;          
-	char *msg_spot;         /* message text address */
-	time_t msg_stime;       /* msgsnd time */
-	short msg_ts;           /* message text size */
-};
 
 asmlinkage long sys_msgget (key_t key, int msgflg);
 asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
diff -u --recursive --new-file v2.3.19/linux/include/linux/ncp.h linux/include/linux/ncp.h
--- v2.3.19/linux/include/linux/ncp.h	Wed Aug 18 16:45:22 1999
+++ linux/include/linux/ncp.h	Thu Oct  7 10:17:09 1999
@@ -11,7 +11,6 @@
 #define _LINUX_NCP_H
 
 #include <linux/types.h>
-#include <linux/ipx.h>
 
 #define NCP_PTYPE                (0x11)
 #define NCP_PORT                 (0x0451)
@@ -57,21 +56,6 @@
 	char volume_name[NCP_VOLNAME_LEN + 1];
 };
 
-/* these define the attribute byte as seen by NCP */
-#define aRONLY     (ntohl(0x01000000))
-#define aHIDDEN    (__constant_ntohl(0x02000000))
-#define aSYSTEM    (__constant_ntohl(0x04000000))
-#define aEXECUTE   (ntohl(0x08000000))
-#define aDIR       (ntohl(0x10000000))
-#define aARCH      (ntohl(0x20000000))
-#define aSHARED	   (ntohl(0x80000000))
-#define aDONTSUBALLOCATE (ntohl(1L<<(11+8)))
-#define aTRANSACTIONAL   (ntohl(1L<<(12+8)))
-#define aPURGE		 (ntohl(1L<<(16-8)))
-#define aRENAMEINHIBIT	 (ntohl(1L<<(17-8)))
-#define aDELETEINHIBIT	 (ntohl(1L<<(18-8)))
-#define aDONTCOMPRESS	 (nothl(1L<<(27-24)))
-
 #define AR_READ      (ntohs(0x0100))
 #define AR_WRITE     (ntohs(0x0200))
 #define AR_EXCLUSIVE (ntohs(0x2000))
@@ -184,15 +168,6 @@
 	__u16 inheritanceGrantMask __attribute__((packed));
 	__u16 inheritanceRevokeMask __attribute__((packed));
 	__u32 maximumSpace __attribute__((packed));
-};
-
-struct nw_file_info {
-	struct nw_info_struct i;
-	int opened;
-	int access;
-	__u32 server_file_handle __attribute__((packed));
-	__u8 open_create_action __attribute__((packed));
-	__u8 file_handle[6] __attribute__((packed));
 };
 
 struct nw_search_sequence {
diff -u --recursive --new-file v2.3.19/linux/include/linux/ncp_fs.h linux/include/linux/ncp_fs.h
--- v2.3.19/linux/include/linux/ncp_fs.h	Wed Aug 18 16:45:41 1999
+++ linux/include/linux/ncp_fs.h	Fri Oct  8 10:27:30 1999
@@ -12,18 +12,8 @@
 #include <linux/in.h>
 #include <linux/types.h>
 
-#include <linux/ncp_mount.h>
-
-/* NLS charsets by ioctl */
-#define NCP_IOCSNAME_LEN 20
-struct ncp_nls_ioctl
-{
-	unsigned char codepage[NCP_IOCSNAME_LEN+1];
-	unsigned char iocharset[NCP_IOCSNAME_LEN+1];
-};
-                
-#include <linux/ncp_fs_sb.h>
-#include <linux/ncp_fs_i.h>
+#include <linux/ipx.h>
+#include <linux/ncp_no.h>
 
 /*
  * ioctl commands
@@ -91,6 +81,14 @@
 	void*		data;		/* ~1000 for NDS */
 };
 
+/* NLS charsets by ioctl */
+#define NCP_IOCSNAME_LEN 20
+struct ncp_nls_ioctl
+{
+	unsigned char codepage[NCP_IOCSNAME_LEN+1];
+	unsigned char iocharset[NCP_IOCSNAME_LEN+1];
+};
+
 #define	NCP_IOC_NCPREQUEST		_IOR('n', 1, struct ncp_ioctl_request)
 #define	NCP_IOC_GETMOUNTUID		_IOW('n', 2, __kernel_uid_t)
 
@@ -123,6 +121,9 @@
 #define NCP_IOC_GETCHARSETS		_IOWR('n', 11, struct ncp_nls_ioctl)
 #define NCP_IOC_SETCHARSETS		_IOR('n', 11, struct ncp_nls_ioctl)
 
+#define NCP_IOC_GETDENTRYTTL		_IOW('n', 12, __u32)
+#define NCP_IOC_SETDENTRYTTL		_IOR('n', 12, __u32)
+
 /*
  * The packet size to allocate. One page should be enough.
  */
@@ -151,53 +152,27 @@
 #define DDPRINTK(format, args...)
 #endif
 
-/* The readdir cache size controls how many directory entries are
- * cached.
- */
-#define NCP_READDIR_CACHE_SIZE        64
-
 #define NCP_MAX_RPC_TIMEOUT (6*HZ)
 
-/*
- * This is the ncpfs part of the inode structure. This must contain
- * all the information we need to work with an inode after creation.
- * (Move to ncp_fs_i.h once it stabilizes, and add a union in fs.h)
- */
-struct ncpfs_i {
-	__u32	dirEntNum __attribute__((packed));
-	__u32	DosDirNum __attribute__((packed));
-	__u32	volNumber __attribute__((packed));
-#ifdef CONFIG_NCPFS_SMALLDOS
-	__u32	origNS;
-#endif
-#ifdef CONFIG_NCPFS_STRONG
-	__u32	nwattr;
-#endif
-	int	opened;
-	int	access;
-	__u32	server_file_handle __attribute__((packed));
-	__u8	open_create_action __attribute__((packed));
-	__u8	file_handle[6] __attribute__((packed));
-};
 
-/*
- * This is an extension of the nw_file_info structure with
- * the additional information we need to create an inode.
- */
-struct ncpfs_inode_info {
-	ino_t	ino;		/* dummy inode number */
-	struct nw_file_info nw_info;
+struct ncp_entry_info {
+	struct nw_info_struct	i;
+	ino_t			ino;
+	int			opened;
+	int			access;
+	__u32			server_file_handle __attribute__((packed));
+	__u8			open_create_action __attribute__((packed));
+	__u8			file_handle[6] __attribute__((packed));
 };
 
 /* Guess, what 0x564c is :-) */
 #define NCP_SUPER_MAGIC  0x564c
 
 
-#define NCP_SBP(sb)          ((struct ncp_server *)((sb)->u.generic_sbp))
+#define NCP_SBP(sb)		(&((sb)->u.ncpfs_sb))
 
-#define NCP_SERVER(inode)    NCP_SBP((inode)->i_sb)
-/* We don't have an ncpfs union yet, so use smbfs ... */
-#define NCP_FINFO(inode)     ((struct ncpfs_i *)&((inode)->u.smbfs_i))
+#define NCP_SERVER(inode)	NCP_SBP((inode)->i_sb)
+#define NCP_FINFO(inode)	(&((inode)->u.ncpfs_i))
 
 #ifdef DEBUG_NCP_MALLOC
 
@@ -230,17 +205,14 @@
 /* linux/fs/ncpfs/inode.c */
 int ncp_notify_change(struct dentry *, struct iattr *attr);
 struct super_block *ncp_read_super(struct super_block *, void *, int);
-struct inode *ncp_iget(struct super_block *, struct ncpfs_inode_info *);
-void ncp_update_inode(struct inode *, struct nw_file_info *);
-void ncp_update_inode2(struct inode *, struct nw_file_info *);
+struct inode *ncp_iget(struct super_block *, struct ncp_entry_info *);
+void ncp_update_inode(struct inode *, struct ncp_entry_info *);
+void ncp_update_inode2(struct inode *, struct ncp_entry_info *);
 extern int init_ncp_fs(void);
 
 /* linux/fs/ncpfs/dir.c */
 extern struct inode_operations ncp_dir_inode_operations;
-int ncp_conn_logged_in(struct ncp_server *);
-void ncp_init_dir_cache(void);
-void ncp_invalid_dir_cache(struct inode *);
-void ncp_free_dir_cache(void);
+int ncp_conn_logged_in(struct super_block *);
 int ncp_date_dos2unix(__u16 time, __u16 date);
 void ncp_date_unix2dos(int unix_date, __u16 * time, __u16 * date);
 
diff -u --recursive --new-file v2.3.19/linux/include/linux/ncp_fs_i.h linux/include/linux/ncp_fs_i.h
--- v2.3.19/linux/include/linux/ncp_fs_i.h	Wed Aug 18 16:45:39 1999
+++ linux/include/linux/ncp_fs_i.h	Thu Oct  7 10:17:09 1999
@@ -8,29 +8,24 @@
 #ifndef _LINUX_NCP_FS_I
 #define _LINUX_NCP_FS_I
 
-#include <linux/ncp.h>
-
 #ifdef __KERNEL__
 
-enum ncp_inode_state {
-	NCP_INODE_VALID = 19,	/* Inode currently in use */
-	NCP_INODE_LOOKED_UP,	/* directly before iget */
-	NCP_INODE_CACHED,	/* in a path to an inode which is in use */
-	NCP_INODE_INVALID
-};
-
 /*
- * ncp fs inode data (in memory only)
+ * This is the ncpfs part of the inode structure. This must contain
+ * all the information we need to work with an inode after creation.
  */
 struct ncp_inode_info {
-	enum ncp_inode_state state;
-	int nused;		/* for directories:
-				   number of references in memory */
-	struct ncp_inode_info *dir;
-	struct ncp_inode_info *next, *prev;
-	struct inode *inode;
-	struct nw_file_info finfo;
+	__u32	dirEntNum __attribute__((packed));
+	__u32	DosDirNum __attribute__((packed));
+	__u32	volNumber __attribute__((packed));
+	__u32	nwattr;
+	int	opened;
+	int	access;
+	__u32	server_file_handle __attribute__((packed));
+	__u8	open_create_action __attribute__((packed));
+	__u8	file_handle[6] __attribute__((packed));
 };
 
-#endif
-#endif
+#endif	/* __KERNEL__ */
+
+#endif	/* _LINUX_NCP_FS_I */
diff -u --recursive --new-file v2.3.19/linux/include/linux/ncp_fs_sb.h linux/include/linux/ncp_fs_sb.h
--- v2.3.19/linux/include/linux/ncp_fs_sb.h	Wed Aug 18 16:45:41 1999
+++ linux/include/linux/ncp_fs_sb.h	Thu Oct  7 10:17:09 1999
@@ -8,9 +8,8 @@
 #ifndef _NCP_FS_SB
 #define _NCP_FS_SB
 
-#include <asm/semaphore.h>
-#include <linux/ncp_mount.h>
 #include <linux/types.h>
+#include <linux/ncp_mount.h>
 
 #ifdef __KERNEL__
 
@@ -51,9 +50,6 @@
 	int has_subfunction;
 	int ncp_reply_size;
 
-	struct ncp_inode_info root;
-	struct dentry* root_dentry;
-
 	int root_setuped;
 
 /* info for packet signing */
@@ -75,10 +71,16 @@
 		void*  data;
 	} priv;
 
-	struct ncp_nls_ioctl nls_charsets;	/* NLS user data */
-	struct nls_table *nls_vol;    /* codepage used on volume */
-	struct nls_table *nls_io;     /* charset used for input and display */
+	/* nls info: codepage for volume and charset for I/O */
+	struct nls_table *nls_vol;
+	struct nls_table *nls_io;
+
+	/* maximum age in jiffies */
+	int dentry_ttl;
 };
+
+#define ncp_sb_info	ncp_server
+
 
 static inline int ncp_conn_valid(struct ncp_server *server)
 {
diff -u --recursive --new-file v2.3.19/linux/include/linux/ncp_mount.h linux/include/linux/ncp_mount.h
--- v2.3.19/linux/include/linux/ncp_mount.h	Wed Aug 18 16:45:40 1999
+++ linux/include/linux/ncp_mount.h	Thu Oct  7 10:17:09 1999
@@ -9,9 +9,7 @@
 #define _LINUX_NCP_MOUNT_H
 
 #include <linux/types.h>
-#include <linux/ipx.h>
 #include <linux/ncp.h>
-#include <linux/ncp_fs_i.h>
 
 #define NCP_MOUNT_VERSION 3
 
diff -u --recursive --new-file v2.3.19/linux/include/linux/ncp_no.h linux/include/linux/ncp_no.h
--- v2.3.19/linux/include/linux/ncp_no.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/ncp_no.h	Thu Oct  7 10:17:09 1999
@@ -0,0 +1,19 @@
+#ifndef _NCP_NO
+#define _NCP_NO
+
+/* these define the attribute byte as seen by NCP */
+#define aRONLY			(ntohl(0x01000000))
+#define aHIDDEN			(__constant_ntohl(0x02000000))
+#define aSYSTEM			(__constant_ntohl(0x04000000))
+#define aEXECUTE		(ntohl(0x08000000))
+#define aDIR			(ntohl(0x10000000))
+#define aARCH			(ntohl(0x20000000))
+#define aSHARED			(ntohl(0x80000000))
+#define aDONTSUBALLOCATE	(ntohl(1L<<(11+8)))
+#define aTRANSACTIONAL		(ntohl(1L<<(12+8)))
+#define aPURGE			(ntohl(1L<<(16-8)))
+#define aRENAMEINHIBIT		(ntohl(1L<<(17-8)))
+#define aDELETEINHIBIT		(ntohl(1L<<(18-8)))
+#define aDONTCOMPRESS		(nothl(1L<<(27-24)))
+
+#endif /* _NCP_NO */
diff -u --recursive --new-file v2.3.19/linux/include/linux/netfilter.h linux/include/linux/netfilter.h
--- v2.3.19/linux/include/linux/netfilter.h	Fri Sep 10 23:57:37 1999
+++ linux/include/linux/netfilter.h	Fri Oct  8 10:26:36 1999
@@ -77,7 +77,8 @@
 int nf_register_hook(struct nf_hook_ops *reg);
 void nf_unregister_hook(struct nf_hook_ops *reg);
 
-/* Functions to register get/setsockopt ranges (non-inclusive). */
+/* Functions to register get/setsockopt ranges (non-inclusive).  You
+   need to check permissions yourself! */
 int nf_register_sockopt(struct nf_sockopt_ops *reg);
 void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
 
diff -u --recursive --new-file v2.3.19/linux/include/linux/netfilter_ipv4.h linux/include/linux/netfilter_ipv4.h
--- v2.3.19/linux/include/linux/netfilter_ipv4.h	Tue Aug 31 17:29:14 1999
+++ linux/include/linux/netfilter_ipv4.h	Fri Oct  8 10:26:39 1999
@@ -58,4 +58,10 @@
 #endif /*__KERNEL__*/
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
+/* Arguments for setsockopt SOL_IP: */
+/* 2.0 firewalling went from 64 through 71 (and +256, +512, etc). */
+/* 2.2 firewalling (+ masq) went from 64 through 76 */
+/* 2.4 firewalling went 64 through 67. */
+#define SO_ORIGINAL_DST 80
+
 #endif /*__LINUX_IP_NETFILTER_H*/
diff -u --recursive --new-file v2.3.19/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.3.19/linux/include/linux/parport.h	Fri Sep 10 23:57:37 1999
+++ linux/include/linux/parport.h	Fri Oct  8 10:34:31 1999
@@ -13,6 +13,7 @@
 #define PARPORT_DMA_NONE  -1
 #define PARPORT_IRQ_AUTO  -2
 #define PARPORT_DMA_AUTO  -2
+#define PARPORT_DMA_NOFIFO -3
 #define PARPORT_DISABLE   -2
 #define PARPORT_IRQ_PROBEONLY -3
 
diff -u --recursive --new-file v2.3.19/linux/include/linux/parport_pc.h linux/include/linux/parport_pc.h
--- v2.3.19/linux/include/linux/parport_pc.h	Wed Aug 18 16:43:46 1999
+++ linux/include/linux/parport_pc.h	Fri Oct  8 10:34:08 1999
@@ -41,33 +41,50 @@
 
 extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
 {
+#ifdef DEBUG_PARPORT
+	printk (KERN_DEBUG "parport_pc_write_data(%p,0x%02x)\n", p, d);
+#endif
 	outb(d, DATA(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
 {
-	return inb(DATA(p));
+	unsigned char val = inb (DATA (p));
+#ifdef DEBUG_PARPORT
+	printk (KERN_DEBUG "parport_pc_read_data(%p) = 0x%02x\n",
+		p, val);
+#endif
+	return val;
 }
 
-extern __inline__ unsigned char __frob_control (struct parport *p,
-						unsigned char mask,
-						unsigned char val)
+/* __parport_pc_frob_control differs from parport_pc_frob_control in that
+ * it doesn't do any extra masking. */
+static __inline__ unsigned char __parport_pc_frob_control (struct parport *p,
+							   unsigned char mask,
+							   unsigned char val)
 {
-	const unsigned char wm = (PARPORT_CONTROL_STROBE |
-				  PARPORT_CONTROL_AUTOFD |
-				  PARPORT_CONTROL_INIT |
-				  PARPORT_CONTROL_SELECT);
 	struct parport_pc_private *priv = p->physport->private_data;
 	unsigned char ctr = priv->ctr;
+#ifdef DEBUG_PARPORT
+	printk (KERN_DEBUG
+		"__parport_pc_frob_control(%02x,%02x): %02x -> %02x\n",
+		mask, val, ctr, ((ctr & ~mask) ^ val) & priv->ctr_writable);
+#endif
 	ctr = (ctr & ~mask) ^ val;
 	ctr &= priv->ctr_writable; /* only write writable bits. */
 	outb (ctr, CONTROL (p));
-	return priv->ctr = ctr & wm; /* update soft copy */
+	priv->ctr = ctr;	/* Update soft copy */
+	return ctr;
 }
 
 extern __inline__ void parport_pc_data_reverse (struct parport *p)
 {
-	__frob_control (p, 0x20, 0x20);
+	__parport_pc_frob_control (p, 0x20, 0x20);
+}
+
+extern __inline__ void parport_pc_data_forward (struct parport *p)
+{
+	__parport_pc_frob_control (p, 0x20, 0x00);
 }
 
 extern __inline__ void parport_pc_write_control (struct parport *p,
@@ -80,18 +97,22 @@
 
 	/* Take this out when drivers have adapted to newer interface. */
 	if (d & 0x20) {
-			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
-					p->name, p->cad->name);
-			parport_pc_data_reverse (p);
+		printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+			p->name, p->cad->name);
+		parport_pc_data_reverse (p);
 	}
 
-	__frob_control (p, wm, d & wm);
+	__parport_pc_frob_control (p, wm, d & wm);
 }
 
 extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
 {
+	const unsigned char rm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
 	const struct parport_pc_private *priv = p->physport->private_data;
-	return priv->ctr; /* Use soft copy */
+	return priv->ctr & rm; /* Use soft copy */
 }
 
 extern __inline__ unsigned char parport_pc_frob_control (struct parport *p,
@@ -105,16 +126,20 @@
 
 	/* Take this out when drivers have adapted to newer interface. */
 	if (mask & 0x20) {
-			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
-					p->name, p->cad->name);
+		printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
+			p->name, p->cad->name,
+			(val & 0x20) ? "reverse" : "forward");
+		if (val & 0x20)
 			parport_pc_data_reverse (p);
+		else
+			parport_pc_data_forward (p);
 	}
 
 	/* Restrict mask and val to control lines. */
 	mask &= wm;
 	val &= wm;
 
-	return __frob_control (p, mask, val);
+	return __parport_pc_frob_control (p, mask, val);
 }
 
 extern __inline__ unsigned char parport_pc_read_status(struct parport *p)
@@ -122,19 +147,15 @@
 	return inb(STATUS(p));
 }
 
-extern __inline__ void parport_pc_data_forward (struct parport *p)
-{
-	__frob_control (p, 0x20, 0x00);
-}
 
 extern __inline__ void parport_pc_disable_irq(struct parport *p)
 {
-	__frob_control (p, 0x10, 0x00);
+	__parport_pc_frob_control (p, 0x10, 0x00);
 }
 
 extern __inline__ void parport_pc_enable_irq(struct parport *p)
 {
-	__frob_control (p, 0x10, 0x10);
+	__parport_pc_frob_control (p, 0x10, 0x10);
 }
 
 extern void parport_pc_release_resources(struct parport *p);
diff -u --recursive --new-file v2.3.19/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.19/linux/include/linux/pci.h	Mon Oct  4 15:49:30 1999
+++ linux/include/linux/pci.h	Fri Oct  8 10:25:18 1999
@@ -262,1097 +262,9 @@
 #define PCI_MSI_DATA_32		8	/* 16 bits of data for 32-bit devices */
 #define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
 
-/* Device classes and subclasses */
+/* Include the ID list */
 
-#define PCI_CLASS_NOT_DEFINED		0x0000
-#define PCI_CLASS_NOT_DEFINED_VGA	0x0001
-
-#define PCI_BASE_CLASS_STORAGE		0x01
-#define PCI_CLASS_STORAGE_SCSI		0x0100
-#define PCI_CLASS_STORAGE_IDE		0x0101
-#define PCI_CLASS_STORAGE_FLOPPY	0x0102
-#define PCI_CLASS_STORAGE_IPI		0x0103
-#define PCI_CLASS_STORAGE_RAID		0x0104
-#define PCI_CLASS_STORAGE_OTHER		0x0180
-
-#define PCI_BASE_CLASS_NETWORK		0x02
-#define PCI_CLASS_NETWORK_ETHERNET	0x0200
-#define PCI_CLASS_NETWORK_TOKEN_RING	0x0201
-#define PCI_CLASS_NETWORK_FDDI		0x0202
-#define PCI_CLASS_NETWORK_ATM		0x0203
-#define PCI_CLASS_NETWORK_OTHER		0x0280
-
-#define PCI_BASE_CLASS_DISPLAY		0x03
-#define PCI_CLASS_DISPLAY_VGA		0x0300
-#define PCI_CLASS_DISPLAY_XGA		0x0301
-#define PCI_CLASS_DISPLAY_OTHER		0x0380
-
-#define PCI_BASE_CLASS_MULTIMEDIA	0x04
-#define PCI_CLASS_MULTIMEDIA_VIDEO	0x0400
-#define PCI_CLASS_MULTIMEDIA_AUDIO	0x0401
-#define PCI_CLASS_MULTIMEDIA_OTHER	0x0480
-
-#define PCI_BASE_CLASS_MEMORY		0x05
-#define  PCI_CLASS_MEMORY_RAM		0x0500
-#define  PCI_CLASS_MEMORY_FLASH		0x0501
-#define  PCI_CLASS_MEMORY_OTHER		0x0580
-
-#define PCI_BASE_CLASS_BRIDGE		0x06
-#define  PCI_CLASS_BRIDGE_HOST		0x0600
-#define  PCI_CLASS_BRIDGE_ISA		0x0601
-#define  PCI_CLASS_BRIDGE_EISA		0x0602
-#define  PCI_CLASS_BRIDGE_MC		0x0603
-#define  PCI_CLASS_BRIDGE_PCI		0x0604
-#define  PCI_CLASS_BRIDGE_PCMCIA	0x0605
-#define  PCI_CLASS_BRIDGE_NUBUS		0x0606
-#define  PCI_CLASS_BRIDGE_CARDBUS	0x0607
-#define  PCI_CLASS_BRIDGE_OTHER		0x0680
-
-#define PCI_BASE_CLASS_COMMUNICATION	0x07
-#define PCI_CLASS_COMMUNICATION_SERIAL	0x0700
-#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
-#define PCI_CLASS_COMMUNICATION_OTHER	0x0780
-
-#define PCI_BASE_CLASS_SYSTEM		0x08
-#define PCI_CLASS_SYSTEM_PIC		0x0800
-#define PCI_CLASS_SYSTEM_DMA		0x0801
-#define PCI_CLASS_SYSTEM_TIMER		0x0802
-#define PCI_CLASS_SYSTEM_RTC		0x0803
-#define PCI_CLASS_SYSTEM_OTHER		0x0880
-
-#define PCI_BASE_CLASS_INPUT		0x09
-#define PCI_CLASS_INPUT_KEYBOARD	0x0900
-#define PCI_CLASS_INPUT_PEN		0x0901
-#define PCI_CLASS_INPUT_MOUSE		0x0902
-#define PCI_CLASS_INPUT_OTHER		0x0980
-
-#define PCI_BASE_CLASS_DOCKING		0x0a
-#define PCI_CLASS_DOCKING_GENERIC	0x0a00
-#define PCI_CLASS_DOCKING_OTHER		0x0a01
-
-#define PCI_BASE_CLASS_PROCESSOR	0x0b
-#define PCI_CLASS_PROCESSOR_386		0x0b00
-#define PCI_CLASS_PROCESSOR_486		0x0b01
-#define PCI_CLASS_PROCESSOR_PENTIUM	0x0b02
-#define PCI_CLASS_PROCESSOR_ALPHA	0x0b10
-#define PCI_CLASS_PROCESSOR_POWERPC	0x0b20
-#define PCI_CLASS_PROCESSOR_CO		0x0b40
-
-#define PCI_BASE_CLASS_SERIAL		0x0c
-#define PCI_CLASS_SERIAL_FIREWIRE	0x0c00
-#define PCI_CLASS_SERIAL_ACCESS		0x0c01
-#define PCI_CLASS_SERIAL_SSA		0x0c02
-#define PCI_CLASS_SERIAL_USB		0x0c03
-#define PCI_CLASS_SERIAL_FIBER		0x0c04
-
-#define PCI_BASE_CLASS_INTELLIGENT	0x0e
-#define PCI_CLASS_INTELLIGENT_I2O	0x0e00
-
-#define PCI_CLASS_HOT_SWAP_CONTROLLER	0xff00
-
-#define PCI_CLASS_OTHERS		0xff
-
-/*
- * Vendor and card ID's: sort these numerically according to vendor
- * (and according to card ID within vendor). Send all updates to
- * <pci-ids@ucw.cz>.
- */
-#define PCI_VENDOR_ID_COMPAQ		0x0e11
-#define PCI_DEVICE_ID_COMPAQ_TOKENRING	0x0508
-#define PCI_DEVICE_ID_COMPAQ_1280	0x3033
-#define PCI_DEVICE_ID_COMPAQ_TRIFLEX	0x4000
-#define PCI_DEVICE_ID_COMPAQ_SMART2P	0xae10
-#define PCI_DEVICE_ID_COMPAQ_NETEL100	0xae32
-#define PCI_DEVICE_ID_COMPAQ_NETEL10	0xae34
-#define PCI_DEVICE_ID_COMPAQ_NETFLEX3I	0xae35
-#define PCI_DEVICE_ID_COMPAQ_NETEL100D	0xae40
-#define PCI_DEVICE_ID_COMPAQ_NETEL100PI	0xae43
-#define PCI_DEVICE_ID_COMPAQ_NETEL100I	0xb011
-#define PCI_DEVICE_ID_COMPAQ_THUNDER	0xf130
-#define PCI_DEVICE_ID_COMPAQ_NETFLEX3B	0xf150
-
-#define PCI_VENDOR_ID_NCR		0x1000
-#define PCI_DEVICE_ID_NCR_53C810	0x0001
-#define PCI_DEVICE_ID_NCR_53C820	0x0002
-#define PCI_DEVICE_ID_NCR_53C825	0x0003
-#define PCI_DEVICE_ID_NCR_53C815	0x0004
-#define PCI_DEVICE_ID_NCR_53C860	0x0006
-#define PCI_DEVICE_ID_NCR_53C896	0x000b
-#define PCI_DEVICE_ID_NCR_53C895	0x000c
-#define PCI_DEVICE_ID_NCR_53C885	0x000d
-#define PCI_DEVICE_ID_NCR_53C875	0x000f
-#define PCI_DEVICE_ID_NCR_53C1510	0x0010
-#define PCI_DEVICE_ID_NCR_53C875J	0x008f
-
-#define PCI_VENDOR_ID_ATI		0x1002
-#define PCI_DEVICE_ID_ATI_68800		0x4158
-#define PCI_DEVICE_ID_ATI_215CT222	0x4354
-#define PCI_DEVICE_ID_ATI_210888CX	0x4358
-#define PCI_DEVICE_ID_ATI_215GB		0x4742
-#define PCI_DEVICE_ID_ATI_215GD		0x4744
-#define PCI_DEVICE_ID_ATI_215GI		0x4749
-#define PCI_DEVICE_ID_ATI_215GP		0x4750
-#define PCI_DEVICE_ID_ATI_215GQ		0x4751
-#define PCI_DEVICE_ID_ATI_215GT		0x4754
-#define PCI_DEVICE_ID_ATI_215GTB	0x4755
-#define PCI_DEVICE_ID_ATI_210888GX	0x4758
-#define PCI_DEVICE_ID_ATI_215LG		0x4c47
-#define PCI_DEVICE_ID_ATI_264LT		0x4c54
-#define PCI_DEVICE_ID_ATI_264VT		0x5654
-
-#define PCI_VENDOR_ID_VLSI		0x1004
-#define PCI_DEVICE_ID_VLSI_82C592	0x0005
-#define PCI_DEVICE_ID_VLSI_82C593	0x0006
-#define PCI_DEVICE_ID_VLSI_82C594	0x0007
-#define PCI_DEVICE_ID_VLSI_82C597	0x0009
-#define PCI_DEVICE_ID_VLSI_82C541	0x000c
-#define PCI_DEVICE_ID_VLSI_82C543	0x000d
-#define PCI_DEVICE_ID_VLSI_82C532	0x0101
-#define PCI_DEVICE_ID_VLSI_82C534	0x0102
-#define PCI_DEVICE_ID_VLSI_82C535	0x0104
-#define PCI_DEVICE_ID_VLSI_82C147	0x0105
-#define PCI_DEVICE_ID_VLSI_VAS96011	0x0702
-
-#define PCI_VENDOR_ID_ADL		0x1005
-#define PCI_DEVICE_ID_ADL_2301		0x2301
-
-#define PCI_VENDOR_ID_NS		0x100b
-#define PCI_DEVICE_ID_NS_87415		0x0002
-#define PCI_DEVICE_ID_NS_87410		0xd001
-
-#define PCI_VENDOR_ID_TSENG		0x100c
-#define PCI_DEVICE_ID_TSENG_W32P_2	0x3202
-#define PCI_DEVICE_ID_TSENG_W32P_b	0x3205
-#define PCI_DEVICE_ID_TSENG_W32P_c	0x3206
-#define PCI_DEVICE_ID_TSENG_W32P_d	0x3207
-#define PCI_DEVICE_ID_TSENG_ET6000	0x3208
-
-#define PCI_VENDOR_ID_WEITEK		0x100e
-#define PCI_DEVICE_ID_WEITEK_P9000	0x9001
-#define PCI_DEVICE_ID_WEITEK_P9100	0x9100
-
-#define PCI_VENDOR_ID_DEC		0x1011
-#define PCI_DEVICE_ID_DEC_BRD		0x0001
-#define PCI_DEVICE_ID_DEC_TULIP		0x0002
-#define PCI_DEVICE_ID_DEC_TGA		0x0004
-#define PCI_DEVICE_ID_DEC_TULIP_FAST	0x0009
-#define PCI_DEVICE_ID_DEC_TGA2		0x000D
-#define PCI_DEVICE_ID_DEC_FDDI		0x000F
-#define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014
-#define PCI_DEVICE_ID_DEC_21142		0x0019
-#define PCI_DEVICE_ID_DEC_21052		0x0021
-#define PCI_DEVICE_ID_DEC_21150		0x0022
-#define PCI_DEVICE_ID_DEC_21152		0x0024
-#define PCI_DEVICE_ID_DEC_21153		0x0025
-#define PCI_DEVICE_ID_DEC_21154		0x0026
-#define PCI_DEVICE_ID_DEC_21285		0x1065
-#define PCI_DEVICE_ID_COMPAQ_42XX	0x0046
-
-#define PCI_VENDOR_ID_CIRRUS		0x1013
-#define PCI_DEVICE_ID_CIRRUS_7548	0x0038
-#define PCI_DEVICE_ID_CIRRUS_5430	0x00a0
-#define PCI_DEVICE_ID_CIRRUS_5434_4	0x00a4
-#define PCI_DEVICE_ID_CIRRUS_5434_8	0x00a8
-#define PCI_DEVICE_ID_CIRRUS_5436	0x00ac
-#define PCI_DEVICE_ID_CIRRUS_5446	0x00b8
-#define PCI_DEVICE_ID_CIRRUS_5480	0x00bc
-#define PCI_DEVICE_ID_CIRRUS_5462	0x00d0
-#define PCI_DEVICE_ID_CIRRUS_5464	0x00d4
-#define PCI_DEVICE_ID_CIRRUS_5465	0x00d6
-#define PCI_DEVICE_ID_CIRRUS_6729	0x1100
-#define PCI_DEVICE_ID_CIRRUS_6832	0x1110
-#define PCI_DEVICE_ID_CIRRUS_7542	0x1200
-#define PCI_DEVICE_ID_CIRRUS_7543	0x1202
-#define PCI_DEVICE_ID_CIRRUS_7541	0x1204
-
-#define PCI_VENDOR_ID_IBM		0x1014
-#define PCI_DEVICE_ID_IBM_FIRE_CORAL	0x000a
-#define PCI_DEVICE_ID_IBM_TR		0x0018
-#define PCI_DEVICE_ID_IBM_82G2675	0x001d
-#define PCI_DEVICE_ID_IBM_MCA		0x0020
-#define PCI_DEVICE_ID_IBM_82351		0x0022
-#define PCI_DEVICE_ID_IBM_PYTHON	0x002d
-#define PCI_DEVICE_ID_IBM_SERVERAID	0x002e
-#define PCI_DEVICE_ID_IBM_TR_WAKE	0x003e
-#define PCI_DEVICE_ID_IBM_MPIC		0x0046
-#define PCI_DEVICE_ID_IBM_3780IDSP	0x007d
-#define PCI_DEVICE_ID_IBM_MPIC_2	0xffff
-
-#define PCI_VENDOR_ID_WD		0x101c
-#define PCI_DEVICE_ID_WD_7197		0x3296
-
-#define PCI_VENDOR_ID_AMD		0x1022
-#define PCI_DEVICE_ID_AMD_LANCE		0x2000
-#define PCI_DEVICE_ID_AMD_LANCE_HOME	0x2001
-#define PCI_DEVICE_ID_AMD_SCSI		0x2020
-
-#define PCI_VENDOR_ID_TRIDENT		0x1023
-#define PCI_DEVICE_ID_TRIDENT_9320	0x9320
-#define PCI_DEVICE_ID_TRIDENT_9388	0x9388
-#define PCI_DEVICE_ID_TRIDENT_9397	0x9397
-#define PCI_DEVICE_ID_TRIDENT_939A	0x939A
-#define PCI_DEVICE_ID_TRIDENT_9520	0x9520
-#define PCI_DEVICE_ID_TRIDENT_9525	0x9525
-#define PCI_DEVICE_ID_TRIDENT_9420	0x9420
-#define PCI_DEVICE_ID_TRIDENT_9440	0x9440
-#define PCI_DEVICE_ID_TRIDENT_9660	0x9660
-#define PCI_DEVICE_ID_TRIDENT_9750	0x9750
-#define PCI_DEVICE_ID_TRIDENT_9850	0x9850
-#define PCI_DEVICE_ID_TRIDENT_9880	0x9880
-#define PCI_DEVICE_ID_TRIDENT_8400	0x8400
-#define PCI_DEVICE_ID_TRIDENT_8420	0x8420
-#define PCI_DEVICE_ID_TRIDENT_8500	0x8500
-
-#define PCI_VENDOR_ID_AI		0x1025
-#define PCI_DEVICE_ID_AI_M1435		0x1435
-
-#define PCI_VENDOR_ID_MATROX		0x102B
-#define PCI_DEVICE_ID_MATROX_MGA_2	0x0518
-#define PCI_DEVICE_ID_MATROX_MIL	0x0519
-#define PCI_DEVICE_ID_MATROX_MYS	0x051A
-#define PCI_DEVICE_ID_MATROX_MIL_2	0x051b
-#define PCI_DEVICE_ID_MATROX_MIL_2_AGP	0x051f
-#define PCI_DEVICE_ID_MATROX_MGA_IMP	0x0d10
-#define PCI_DEVICE_ID_MATROX_G100_MM    0x1000
-#define PCI_DEVICE_ID_MATROX_G100_AGP   0x1001
-#define PCI_DEVICE_ID_MATROX_G200_PCI   0x0520
-#define PCI_DEVICE_ID_MATROX_G200_AGP   0x0521
-#define	PCI_DEVICE_ID_MATROX_G400	0x0525
-#define PCI_DEVICE_ID_MATROX_VIA	0x4536
-
-#define PCI_VENDOR_ID_CT		0x102c
-#define PCI_DEVICE_ID_CT_65545		0x00d8
-#define PCI_DEVICE_ID_CT_65548		0x00dc
-#define PCI_DEVICE_ID_CT_65550		0x00e0
-#define PCI_DEVICE_ID_CT_65554		0x00e4
-#define PCI_DEVICE_ID_CT_65555		0x00e5
-
-#define PCI_VENDOR_ID_MIRO		0x1031
-#define PCI_DEVICE_ID_MIRO_36050	0x5601
-
-#define PCI_VENDOR_ID_NEC		0x1033
-#define PCI_DEVICE_ID_NEC_PCX2		0x0046
-
-#define PCI_VENDOR_ID_FD		0x1036
-#define PCI_DEVICE_ID_FD_36C70		0x0000
-
-#define PCI_VENDOR_ID_SI		0x1039
-#define PCI_DEVICE_ID_SI_5591_AGP	0x0001
-#define PCI_DEVICE_ID_SI_6202		0x0002
-#define PCI_DEVICE_ID_SI_503		0x0008
-#define PCI_DEVICE_ID_SI_ACPI		0x0009
-#define PCI_DEVICE_ID_SI_5597_VGA	0x0200
-#define PCI_DEVICE_ID_SI_6205		0x0205
-#define PCI_DEVICE_ID_SI_501		0x0406
-#define PCI_DEVICE_ID_SI_496		0x0496
-#define PCI_DEVICE_ID_SI_530		0x0530
-#define PCI_DEVICE_ID_SI_601		0x0601
-#define PCI_DEVICE_ID_SI_620		0x0620
-#define PCI_DEVICE_ID_SI_5107		0x5107
-#define PCI_DEVICE_ID_SI_5511		0x5511
-#define PCI_DEVICE_ID_SI_5513		0x5513
-#define PCI_DEVICE_ID_SI_5571		0x5571
-#define PCI_DEVICE_ID_SI_5591		0x5591
-#define PCI_DEVICE_ID_SI_5597		0x5597
-#define PCI_DEVICE_ID_SI_5600		0x5600
-#define PCI_DEVICE_ID_SI_6306		0x6306
-#define PCI_DEVICE_ID_SI_6326		0x6326
-#define PCI_DEVICE_ID_SI_7001		0x7001
-
-#define PCI_VENDOR_ID_HP		0x103c
-#define PCI_DEVICE_ID_HP_J2585A		0x1030
-#define PCI_DEVICE_ID_HP_J2585B		0x1031
-
-#define PCI_VENDOR_ID_PCTECH		0x1042
-#define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
-#define PCI_DEVICE_ID_PCTECH_RZ1001	0x1001
-#define PCI_DEVICE_ID_PCTECH_SAMURAI_0	0x3000
-#define PCI_DEVICE_ID_PCTECH_SAMURAI_1	0x3010
-#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020
-
-#define PCI_VENDOR_ID_DPT               0x1044   
-#define PCI_DEVICE_ID_DPT               0xa400  
-
-#define PCI_VENDOR_ID_OPTI		0x1045
-#define PCI_DEVICE_ID_OPTI_92C178	0xc178
-#define PCI_DEVICE_ID_OPTI_82C557	0xc557
-#define PCI_DEVICE_ID_OPTI_82C558	0xc558
-#define PCI_DEVICE_ID_OPTI_82C621	0xc621
-#define PCI_DEVICE_ID_OPTI_82C700	0xc700
-#define PCI_DEVICE_ID_OPTI_82C701	0xc701
-#define PCI_DEVICE_ID_OPTI_82C814	0xc814
-#define PCI_DEVICE_ID_OPTI_82C822	0xc822
-#define PCI_DEVICE_ID_OPTI_82C861	0xc861
-#define PCI_DEVICE_ID_OPTI_82C825	0xd568
-
-#define PCI_VENDOR_ID_SGS		0x104a
-#define PCI_DEVICE_ID_SGS_2000		0x0008
-#define PCI_DEVICE_ID_SGS_1764		0x0009
-
-#define PCI_VENDOR_ID_BUSLOGIC		      0x104B
-#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
-#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER    0x1040
-#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT     0x8130
-
-#define PCI_VENDOR_ID_TI		0x104c
-#define PCI_DEVICE_ID_TI_TVP4010	0x3d04
-#define PCI_DEVICE_ID_TI_TVP4020	0x3d07
-#define PCI_DEVICE_ID_TI_PCI1130	0xac12
-#define PCI_DEVICE_ID_TI_PCI1031	0xac13
-#define PCI_DEVICE_ID_TI_PCI1131	0xac15
-#define PCI_DEVICE_ID_TI_PCI1250	0xac16
-#define PCI_DEVICE_ID_TI_PCI1220	0xac17
-
-#define PCI_VENDOR_ID_OAK		0x104e
-#define PCI_DEVICE_ID_OAK_OTI107	0x0107
-
-/* Winbond have two vendor IDs! See 0x10ad as well */
-#define PCI_VENDOR_ID_WINBOND2		0x1050
-#define PCI_DEVICE_ID_WINBOND2_89C940	0x0940
-#define PCI_DEVICE_ID_WINBOND2_89C940F	0x5a5a
-
-#define PCI_VENDOR_ID_MOTOROLA		0x1057
-#define PCI_VENDOR_ID_MOTOROLA_OOPS	0x1507
-#define PCI_DEVICE_ID_MOTOROLA_MPC105	0x0001
-#define PCI_DEVICE_ID_MOTOROLA_MPC106	0x0002
-#define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
-#define PCI_DEVICE_ID_MOTOROLA_FALCON	0x4802
-#define PCI_DEVICE_ID_MOTOROLA_CPX8216	0x4806
-
-#define PCI_VENDOR_ID_PROMISE		0x105a
-#define PCI_DEVICE_ID_PROMISE_20246	0x4d33
-#define PCI_DEVICE_ID_PROMISE_20262	0x4d38
-#define PCI_DEVICE_ID_PROMISE_5300	0x5300
-
-#define PCI_VENDOR_ID_N9		0x105d
-#define PCI_DEVICE_ID_N9_I128		0x2309
-#define PCI_DEVICE_ID_N9_I128_2		0x2339
-#define PCI_DEVICE_ID_N9_I128_T2R	0x493d
-
-#define PCI_VENDOR_ID_UMC		0x1060
-#define PCI_DEVICE_ID_UMC_UM8673F	0x0101
-#define PCI_DEVICE_ID_UMC_UM8891A	0x0891
-#define PCI_DEVICE_ID_UMC_UM8886BF	0x673a
-#define PCI_DEVICE_ID_UMC_UM8886A	0x886a
-#define PCI_DEVICE_ID_UMC_UM8881F	0x8881
-#define PCI_DEVICE_ID_UMC_UM8886F	0x8886
-#define PCI_DEVICE_ID_UMC_UM9017F	0x9017
-#define PCI_DEVICE_ID_UMC_UM8886N	0xe886
-#define PCI_DEVICE_ID_UMC_UM8891N	0xe891
-
-#define PCI_VENDOR_ID_X			0x1061
-#define PCI_DEVICE_ID_X_AGX016		0x0001
-
-#define PCI_VENDOR_ID_MYLEX		0x1069
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V2	0x0001
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V3	0x0002
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V4	0x0010
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V5	0x0020
-
-#define PCI_VENDOR_ID_MYLEX		0x1069
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V2	0x0001
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V3	0x0002
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V4	0x0010
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V5	0x0020
-
-#define PCI_VENDOR_ID_MYLEX		0x1069
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V2	0x0001
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V3	0x0002
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V4	0x0010
-#define PCI_DEVICE_ID_MYLEX_DAC960P_V5	0x0020
-
-#define PCI_VENDOR_ID_PICOP		0x1066
-#define PCI_DEVICE_ID_PICOP_PT86C52X	0x0001
-#define PCI_DEVICE_ID_PICOP_PT80C524	0x8002
-
-#define PCI_VENDOR_ID_APPLE		0x106b
-#define PCI_DEVICE_ID_APPLE_BANDIT	0x0001
-#define PCI_DEVICE_ID_APPLE_GC		0x0002
-#define PCI_DEVICE_ID_APPLE_HYDRA	0x000e
-
-#define PCI_VENDOR_ID_NEXGEN		0x1074
-#define PCI_DEVICE_ID_NEXGEN_82C501	0x4e78
-
-#define PCI_VENDOR_ID_QLOGIC		0x1077
-#define PCI_DEVICE_ID_QLOGIC_ISP1020	0x1020
-#define PCI_DEVICE_ID_QLOGIC_ISP1022	0x1022
-#define PCI_DEVICE_ID_QLOGIC_ISP2100	0x2100
-#define PCI_DEVICE_ID_QLOGIC_ISP2200	0x2200
-
-#define PCI_VENDOR_ID_CYRIX		0x1078
-#define PCI_DEVICE_ID_CYRIX_5510	0x0000
-#define PCI_DEVICE_ID_CYRIX_PCI_MASTER	0x0001
-#define PCI_DEVICE_ID_CYRIX_5520	0x0002
-#define PCI_DEVICE_ID_CYRIX_5530_LEGACY	0x0100
-#define PCI_DEVICE_ID_CYRIX_5530_SMI	0x0101
-#define PCI_DEVICE_ID_CYRIX_5530_IDE	0x0102
-#define PCI_DEVICE_ID_CYRIX_5530_AUDIO	0x0103
-#define PCI_DEVICE_ID_CYRIX_5530_VIDEO	0x0104
-
-#define PCI_VENDOR_ID_LEADTEK		0x107d
-#define PCI_DEVICE_ID_LEADTEK_805	0x0000
-
-#define PCI_VENDOR_ID_CONTAQ		0x1080
-#define PCI_DEVICE_ID_CONTAQ_82C599	0x0600
-#define PCI_DEVICE_ID_CONTAQ_82C693	0xc693
-
-#define PCI_VENDOR_ID_FOREX		0x1083
-
-#define PCI_VENDOR_ID_OLICOM		0x108d
-#define PCI_DEVICE_ID_OLICOM_OC3136	0x0001
-#define PCI_DEVICE_ID_OLICOM_OC2315	0x0011
-#define PCI_DEVICE_ID_OLICOM_OC2325	0x0012
-#define PCI_DEVICE_ID_OLICOM_OC2183	0x0013
-#define PCI_DEVICE_ID_OLICOM_OC2326	0x0014
-#define PCI_DEVICE_ID_OLICOM_OC6151	0x0021
-
-#define PCI_VENDOR_ID_SUN		0x108e
-#define PCI_DEVICE_ID_SUN_EBUS		0x1000
-#define PCI_DEVICE_ID_SUN_HAPPYMEAL	0x1001
-#define PCI_DEVICE_ID_SUN_SIMBA		0x5000
-#define PCI_DEVICE_ID_SUN_PBM		0x8000
-#define PCI_DEVICE_ID_SUN_SABRE		0xa000
-
-#define PCI_VENDOR_ID_CMD		0x1095
-#define PCI_DEVICE_ID_CMD_640		0x0640
-#define PCI_DEVICE_ID_CMD_643		0x0643
-#define PCI_DEVICE_ID_CMD_646		0x0646
-#define PCI_DEVICE_ID_CMD_647		0x0647
-#define PCI_DEVICE_ID_CMD_670		0x0670
-
-#define PCI_VENDOR_ID_VISION		0x1098
-#define PCI_DEVICE_ID_VISION_QD8500	0x0001
-#define PCI_DEVICE_ID_VISION_QD8580	0x0002
-
-#define PCI_VENDOR_ID_BROOKTREE		0x109e
-#define PCI_DEVICE_ID_BROOKTREE_848	0x0350
-#define PCI_DEVICE_ID_BROOKTREE_849A	0x0351
-#define PCI_DEVICE_ID_BROOKTREE_878_1   0x036e
-#define PCI_DEVICE_ID_BROOKTREE_878     0x0878
-#define PCI_DEVICE_ID_BROOKTREE_8474	0x8474
-
-#define PCI_VENDOR_ID_SIERRA		0x10a8
-#define PCI_DEVICE_ID_SIERRA_STB	0x0000
-
-#define PCI_VENDOR_ID_SGI		0x10a9
-#define PCI_DEVICE_ID_SGI_IOC3		0x0003
-
-#define PCI_VENDOR_ID_ACC		0x10aa
-#define PCI_DEVICE_ID_ACC_2056		0x0000
-
-#define PCI_VENDOR_ID_WINBOND		0x10ad
-#define PCI_DEVICE_ID_WINBOND_83769	0x0001
-#define PCI_DEVICE_ID_WINBOND_82C105	0x0105
-#define PCI_DEVICE_ID_WINBOND_83C553	0x0565
-
-#define PCI_VENDOR_ID_DATABOOK		0x10b3
-#define PCI_DEVICE_ID_DATABOOK_87144	0xb106
-
-#define PCI_VENDOR_ID_PLX		0x10b5
-#define PCI_DEVICE_ID_PLX_SPCOM200	0x1103
-#define PCI_DEVICE_ID_PLX_9050		0x9050
-#define PCI_DEVICE_ID_PLX_9060		0x9060
-#define PCI_DEVICE_ID_PLX_9060ES	0x906E
-#define PCI_DEVICE_ID_PLX_9060SD	0x906D
-#define PCI_DEVICE_ID_PLX_9080		0x9080
-#define PCI_DEVICE_ID_PLX_GTEK_SERIAL2	0xa001
-
-#define PCI_VENDOR_ID_MADGE		0x10b6
-#define PCI_DEVICE_ID_MADGE_MK2		0x0002
-#define PCI_DEVICE_ID_MADGE_C155S	0x1001
-
-#define PCI_VENDOR_ID_3COM		0x10b7
-#define PCI_DEVICE_ID_3COM_3C985	0x0001
-#define PCI_DEVICE_ID_3COM_3C339	0x3390
-#define PCI_DEVICE_ID_3COM_3C590	0x5900
-#define PCI_DEVICE_ID_3COM_3C595TX	0x5950
-#define PCI_DEVICE_ID_3COM_3C595T4	0x5951
-#define PCI_DEVICE_ID_3COM_3C595MII	0x5952
-#define PCI_DEVICE_ID_3COM_3C900TPO	0x9000
-#define PCI_DEVICE_ID_3COM_3C900COMBO	0x9001
-#define PCI_DEVICE_ID_3COM_3C905TX	0x9050
-#define PCI_DEVICE_ID_3COM_3C905T4	0x9051
-#define PCI_DEVICE_ID_3COM_3C905B_TX	0x9055
-
-#define PCI_VENDOR_ID_SMC		0x10b8
-#define PCI_DEVICE_ID_SMC_EPIC100	0x0005
-
-#define PCI_VENDOR_ID_AL		0x10b9
-#define PCI_DEVICE_ID_AL_M1445		0x1445
-#define PCI_DEVICE_ID_AL_M1449		0x1449
-#define PCI_DEVICE_ID_AL_M1451		0x1451
-#define PCI_DEVICE_ID_AL_M1461		0x1461
-#define PCI_DEVICE_ID_AL_M1489		0x1489
-#define PCI_DEVICE_ID_AL_M1511		0x1511
-#define PCI_DEVICE_ID_AL_M1513		0x1513
-#define PCI_DEVICE_ID_AL_M1521		0x1521
-#define PCI_DEVICE_ID_AL_M1523		0x1523
-#define PCI_DEVICE_ID_AL_M1531		0x1531
-#define PCI_DEVICE_ID_AL_M1533		0x1533
-#define PCI_DEVICE_ID_AL_M1541		0x1541
-#define PCI_DEVICE_ID_AL_M1543		0x1543
-#define PCI_DEVICE_ID_AL_M3307		0x3307
-#define PCI_DEVICE_ID_AL_M4803		0x5215
-#define PCI_DEVICE_ID_AL_M5219		0x5219
-#define PCI_DEVICE_ID_AL_M5229		0x5229
-#define PCI_DEVICE_ID_AL_M5237		0x5237
-#define PCI_DEVICE_ID_AL_M5243		0x5243
-#define PCI_DEVICE_ID_AL_M7101		0x7101
-
-#define PCI_VENDOR_ID_MITSUBISHI	0x10ba
-
-#define PCI_VENDOR_ID_SURECOM		0x10bd
-#define PCI_DEVICE_ID_SURECOM_NE34	0x0e34
-
-#define PCI_VENDOR_ID_NEOMAGIC          0x10c8
-#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2070 0x0001
-#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128V 0x0002
-#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZV 0x0003
-#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2160 0x0004
-#define PCI_DEVICE_ID_NEOMAGIC_MAGICMEDIA_256AV       0x0005
-#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZVPLUS   0x0083
-
-#define PCI_VENDOR_ID_ASP		0x10cd
-#define PCI_DEVICE_ID_ASP_ABP940	0x1200
-#define PCI_DEVICE_ID_ASP_ABP940U	0x1300
-#define PCI_DEVICE_ID_ASP_ABP940UW	0x2300
-
-#define PCI_VENDOR_ID_MACRONIX		0x10d9
-#define PCI_DEVICE_ID_MACRONIX_MX98713	0x0512
-#define PCI_DEVICE_ID_MACRONIX_MX987x5	0x0531
-
-#define PCI_VENDOR_ID_CERN		0x10dc
-#define PCI_DEVICE_ID_CERN_SPSB_PMC	0x0001
-#define PCI_DEVICE_ID_CERN_SPSB_PCI	0x0002
-#define PCI_DEVICE_ID_CERN_HIPPI_DST	0x0021
-#define PCI_DEVICE_ID_CERN_HIPPI_SRC	0x0022
-
-#define PCI_VENDOR_ID_NVIDIA		0x10de
-#define PCI_DEVICE_ID_NVIDIA_TNT	0x0020
-#define PCI_DEVICE_ID_NVIDIA_TNT2	0x0028
-#define PCI_DEVICE_ID_NVIDIA_UTNT2	0x0029
-#define PCI_DEVICE_ID_NVIDIA_VTNT2	0x002C
-#define PCI_DEVICE_ID_NVIDIA_UVTNT2	0x002D
-#define PCI_DEVICE_ID_NVIDIA_ITNT2	0x00A0
-
-#define PCI_VENDOR_ID_IMS		0x10e0
-#define PCI_DEVICE_ID_IMS_8849		0x8849
-
-#define PCI_VENDOR_ID_TEKRAM2		0x10e1
-#define PCI_DEVICE_ID_TEKRAM2_690c	0x690c
-
-#define PCI_VENDOR_ID_TUNDRA		0x10e3
-#define PCI_DEVICE_ID_TUNDRA_CA91C042	0x0000
-
-#define PCI_VENDOR_ID_AMCC		0x10e8
-#define PCI_DEVICE_ID_AMCC_MYRINET	0x8043
-#define PCI_DEVICE_ID_AMCC_PARASTATION	0x8062
-#define PCI_DEVICE_ID_AMCC_S5933	0x807d
-#define PCI_DEVICE_ID_AMCC_S5933_HEPC3	0x809c
-
-#define PCI_VENDOR_ID_INTERG		0x10ea
-#define PCI_DEVICE_ID_INTERG_1680	0x1680
-#define PCI_DEVICE_ID_INTERG_1682	0x1682
-#define PCI_DEVICE_ID_INTERG_2000	0x2000
-
-#define PCI_VENDOR_ID_REALTEK		0x10ec
-#define PCI_DEVICE_ID_REALTEK_8029	0x8029
-#define PCI_DEVICE_ID_REALTEK_8129	0x8129
-#define PCI_DEVICE_ID_REALTEK_8139	0x8139
-
-#define PCI_VENDOR_ID_TRUEVISION	0x10fa
-#define PCI_DEVICE_ID_TRUEVISION_T1000	0x000c
-
-#define PCI_VENDOR_ID_INIT		0x1101
-#define PCI_DEVICE_ID_INIT_320P		0x9100
-#define PCI_DEVICE_ID_INIT_360P		0x9500
-
-#define PCI_VENDOR_ID_TTI		0x1103
-#define PCI_DEVICE_ID_TTI_HPT343	0x0003
-#define PCI_DEVICE_ID_TTI_HPT366	0x0004
-
-#define PCI_VENDOR_ID_VIA		0x1106
-#define PCI_DEVICE_ID_VIA_8501_0	0x0501
-#define PCI_DEVICE_ID_VIA_82C505	0x0505
-#define PCI_DEVICE_ID_VIA_82C561	0x0561
-#define PCI_DEVICE_ID_VIA_82C586_1	0x0571
-#define PCI_DEVICE_ID_VIA_82C576	0x0576
-#define PCI_DEVICE_ID_VIA_82C585	0x0585
-#define PCI_DEVICE_ID_VIA_82C586_0	0x0586
-#define PCI_DEVICE_ID_VIA_82C595	0x0595
-#define PCI_DEVICE_ID_VIA_82C596	0x0596
-#define PCI_DEVICE_ID_VIA_82C597_0	0x0597
-#define PCI_DEVICE_ID_VIA_82C598_0	0x0598
-#define PCI_DEVICE_ID_VIA_82C680	0x0680
-#define PCI_DEVICE_ID_VIA_82C686	0x0686
-#define PCI_DEVICE_ID_VIA_82C691	0x0691
-#define PCI_DEVICE_ID_VIA_82C693	0x0693
-#define PCI_DEVICE_ID_VIA_82C926	0x0926
-#define PCI_DEVICE_ID_VIA_82C416	0x1571
-#define PCI_DEVICE_ID_VIA_82C595_97	0x1595
-#define PCI_DEVICE_ID_VIA_82C586_2	0x3038
-#define PCI_DEVICE_ID_VIA_82C586_3	0x3040
-#define PCI_DEVICE_ID_VIA_82C686_4	0x3057
-#define PCI_DEVICE_ID_VIA_82C686_5	0x3058
-#define PCI_DEVICE_ID_VIA_82C686_6	0x3068
-#define PCI_DEVICE_ID_VIA_86C100A	0x6100
-#define PCI_DEVICE_ID_VIA_8501_1	0x8501
-#define PCI_DEVICE_ID_VIA_82C597_1	0x8597
-#define PCI_DEVICE_ID_VIA_82C598_1	0x8598
-
-#define PCI_VENDOR_ID_SMC2             0x1113
-#define PCI_DEVICE_ID_SMC2_1211TX      0x1211
-
-#define PCI_VENDOR_ID_VORTEX		0x1119
-#define PCI_DEVICE_ID_VORTEX_GDT60x0	0x0000
-#define PCI_DEVICE_ID_VORTEX_GDT6000B	0x0001
-#define PCI_DEVICE_ID_VORTEX_GDT6x10	0x0002
-#define PCI_DEVICE_ID_VORTEX_GDT6x20	0x0003
-#define PCI_DEVICE_ID_VORTEX_GDT6530	0x0004
-#define PCI_DEVICE_ID_VORTEX_GDT6550	0x0005
-#define PCI_DEVICE_ID_VORTEX_GDT6x17	0x0006
-#define PCI_DEVICE_ID_VORTEX_GDT6x27	0x0007
-#define PCI_DEVICE_ID_VORTEX_GDT6537	0x0008
-#define PCI_DEVICE_ID_VORTEX_GDT6557	0x0009
-#define PCI_DEVICE_ID_VORTEX_GDT6x15	0x000a
-#define PCI_DEVICE_ID_VORTEX_GDT6x25	0x000b
-#define PCI_DEVICE_ID_VORTEX_GDT6535	0x000c
-#define PCI_DEVICE_ID_VORTEX_GDT6555	0x000d
-#define PCI_DEVICE_ID_VORTEX_GDT6x17RP	0x0100
-#define PCI_DEVICE_ID_VORTEX_GDT6x27RP	0x0101
-#define PCI_DEVICE_ID_VORTEX_GDT6537RP	0x0102
-#define PCI_DEVICE_ID_VORTEX_GDT6557RP	0x0103
-#define PCI_DEVICE_ID_VORTEX_GDT6x11RP	0x0104
-#define PCI_DEVICE_ID_VORTEX_GDT6x21RP	0x0105
-#define PCI_DEVICE_ID_VORTEX_GDT6x17RP1	0x0110
-#define PCI_DEVICE_ID_VORTEX_GDT6x27RP1	0x0111
-#define PCI_DEVICE_ID_VORTEX_GDT6537RP1	0x0112
-#define PCI_DEVICE_ID_VORTEX_GDT6557RP1	0x0113
-#define PCI_DEVICE_ID_VORTEX_GDT6x11RP1	0x0114
-#define PCI_DEVICE_ID_VORTEX_GDT6x21RP1	0x0115
-#define PCI_DEVICE_ID_VORTEX_GDT6x17RP2	0x0120
-#define PCI_DEVICE_ID_VORTEX_GDT6x27RP2	0x0121
-#define PCI_DEVICE_ID_VORTEX_GDT6537RP2	0x0122
-#define PCI_DEVICE_ID_VORTEX_GDT6557RP2	0x0123
-#define PCI_DEVICE_ID_VORTEX_GDT6x11RP2	0x0124
-#define PCI_DEVICE_ID_VORTEX_GDT6x21RP2	0x0125
-
-#define PCI_VENDOR_ID_EF		0x111a
-#define PCI_DEVICE_ID_EF_ATM_FPGA	0x0000
-#define PCI_DEVICE_ID_EF_ATM_ASIC	0x0002
-
-#define PCI_VENDOR_ID_FORE		0x1127
-#define PCI_DEVICE_ID_FORE_PCA200PC	0x0210
-#define PCI_DEVICE_ID_FORE_PCA200E	0x0300
-
-#define PCI_VENDOR_ID_IMAGINGTECH	0x112f
-#define PCI_DEVICE_ID_IMAGINGTECH_ICPCI	0x0000
-
-#define PCI_VENDOR_ID_PHILIPS		0x1131
-#define PCI_DEVICE_ID_PHILIPS_SAA7145	0x7145
-#define PCI_DEVICE_ID_PHILIPS_SAA7146	0x7146
-
-#define PCI_VENDOR_ID_CYCLONE		0x113c
-#define PCI_DEVICE_ID_CYCLONE_SDK	0x0001
-
-#define PCI_VENDOR_ID_ALLIANCE		0x1142
-#define PCI_DEVICE_ID_ALLIANCE_PROMOTIO	0x3210
-#define PCI_DEVICE_ID_ALLIANCE_PROVIDEO	0x6422
-#define PCI_DEVICE_ID_ALLIANCE_AT24	0x6424
-#define PCI_DEVICE_ID_ALLIANCE_AT3D	0x643d
-
-#define PCI_VENDOR_ID_SK		0x1148
-#define PCI_DEVICE_ID_SK_FP		0x4000
-#define PCI_DEVICE_ID_SK_TR		0x4200
-#define PCI_DEVICE_ID_SK_GE		0x4300
-
-#define PCI_VENDOR_ID_VMIC		0x114a
-#define PCI_DEVICE_ID_VMIC_VME		0x7587
-
-#define PCI_VENDOR_ID_DIGI		0x114f
-#define PCI_DEVICE_ID_DIGI_EPC		0x0002
-#define PCI_DEVICE_ID_DIGI_RIGHTSWITCH	0x0003
-#define PCI_DEVICE_ID_DIGI_XEM		0x0004
-#define PCI_DEVICE_ID_DIGI_XR		0x0005
-#define PCI_DEVICE_ID_DIGI_CX		0x0006
-#define PCI_DEVICE_ID_DIGI_XRJ		0x0009
-#define PCI_DEVICE_ID_DIGI_EPCJ		0x000a
-#define PCI_DEVICE_ID_DIGI_XR_920	0x0027
-
-#define PCI_VENDOR_ID_MUTECH		0x1159
-#define PCI_DEVICE_ID_MUTECH_MV1000	0x0001
-
-#define PCI_VENDOR_ID_RENDITION		0x1163
-#define PCI_DEVICE_ID_RENDITION_VERITE	0x0001
-#define PCI_DEVICE_ID_RENDITION_VERITE2100 0x2000
-
-#define PCI_VENDOR_ID_TOSHIBA		0x1179
-#define PCI_DEVICE_ID_TOSHIBA_601	0x0601
-#define PCI_DEVICE_ID_TOSHIBA_TOPIC95	0x060a
-#define PCI_DEVICE_ID_TOSHIBA_TOPIC97	0x060f
-
-#define PCI_VENDOR_ID_RICOH		0x1180
-#define PCI_DEVICE_ID_RICOH_RL5C465	0x0465
-#define PCI_DEVICE_ID_RICOH_RL5C466	0x0466
-#define PCI_DEVICE_ID_RICOH_RL5C475	0x0475
-#define PCI_DEVICE_ID_RICOH_RL5C478	0x0478
-
-#define PCI_VENDOR_ID_ARTOP		0x1191
-#define PCI_DEVICE_ID_ARTOP_ATP8400	0x0004
-#define PCI_DEVICE_ID_ARTOP_ATP850UF	0x0005
-
-#define PCI_VENDOR_ID_ZEITNET		0x1193
-#define PCI_DEVICE_ID_ZEITNET_1221	0x0001
-#define PCI_DEVICE_ID_ZEITNET_1225	0x0002
-
-#define PCI_VENDOR_ID_OMEGA		0x119b
-#define PCI_DEVICE_ID_OMEGA_82C092G	0x1221
-
-#define PCI_SUBVENDOR_ID_KEYSPAN	0x11a9
-#define PCI_SUBDEVICE_ID_KEYSPAN_SX2	0x5334
-
-#define PCI_VENDOR_ID_GALILEO		0x11ab
-#define PCI_DEVICE_ID_GALILEO_GT64011	0x4146
-
-#define PCI_VENDOR_ID_LITEON		0x11ad
-#define PCI_DEVICE_ID_LITEON_LNE100TX	0x0002
-
-#define PCI_VENDOR_ID_V3		0x11b0
-#define PCI_DEVICE_ID_V3_V960		0x0001
-#define PCI_DEVICE_ID_V3_V350		0x0001
-#define PCI_DEVICE_ID_V3_V960V2		0x0002
-#define PCI_DEVICE_ID_V3_V350V2		0x0002
-
-#define PCI_VENDOR_ID_NP		0x11bc
-#define PCI_DEVICE_ID_NP_PCI_FDDI	0x0001
-
-#define PCI_VENDOR_ID_ATT		0x11c1
-#define PCI_DEVICE_ID_ATT_L56XMF	0x0440
-
-#define PCI_VENDOR_ID_SPECIALIX		0x11cb
-#define PCI_DEVICE_ID_SPECIALIX_IO8	0x2000
-#define PCI_DEVICE_ID_SPECIALIX_XIO	0x4000
-#define PCI_DEVICE_ID_SPECIALIX_RIO	0x8000
-
-#define PCI_VENDOR_ID_AURAVISION	0x11d1
-#define PCI_DEVICE_ID_AURAVISION_VXP524	0x01f7
-
-#define PCI_VENDOR_ID_IKON		0x11d5
-#define PCI_DEVICE_ID_IKON_10115	0x0115
-#define PCI_DEVICE_ID_IKON_10117	0x0117
-
-#define PCI_VENDOR_ID_ZORAN		0x11de
-#define PCI_DEVICE_ID_ZORAN_36057	0x6057
-#define PCI_DEVICE_ID_ZORAN_36120	0x6120
-
-#define PCI_VENDOR_ID_KINETIC		0x11f4
-#define PCI_DEVICE_ID_KINETIC_2915	0x2915
-
-#define PCI_VENDOR_ID_COMPEX		0x11f6
-#define PCI_DEVICE_ID_COMPEX_ENET100VG4	0x0112
-#define PCI_DEVICE_ID_COMPEX_RL2000	0x1401
-
-#define PCI_VENDOR_ID_RP               0x11fe
-#define PCI_DEVICE_ID_RP32INTF         0x0001
-#define PCI_DEVICE_ID_RP8INTF          0x0002
-#define PCI_DEVICE_ID_RP16INTF         0x0003
-#define PCI_DEVICE_ID_RP4QUAD	       0x0004
-#define PCI_DEVICE_ID_RP8OCTA          0x0005
-#define PCI_DEVICE_ID_RP8J	       0x0006
-#define PCI_DEVICE_ID_RPP4	       0x000A
-#define PCI_DEVICE_ID_RPP8	       0x000B
-#define PCI_DEVICE_ID_RP8M	       0x000C
-
-#define PCI_VENDOR_ID_CYCLADES		0x120e
-#define PCI_DEVICE_ID_CYCLOM_Y_Lo	0x0100
-#define PCI_DEVICE_ID_CYCLOM_Y_Hi	0x0101
-#define PCI_DEVICE_ID_CYCLOM_4Y_Lo	0x0102
-#define PCI_DEVICE_ID_CYCLOM_4Y_Hi	0x0103
-#define PCI_DEVICE_ID_CYCLOM_8Y_Lo	0x0104
-#define PCI_DEVICE_ID_CYCLOM_8Y_Hi	0x0105
-#define PCI_DEVICE_ID_CYCLOM_Z_Lo	0x0200
-#define PCI_DEVICE_ID_CYCLOM_Z_Hi	0x0201
-
-#define PCI_VENDOR_ID_ESSENTIAL		0x120f
-#define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER	0x0001
-
-#define PCI_VENDOR_ID_O2		0x1217
-#define PCI_DEVICE_ID_O2_6729		0x6729
-#define PCI_DEVICE_ID_O2_6730		0x673a
-#define PCI_DEVICE_ID_O2_6832		0x6832
-#define PCI_DEVICE_ID_O2_6836		0x6836
-
-#define PCI_VENDOR_ID_3DFX		0x121a
-#define PCI_DEVICE_ID_3DFX_VOODOO	0x0001
-#define PCI_DEVICE_ID_3DFX_VOODOO2	0x0002
-#define PCI_DEVICE_ID_3DFX_BANSHEE      0x0003
-#define PCI_DEVICE_ID_3DFX_VOODOO3	0x0005
-
-#define PCI_VENDOR_ID_SIGMADES		0x1236
-#define PCI_DEVICE_ID_SIGMADES_6425	0x6401
-
-#define PCI_VENDOR_ID_CCUBE		0x123f
-
-#define PCI_VENDOR_ID_AVM		0x1244
-#define PCI_DEVICE_ID_AVM_A1		0x0a00
-
-#define PCI_VENDOR_ID_DIPIX		0x1246
-
-#define PCI_VENDOR_ID_STALLION		0x124d
-#define PCI_DEVICE_ID_STALLION_ECHPCI832 0x0000
-#define PCI_DEVICE_ID_STALLION_ECHPCI864 0x0002
-#define PCI_DEVICE_ID_STALLION_EIOPCI	0x0003
-
-#define PCI_VENDOR_ID_OPTIBASE		0x1255
-#define PCI_DEVICE_ID_OPTIBASE_FORGE	0x1110
-#define PCI_DEVICE_ID_OPTIBASE_FUSION	0x1210
-#define PCI_DEVICE_ID_OPTIBASE_VPLEX	0x2110
-#define PCI_DEVICE_ID_OPTIBASE_VPLEXCC	0x2120
-#define PCI_DEVICE_ID_OPTIBASE_VQUEST	0x2130
-
-#define PCI_VENDOR_ID_ESS		0x125d
-#define PCI_DEVICE_ID_ESS_AUDIOPCI	0x1969
-
-#define PCI_VENDOR_ID_SATSAGEM		0x1267
-#define PCI_DEVICE_ID_SATSAGEM_PCR2101	0x5352
-#define PCI_DEVICE_ID_SATSAGEM_TELSATTURBO 0x5a4b
-
-#define PCI_VENDOR_ID_HUGHES		0x1273
-#define PCI_DEVICE_ID_HUGHES_DIRECPC	0x0002
-
-#define PCI_VENDOR_ID_ENSONIQ		0x1274
-#define PCI_DEVICE_ID_ENSONIQ_AUDIOPCI	0x5000
-#define PCI_DEVICE_ID_ENSONIQ_ES1371    0x1371
-
-#define PCI_VENDOR_ID_ALTEON		0x12ae
-#define PCI_DEVICE_ID_ALTEON_ACENIC	0x0001
-
-#define PCI_SUBVENDOR_ID_CONNECT_TECH			0x12c4
-#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232		0x0001
-#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232		0x0002
-#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232		0x0003
-#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485		0x0004
-#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4	0x0005
-#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485		0x0006
-#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2	0x0007
-#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485		0x0008
-
-#define PCI_VENDOR_ID_PICTUREL		0x12c5
-#define PCI_DEVICE_ID_PICTUREL_PCIVST	0x0081
-
-#define PCI_VENDOR_ID_NVIDIA_SGS	0x12d2
-#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018
-
-#define PCI_VENDOR_ID_CBOARDS		0x1307
-#define PCI_DEVICE_ID_CBOARDS_DAS1602_16 0x0001
-
-#define PCI_VENDOR_ID_SIIG		0x131f
-#define PCI_DEVICE_ID_SIIG_1S1P_10x_550	0x1010
-#define PCI_DEVICE_ID_SIIG_1S1P_10x_650	0x1011
-#define PCI_DEVICE_ID_SIIG_1S1P_10x_850	0x1012
-#define PCI_DEVICE_ID_SIIG_1P_10x	0x1020
-#define PCI_DEVICE_ID_SIIG_2P_10x	0x1021
-#define PCI_DEVICE_ID_SIIG_2S1P_10x_550	0x1034
-#define PCI_DEVICE_ID_SIIG_2S1P_10x_650	0x1035
-#define PCI_DEVICE_ID_SIIG_2S1P_10x_850	0x1036
-#define PCI_DEVICE_ID_SIIG_1P_20x	0x2020
-#define PCI_DEVICE_ID_SIIG_2P_20x	0x2021
-#define PCI_DEVICE_ID_SIIG_2P1S_20x_550	0x2040
-#define PCI_DEVICE_ID_SIIG_2P1S_20x_650	0x2041
-#define PCI_DEVICE_ID_SIIG_2P1S_20x_850	0x2042
-#define PCI_DEVICE_ID_SIIG_1S1P_20x_550	0x2010
-#define PCI_DEVICE_ID_SIIG_1S1P_20x_650	0x2011
-#define PCI_DEVICE_ID_SIIG_1S1P_20x_850	0x2012
-#define PCI_DEVICE_ID_SIIG_2S1P_20x_550	0x2060
-#define PCI_DEVICE_ID_SIIG_2S1P_20x_650	0x2061
-#define PCI_DEVICE_ID_SIIG_2S1P_20x_850	0x2062
-
-#define PCI_VENDOR_ID_SEALEVEL		0x135e
-#define PCI_DEVICE_ID_SEALEVEL_U530	0x7101
-#define PCI_DEVICE_ID_SEALEVEL_UCOMM2	0x7201
-#define PCI_DEVICE_ID_SEALEVEL_UCOMM422	0x7402
-#define PCI_DEVICE_ID_SEALEVEL_UCOMM232	0x7202
-#define PCI_DEVICE_ID_SEALEVEL_COMM4	0x7401
-#define PCI_DEVICE_ID_SEALEVEL_COMM8	0x7801
-
-#define PCI_VENDOR_ID_NETGEAR		0x1385
-#define PCI_DEVICE_ID_NETGEAR_GA620	0x620a
-
-#define PCI_VENDOR_ID_LAVA		0x1407
-#define PCI_DEVICE_ID_LAVA_PARALLEL	0x8000
-#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A	0x8002 /* The Lava Dual Parallel is */
-#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B	0x8003 /* two PCI devices on a card */
-
-#define PCI_VENDOR_ID_PANACOM		0x14d4
-#define PCI_DEVICE_ID_PANACOM_QUADMODEM	0x0400
-#define PCI_DEVICE_ID_PANACOM_DUALMODEM	0x0402
-
-#define PCI_VENDOR_ID_SYMPHONY		0x1c1c
-#define PCI_DEVICE_ID_SYMPHONY_101	0x0001
-
-#define PCI_VENDOR_ID_TEKRAM		0x1de1
-#define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29
-
-#define PCI_VENDOR_ID_3DLABS		0x3d3d
-#define PCI_DEVICE_ID_3DLABS_300SX	0x0001
-#define PCI_DEVICE_ID_3DLABS_500TX	0x0002
-#define PCI_DEVICE_ID_3DLABS_DELTA	0x0003
-#define PCI_DEVICE_ID_3DLABS_PERMEDIA	0x0004
-#define PCI_DEVICE_ID_3DLABS_MX		0x0006
-
-#define PCI_VENDOR_ID_AVANCE		0x4005
-#define PCI_DEVICE_ID_AVANCE_ALG2064	0x2064
-#define PCI_DEVICE_ID_AVANCE_2302	0x2302
-
-#define PCI_VENDOR_ID_NETVIN		0x4a14
-#define PCI_DEVICE_ID_NETVIN_NV5000SC	0x5000
-
-#define PCI_VENDOR_ID_S3		0x5333
-#define PCI_DEVICE_ID_S3_PLATO_PXS	0x0551
-#define PCI_DEVICE_ID_S3_ViRGE		0x5631
-#define PCI_DEVICE_ID_S3_TRIO		0x8811
-#define PCI_DEVICE_ID_S3_AURORA64VP	0x8812
-#define PCI_DEVICE_ID_S3_TRIO64UVP	0x8814
-#define PCI_DEVICE_ID_S3_ViRGE_VX	0x883d
-#define PCI_DEVICE_ID_S3_868		0x8880
-#define PCI_DEVICE_ID_S3_928		0x88b0
-#define PCI_DEVICE_ID_S3_864_1		0x88c0
-#define PCI_DEVICE_ID_S3_864_2		0x88c1
-#define PCI_DEVICE_ID_S3_964_1		0x88d0
-#define PCI_DEVICE_ID_S3_964_2		0x88d1
-#define PCI_DEVICE_ID_S3_968		0x88f0
-#define PCI_DEVICE_ID_S3_TRIO64V2	0x8901
-#define PCI_DEVICE_ID_S3_PLATO_PXG	0x8902
-#define PCI_DEVICE_ID_S3_ViRGE_DXGX	0x8a01
-#define PCI_DEVICE_ID_S3_ViRGE_GX2	0x8a10
-#define PCI_DEVICE_ID_S3_ViRGE_MX	0x8c01
-#define PCI_DEVICE_ID_S3_ViRGE_MXP	0x8c02
-#define PCI_DEVICE_ID_S3_ViRGE_MXPMV	0x8c03
-#define PCI_DEVICE_ID_S3_SONICVIBES	0xca00
-
-#define PCI_VENDOR_ID_DCI       0x6666
-#define PCI_DEVICE_ID_DCI_PCCOM4    0x0001
-
-#define PCI_VENDOR_ID_GENROCO		0x5555
-#define PCI_DEVICE_ID_GENROCO_HFP832	0x0003
-
-#define PCI_VENDOR_ID_INTEL		0x8086
-#define PCI_DEVICE_ID_INTEL_21145	0x0039
-#define PCI_DEVICE_ID_INTEL_82375	0x0482
-#define PCI_DEVICE_ID_INTEL_82424	0x0483
-#define PCI_DEVICE_ID_INTEL_82378	0x0484
-#define PCI_DEVICE_ID_INTEL_82430	0x0486
-#define PCI_DEVICE_ID_INTEL_82434	0x04a3
-#define PCI_DEVICE_ID_INTEL_I960	0x0960
-#define PCI_DEVICE_ID_INTEL_82559ER	0x1209
-#define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
-#define PCI_DEVICE_ID_INTEL_82092AA_1	0x1222
-#define PCI_DEVICE_ID_INTEL_7116	0x1223
-#define PCI_DEVICE_ID_INTEL_82596	0x1226
-#define PCI_DEVICE_ID_INTEL_82865	0x1227
-#define PCI_DEVICE_ID_INTEL_82557	0x1229
-#define PCI_DEVICE_ID_INTEL_82437	0x122d
-#define PCI_DEVICE_ID_INTEL_82371FB_0	0x122e
-#define PCI_DEVICE_ID_INTEL_82371FB_1	0x1230
-#define PCI_DEVICE_ID_INTEL_82371MX	0x1234
-#define PCI_DEVICE_ID_INTEL_82437MX	0x1235
-#define PCI_DEVICE_ID_INTEL_82441	0x1237
-#define PCI_DEVICE_ID_INTEL_82380FB	0x124b
-#define PCI_DEVICE_ID_INTEL_82439	0x1250
-#define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
-#define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
-#define PCI_DEVICE_ID_INTEL_82371SB_2	0x7020
-#define PCI_DEVICE_ID_INTEL_82437VX	0x7030
-#define PCI_DEVICE_ID_INTEL_82439TX	0x7100
-#define PCI_DEVICE_ID_INTEL_82371AB_0	0x7110
-#define PCI_DEVICE_ID_INTEL_82371AB	0x7111
-#define PCI_DEVICE_ID_INTEL_82371AB_2	0x7112
-#define PCI_DEVICE_ID_INTEL_82371AB_3	0x7113
-#define PCI_VENDOR_ID_COMPUTONE		0x8e0e
-#define PCI_DEVICE_ID_COMPUTONE_IP2EX	0x0291
-
-#define PCI_DEVICE_ID_INTEL_82443LX_0	0x7180
-#define PCI_DEVICE_ID_INTEL_82443LX_1	0x7181
-#define PCI_DEVICE_ID_INTEL_82443BX_0	0x7190
-#define PCI_DEVICE_ID_INTEL_82443BX_1	0x7191
-#define PCI_DEVICE_ID_INTEL_82443BX_2	0x7192
-#define PCI_DEVICE_ID_INTEL_P6		0x84c4
-#define PCI_DEVICE_ID_INTEL_82450GX	0x84c5
-#define PCI_DEVICE_ID_INTEL_82451NX	0x84ca
-
-#define PCI_VENDOR_ID_KTI		0x8e2e
-#define PCI_DEVICE_ID_KTI_ET32P2	0x3000
-
-#define PCI_VENDOR_ID_ADAPTEC		0x9004
-#define PCI_DEVICE_ID_ADAPTEC_7810	0x1078
-#define PCI_DEVICE_ID_ADAPTEC_7821	0x2178
-#define PCI_DEVICE_ID_ADAPTEC_38602	0x3860
-#define PCI_DEVICE_ID_ADAPTEC_7850	0x5078
-#define PCI_DEVICE_ID_ADAPTEC_7855	0x5578
-#define PCI_DEVICE_ID_ADAPTEC_5800	0x5800
-#define PCI_DEVICE_ID_ADAPTEC_3860	0x6038
-#define PCI_DEVICE_ID_ADAPTEC_1480A	0x6075
-#define PCI_DEVICE_ID_ADAPTEC_7860	0x6078
-#define PCI_DEVICE_ID_ADAPTEC_7861	0x6178
-#define PCI_DEVICE_ID_ADAPTEC_7870	0x7078
-#define PCI_DEVICE_ID_ADAPTEC_7871	0x7178
-#define PCI_DEVICE_ID_ADAPTEC_7872	0x7278
-#define PCI_DEVICE_ID_ADAPTEC_7873	0x7378
-#define PCI_DEVICE_ID_ADAPTEC_7874	0x7478
-#define PCI_DEVICE_ID_ADAPTEC_7895	0x7895
-#define PCI_DEVICE_ID_ADAPTEC_7880	0x8078
-#define PCI_DEVICE_ID_ADAPTEC_7881	0x8178
-#define PCI_DEVICE_ID_ADAPTEC_7882	0x8278
-#define PCI_DEVICE_ID_ADAPTEC_7883	0x8378
-#define PCI_DEVICE_ID_ADAPTEC_7884	0x8478
-#define PCI_DEVICE_ID_ADAPTEC_7885	0x8578
-#define PCI_DEVICE_ID_ADAPTEC_7886	0x8678
-#define PCI_DEVICE_ID_ADAPTEC_7887	0x8778
-#define PCI_DEVICE_ID_ADAPTEC_7888	0x8878
-#define PCI_DEVICE_ID_ADAPTEC_1030	0x8b78
-
-#define PCI_VENDOR_ID_ADAPTEC2		0x9005
-#define PCI_DEVICE_ID_ADAPTEC2_2940U2	0x0010
-#define PCI_DEVICE_ID_ADAPTEC2_2930U2	0x0011
-#define PCI_DEVICE_ID_ADAPTEC2_7890B	0x0013
-#define PCI_DEVICE_ID_ADAPTEC2_7890	0x001f
-#define PCI_DEVICE_ID_ADAPTEC2_3940U2	0x0050
-#define PCI_DEVICE_ID_ADAPTEC2_3950U2D	0x0051
-#define PCI_DEVICE_ID_ADAPTEC2_7896	0x005f
-#define PCI_DEVICE_ID_ADAPTEC2_7892A	0x0080
-#define PCI_DEVICE_ID_ADAPTEC2_7892B	0x0081
-#define PCI_DEVICE_ID_ADAPTEC2_7892D	0x0083
-#define PCI_DEVICE_ID_ADAPTEC2_7892P	0x008f
-#define PCI_DEVICE_ID_ADAPTEC2_7899A	0x00c0
-#define PCI_DEVICE_ID_ADAPTEC2_7899B	0x00c1
-#define PCI_DEVICE_ID_ADAPTEC2_7899D	0x00c3
-#define PCI_DEVICE_ID_ADAPTEC2_7899P	0x00cf
-
-#define PCI_VENDOR_ID_ATRONICS		0x907f
-#define PCI_DEVICE_ID_ATRONICS_2015	0x2015
-
-#define PCI_VENDOR_ID_HOLTEK		0x9412
-#define PCI_DEVICE_ID_HOLTEK_6565	0x6565
-
-#define PCI_VENDOR_ID_TIGERJET		0xe159
-#define PCI_DEVICE_ID_TIGERJET_300	0x0001
-
-#define PCI_VENDOR_ID_ARK		0xedd8
-#define PCI_DEVICE_ID_ARK_STING		0xa091
-#define PCI_DEVICE_ID_ARK_STINGARK	0xa099
-#define PCI_DEVICE_ID_ARK_2000MT	0xa0a1
-
-#define PCI_VENDOR_ID_INTERPHASE		0x107e
-#define PCI_DEVICE_ID_INTERPHASE_5526	0x0004
-#define PCI_DEVICE_ID_INTERPHASE_55x6	0x0005
-
-#define PCI_VENDOR_ID_INTERPHASE		0x107e
-#define PCI_DEVICE_ID_INTERPHASE_5526	0x0004
-#define PCI_DEVICE_ID_INTERPHASE_55x6	0x0005
-
-#define PCI_VENDOR_ID_INTERPHASE		0x107e
-#define PCI_DEVICE_ID_INTERPHASE_5526	0x0004
-#define PCI_DEVICE_ID_INTERPHASE_55x6	0x0005
+#include <linux/pci_ids.h>
 
 /*
  * The PCI interface treats multi-function devices as independent
@@ -1372,6 +284,8 @@
 #include <linux/config.h>
 #include <linux/ioport.h>
 
+#include <asm/pci.h>
+
 #define DEVICE_COUNT_COMPATIBLE	4
 #define DEVICE_COUNT_IRQ	2
 #define DEVICE_COUNT_DMA	2
@@ -1397,7 +311,8 @@
 	unsigned short	subsystem_vendor;
 	unsigned short	subsystem_device;
 	unsigned int	class;		/* 3 bytes: (base,sub,prog-if) */
-	unsigned int	hdr_type;	/* PCI header type */
+	u8		hdr_type;	/* PCI header type (`multi' flag masked out) */
+	u8		rom_base_reg;	/* Which config register controls the ROM */
 
 	unsigned short	regs;
 
@@ -1415,6 +330,7 @@
 	struct resource irq_resource[DEVICE_COUNT_IRQ];
 
 	char		name[48];	/* Device name */
+	char		slot_name[8];	/* Slot name */
 
 	int (*prepare)(struct pci_dev *dev);
 	int (*activate)(struct pci_dev *dev);
@@ -1491,11 +407,11 @@
 void pcibios_init(void);
 void pcibios_fixup_bus(struct pci_bus *);
 char *pcibios_setup (char *str);
+
 void pcibios_update_resource(struct pci_dev *, struct resource *,
 			     struct resource *, int);
 void pcibios_update_irq(struct pci_dev *, int irq);
 
-
 /* Backward compatibility, don't use in new code! */
 
 int pcibios_present(void);
@@ -1525,6 +441,7 @@
 int pci_proc_attach_device(struct pci_dev *dev);
 int pci_proc_detach_device(struct pci_dev *dev);
 void pci_name_device(struct pci_dev *dev);
+void pci_read_bridge_bases(struct pci_bus *child);
 struct resource *pci_find_parent_resource(struct pci_dev *dev, struct resource *res);
 
 struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
@@ -1535,13 +452,6 @@
 struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
 int pci_find_capability (struct pci_dev *dev, int cap);
 
-int pci_assign_resource(struct pci_dev *dev, int i);
-int pci_claim_resource(struct pci_dev *, int);
-void pci_assign_unassigned_resources(u32 min_io, u32 min_mem);
-void pci_set_bus_ranges(void);
-void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
-		    int (*)(struct pci_dev *, u8, u8));
-
 #define PCI_ANY_ID (~0)
 
 int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val);
@@ -1552,9 +462,42 @@
 int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
 void pci_set_master(struct pci_dev *dev);
 
+/* Helper functions (drivers/pci/setup.c) */
+
+int pci_claim_resource(struct pci_dev *, int);
+void pci_assign_unassigned_resources(u32 min_io, u32 min_mem);
+void pci_set_bus_ranges(void);
+void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
+		    int (*)(struct pci_dev *, u8, u8));
+
+/*
+ * simple PCI probing for drivers
+ */
+ 
+struct pci_simple_probe_entry;
+typedef int (*pci_simple_probe_callback) (struct pci_dev *dev, int match_num,
+				   	  const struct pci_simple_probe_entry *ent,
+					  void *drvr_data);
+
+struct pci_simple_probe_entry {
+	unsigned short vendor;	/* vendor id, PCI_ANY_ID, or 0 for last entry */
+	unsigned short device;	/* device id, PCI_ANY_ID, or 0 for last entry */
+	unsigned short subsys_vendor; /* subsystem vendor id, 0 for don't care */
+	unsigned short subsys_device; /* subsystem device id, 0 for don't care */
+	void *dev_data;		/* driver-private, entry-specific data */
+};
+
+int pci_simple_probe (struct pci_simple_probe_entry *list, size_t match_limit,
+		      pci_simple_probe_callback cb, void *drvr_data);
+
+
+
+/*
+ *  If the system does not have PCI, clearly these return errors.  Define
+ *  these as simple inline functions to avoid hair in drivers.
+ */
+
 #ifndef CONFIG_PCI
-/* If the system does not have PCI, clearly these return errors.  Define
-   these as simple inline functions to avoid hair in drivers.  */
 extern inline int pcibios_present(void) { return 0; }
 
 #define _PCI_NOP(o,s,t) \
@@ -1577,9 +520,16 @@
 extern inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
 { return NULL; }
 
+extern inline struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int device,
+unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from)
+{ return NULL; }
+
 extern inline void pci_set_master(struct pci_dev *dev) 
 { return; }
 
+extern inline int pci_simple_probe (struct pci_simple_probe_entry *list, size_t match_limit,
+		      pci_simple_probe_callback cb, void *drvr_data)
+{ return 0; }
 
 #endif /* !CONFIG_PCI */
 
diff -u --recursive --new-file v2.3.19/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.3.19/linux/include/linux/pci_ids.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/pci_ids.h	Fri Oct  8 10:06:21 1999
@@ -0,0 +1,1098 @@
+/*
+ *	PCI Class, Vendor and Device IDs
+ *
+ *	Please keep sorted.
+ */
+
+/* Device classes and subclasses */
+
+#define PCI_CLASS_NOT_DEFINED		0x0000
+#define PCI_CLASS_NOT_DEFINED_VGA	0x0001
+
+#define PCI_BASE_CLASS_STORAGE		0x01
+#define PCI_CLASS_STORAGE_SCSI		0x0100
+#define PCI_CLASS_STORAGE_IDE		0x0101
+#define PCI_CLASS_STORAGE_FLOPPY	0x0102
+#define PCI_CLASS_STORAGE_IPI		0x0103
+#define PCI_CLASS_STORAGE_RAID		0x0104
+#define PCI_CLASS_STORAGE_OTHER		0x0180
+
+#define PCI_BASE_CLASS_NETWORK		0x02
+#define PCI_CLASS_NETWORK_ETHERNET	0x0200
+#define PCI_CLASS_NETWORK_TOKEN_RING	0x0201
+#define PCI_CLASS_NETWORK_FDDI		0x0202
+#define PCI_CLASS_NETWORK_ATM		0x0203
+#define PCI_CLASS_NETWORK_OTHER		0x0280
+
+#define PCI_BASE_CLASS_DISPLAY		0x03
+#define PCI_CLASS_DISPLAY_VGA		0x0300
+#define PCI_CLASS_DISPLAY_XGA		0x0301
+#define PCI_CLASS_DISPLAY_OTHER		0x0380
+
+#define PCI_BASE_CLASS_MULTIMEDIA	0x04
+#define PCI_CLASS_MULTIMEDIA_VIDEO	0x0400
+#define PCI_CLASS_MULTIMEDIA_AUDIO	0x0401
+#define PCI_CLASS_MULTIMEDIA_OTHER	0x0480
+
+#define PCI_BASE_CLASS_MEMORY		0x05
+#define  PCI_CLASS_MEMORY_RAM		0x0500
+#define  PCI_CLASS_MEMORY_FLASH		0x0501
+#define  PCI_CLASS_MEMORY_OTHER		0x0580
+
+#define PCI_BASE_CLASS_BRIDGE		0x06
+#define  PCI_CLASS_BRIDGE_HOST		0x0600
+#define  PCI_CLASS_BRIDGE_ISA		0x0601
+#define  PCI_CLASS_BRIDGE_EISA		0x0602
+#define  PCI_CLASS_BRIDGE_MC		0x0603
+#define  PCI_CLASS_BRIDGE_PCI		0x0604
+#define  PCI_CLASS_BRIDGE_PCMCIA	0x0605
+#define  PCI_CLASS_BRIDGE_NUBUS		0x0606
+#define  PCI_CLASS_BRIDGE_CARDBUS	0x0607
+#define  PCI_CLASS_BRIDGE_OTHER		0x0680
+
+#define PCI_BASE_CLASS_COMMUNICATION	0x07
+#define PCI_CLASS_COMMUNICATION_SERIAL	0x0700
+#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
+#define PCI_CLASS_COMMUNICATION_OTHER	0x0780
+
+#define PCI_BASE_CLASS_SYSTEM		0x08
+#define PCI_CLASS_SYSTEM_PIC		0x0800
+#define PCI_CLASS_SYSTEM_DMA		0x0801
+#define PCI_CLASS_SYSTEM_TIMER		0x0802
+#define PCI_CLASS_SYSTEM_RTC		0x0803
+#define PCI_CLASS_SYSTEM_OTHER		0x0880
+
+#define PCI_BASE_CLASS_INPUT		0x09
+#define PCI_CLASS_INPUT_KEYBOARD	0x0900
+#define PCI_CLASS_INPUT_PEN		0x0901
+#define PCI_CLASS_INPUT_MOUSE		0x0902
+#define PCI_CLASS_INPUT_OTHER		0x0980
+
+#define PCI_BASE_CLASS_DOCKING		0x0a
+#define PCI_CLASS_DOCKING_GENERIC	0x0a00
+#define PCI_CLASS_DOCKING_OTHER		0x0a01
+
+#define PCI_BASE_CLASS_PROCESSOR	0x0b
+#define PCI_CLASS_PROCESSOR_386		0x0b00
+#define PCI_CLASS_PROCESSOR_486		0x0b01
+#define PCI_CLASS_PROCESSOR_PENTIUM	0x0b02
+#define PCI_CLASS_PROCESSOR_ALPHA	0x0b10
+#define PCI_CLASS_PROCESSOR_POWERPC	0x0b20
+#define PCI_CLASS_PROCESSOR_CO		0x0b40
+
+#define PCI_BASE_CLASS_SERIAL		0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE	0x0c00
+#define PCI_CLASS_SERIAL_ACCESS		0x0c01
+#define PCI_CLASS_SERIAL_SSA		0x0c02
+#define PCI_CLASS_SERIAL_USB		0x0c03
+#define PCI_CLASS_SERIAL_FIBER		0x0c04
+
+#define PCI_BASE_CLASS_INTELLIGENT	0x0e
+#define PCI_CLASS_INTELLIGENT_I2O	0x0e00
+
+#define PCI_CLASS_HOT_SWAP_CONTROLLER	0xff00
+
+#define PCI_CLASS_OTHERS		0xff
+
+/* Vendors and devices.  Sort key: vendor first, device next. */
+
+#define PCI_VENDOR_ID_COMPAQ		0x0e11
+#define PCI_DEVICE_ID_COMPAQ_TOKENRING	0x0508
+#define PCI_DEVICE_ID_COMPAQ_1280	0x3033
+#define PCI_DEVICE_ID_COMPAQ_TRIFLEX	0x4000
+#define PCI_DEVICE_ID_COMPAQ_SMART2P	0xae10
+#define PCI_DEVICE_ID_COMPAQ_NETEL100	0xae32
+#define PCI_DEVICE_ID_COMPAQ_NETEL10	0xae34
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3I	0xae35
+#define PCI_DEVICE_ID_COMPAQ_NETEL100D	0xae40
+#define PCI_DEVICE_ID_COMPAQ_NETEL100PI	0xae43
+#define PCI_DEVICE_ID_COMPAQ_NETEL100I	0xb011
+#define PCI_DEVICE_ID_COMPAQ_THUNDER	0xf130
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3B	0xf150
+
+#define PCI_VENDOR_ID_NCR		0x1000
+#define PCI_DEVICE_ID_NCR_53C810	0x0001
+#define PCI_DEVICE_ID_NCR_53C820	0x0002
+#define PCI_DEVICE_ID_NCR_53C825	0x0003
+#define PCI_DEVICE_ID_NCR_53C815	0x0004
+#define PCI_DEVICE_ID_NCR_53C860	0x0006
+#define PCI_DEVICE_ID_NCR_53C896	0x000b
+#define PCI_DEVICE_ID_NCR_53C895	0x000c
+#define PCI_DEVICE_ID_NCR_53C885	0x000d
+#define PCI_DEVICE_ID_NCR_53C875	0x000f
+#define PCI_DEVICE_ID_NCR_53C1510	0x0010
+#define PCI_DEVICE_ID_NCR_53C875J	0x008f
+
+#define PCI_VENDOR_ID_ATI		0x1002
+#define PCI_DEVICE_ID_ATI_68800		0x4158
+#define PCI_DEVICE_ID_ATI_215CT222	0x4354
+#define PCI_DEVICE_ID_ATI_210888CX	0x4358
+#define PCI_DEVICE_ID_ATI_215GB		0x4742
+#define PCI_DEVICE_ID_ATI_215GD		0x4744
+#define PCI_DEVICE_ID_ATI_215GI		0x4749
+#define PCI_DEVICE_ID_ATI_215GP		0x4750
+#define PCI_DEVICE_ID_ATI_215GQ		0x4751
+#define PCI_DEVICE_ID_ATI_215GT		0x4754
+#define PCI_DEVICE_ID_ATI_215GTB	0x4755
+#define PCI_DEVICE_ID_ATI_210888GX	0x4758
+#define PCI_DEVICE_ID_ATI_215LG		0x4c47
+#define PCI_DEVICE_ID_ATI_264LT		0x4c54
+#define PCI_DEVICE_ID_ATI_264VT		0x5654
+
+#define PCI_VENDOR_ID_VLSI		0x1004
+#define PCI_DEVICE_ID_VLSI_82C592	0x0005
+#define PCI_DEVICE_ID_VLSI_82C593	0x0006
+#define PCI_DEVICE_ID_VLSI_82C594	0x0007
+#define PCI_DEVICE_ID_VLSI_82C597	0x0009
+#define PCI_DEVICE_ID_VLSI_82C541	0x000c
+#define PCI_DEVICE_ID_VLSI_82C543	0x000d
+#define PCI_DEVICE_ID_VLSI_82C532	0x0101
+#define PCI_DEVICE_ID_VLSI_82C534	0x0102
+#define PCI_DEVICE_ID_VLSI_82C535	0x0104
+#define PCI_DEVICE_ID_VLSI_82C147	0x0105
+#define PCI_DEVICE_ID_VLSI_VAS96011	0x0702
+
+#define PCI_VENDOR_ID_ADL		0x1005
+#define PCI_DEVICE_ID_ADL_2301		0x2301
+
+#define PCI_VENDOR_ID_NS		0x100b
+#define PCI_DEVICE_ID_NS_87415		0x0002
+#define PCI_DEVICE_ID_NS_87410		0xd001
+
+#define PCI_VENDOR_ID_TSENG		0x100c
+#define PCI_DEVICE_ID_TSENG_W32P_2	0x3202
+#define PCI_DEVICE_ID_TSENG_W32P_b	0x3205
+#define PCI_DEVICE_ID_TSENG_W32P_c	0x3206
+#define PCI_DEVICE_ID_TSENG_W32P_d	0x3207
+#define PCI_DEVICE_ID_TSENG_ET6000	0x3208
+
+#define PCI_VENDOR_ID_WEITEK		0x100e
+#define PCI_DEVICE_ID_WEITEK_P9000	0x9001
+#define PCI_DEVICE_ID_WEITEK_P9100	0x9100
+
+#define PCI_VENDOR_ID_DEC		0x1011
+#define PCI_DEVICE_ID_DEC_BRD		0x0001
+#define PCI_DEVICE_ID_DEC_TULIP		0x0002
+#define PCI_DEVICE_ID_DEC_TGA		0x0004
+#define PCI_DEVICE_ID_DEC_TULIP_FAST	0x0009
+#define PCI_DEVICE_ID_DEC_TGA2		0x000D
+#define PCI_DEVICE_ID_DEC_FDDI		0x000F
+#define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014
+#define PCI_DEVICE_ID_DEC_21142		0x0019
+#define PCI_DEVICE_ID_DEC_21052		0x0021
+#define PCI_DEVICE_ID_DEC_21150		0x0022
+#define PCI_DEVICE_ID_DEC_21152		0x0024
+#define PCI_DEVICE_ID_DEC_21153		0x0025
+#define PCI_DEVICE_ID_DEC_21154		0x0026
+#define PCI_DEVICE_ID_DEC_21285		0x1065
+#define PCI_DEVICE_ID_COMPAQ_42XX	0x0046
+
+#define PCI_VENDOR_ID_CIRRUS		0x1013
+#define PCI_DEVICE_ID_CIRRUS_7548	0x0038
+#define PCI_DEVICE_ID_CIRRUS_5430	0x00a0
+#define PCI_DEVICE_ID_CIRRUS_5434_4	0x00a4
+#define PCI_DEVICE_ID_CIRRUS_5434_8	0x00a8
+#define PCI_DEVICE_ID_CIRRUS_5436	0x00ac
+#define PCI_DEVICE_ID_CIRRUS_5446	0x00b8
+#define PCI_DEVICE_ID_CIRRUS_5480	0x00bc
+#define PCI_DEVICE_ID_CIRRUS_5462	0x00d0
+#define PCI_DEVICE_ID_CIRRUS_5464	0x00d4
+#define PCI_DEVICE_ID_CIRRUS_5465	0x00d6
+#define PCI_DEVICE_ID_CIRRUS_6729	0x1100
+#define PCI_DEVICE_ID_CIRRUS_6832	0x1110
+#define PCI_DEVICE_ID_CIRRUS_7542	0x1200
+#define PCI_DEVICE_ID_CIRRUS_7543	0x1202
+#define PCI_DEVICE_ID_CIRRUS_7541	0x1204
+
+#define PCI_VENDOR_ID_IBM		0x1014
+#define PCI_DEVICE_ID_IBM_FIRE_CORAL	0x000a
+#define PCI_DEVICE_ID_IBM_TR		0x0018
+#define PCI_DEVICE_ID_IBM_82G2675	0x001d
+#define PCI_DEVICE_ID_IBM_MCA		0x0020
+#define PCI_DEVICE_ID_IBM_82351		0x0022
+#define PCI_DEVICE_ID_IBM_PYTHON	0x002d
+#define PCI_DEVICE_ID_IBM_SERVERAID	0x002e
+#define PCI_DEVICE_ID_IBM_TR_WAKE	0x003e
+#define PCI_DEVICE_ID_IBM_MPIC		0x0046
+#define PCI_DEVICE_ID_IBM_3780IDSP	0x007d
+#define PCI_DEVICE_ID_IBM_MPIC_2	0xffff
+
+#define PCI_VENDOR_ID_WD		0x101c
+#define PCI_DEVICE_ID_WD_7197		0x3296
+
+#define PCI_VENDOR_ID_AMD		0x1022
+#define PCI_DEVICE_ID_AMD_LANCE		0x2000
+#define PCI_DEVICE_ID_AMD_LANCE_HOME	0x2001
+#define PCI_DEVICE_ID_AMD_SCSI		0x2020
+
+#define PCI_VENDOR_ID_TRIDENT		0x1023
+#define PCI_DEVICE_ID_TRIDENT_9320	0x9320
+#define PCI_DEVICE_ID_TRIDENT_9388	0x9388
+#define PCI_DEVICE_ID_TRIDENT_9397	0x9397
+#define PCI_DEVICE_ID_TRIDENT_939A	0x939A
+#define PCI_DEVICE_ID_TRIDENT_9520	0x9520
+#define PCI_DEVICE_ID_TRIDENT_9525	0x9525
+#define PCI_DEVICE_ID_TRIDENT_9420	0x9420
+#define PCI_DEVICE_ID_TRIDENT_9440	0x9440
+#define PCI_DEVICE_ID_TRIDENT_9660	0x9660
+#define PCI_DEVICE_ID_TRIDENT_9750	0x9750
+#define PCI_DEVICE_ID_TRIDENT_9850	0x9850
+#define PCI_DEVICE_ID_TRIDENT_9880	0x9880
+#define PCI_DEVICE_ID_TRIDENT_8400	0x8400
+#define PCI_DEVICE_ID_TRIDENT_8420	0x8420
+#define PCI_DEVICE_ID_TRIDENT_8500	0x8500
+
+#define PCI_VENDOR_ID_AI		0x1025
+#define PCI_DEVICE_ID_AI_M1435		0x1435
+
+#define PCI_VENDOR_ID_MATROX		0x102B
+#define PCI_DEVICE_ID_MATROX_MGA_2	0x0518
+#define PCI_DEVICE_ID_MATROX_MIL	0x0519
+#define PCI_DEVICE_ID_MATROX_MYS	0x051A
+#define PCI_DEVICE_ID_MATROX_MIL_2	0x051b
+#define PCI_DEVICE_ID_MATROX_MIL_2_AGP	0x051f
+#define PCI_DEVICE_ID_MATROX_MGA_IMP	0x0d10
+#define PCI_DEVICE_ID_MATROX_G100_MM    0x1000
+#define PCI_DEVICE_ID_MATROX_G100_AGP   0x1001
+#define PCI_DEVICE_ID_MATROX_G200_PCI   0x0520
+#define PCI_DEVICE_ID_MATROX_G200_AGP   0x0521
+#define	PCI_DEVICE_ID_MATROX_G400	0x0525
+#define PCI_DEVICE_ID_MATROX_VIA	0x4536
+
+#define PCI_VENDOR_ID_CT		0x102c
+#define PCI_DEVICE_ID_CT_65545		0x00d8
+#define PCI_DEVICE_ID_CT_65548		0x00dc
+#define PCI_DEVICE_ID_CT_65550		0x00e0
+#define PCI_DEVICE_ID_CT_65554		0x00e4
+#define PCI_DEVICE_ID_CT_65555		0x00e5
+
+#define PCI_VENDOR_ID_MIRO		0x1031
+#define PCI_DEVICE_ID_MIRO_36050	0x5601
+
+#define PCI_VENDOR_ID_NEC		0x1033
+#define PCI_DEVICE_ID_NEC_PCX2		0x0046
+
+#define PCI_VENDOR_ID_FD		0x1036
+#define PCI_DEVICE_ID_FD_36C70		0x0000
+
+#define PCI_VENDOR_ID_SI		0x1039
+#define PCI_DEVICE_ID_SI_5591_AGP	0x0001
+#define PCI_DEVICE_ID_SI_6202		0x0002
+#define PCI_DEVICE_ID_SI_503		0x0008
+#define PCI_DEVICE_ID_SI_ACPI		0x0009
+#define PCI_DEVICE_ID_SI_5597_VGA	0x0200
+#define PCI_DEVICE_ID_SI_6205		0x0205
+#define PCI_DEVICE_ID_SI_501		0x0406
+#define PCI_DEVICE_ID_SI_496		0x0496
+#define PCI_DEVICE_ID_SI_530		0x0530
+#define PCI_DEVICE_ID_SI_601		0x0601
+#define PCI_DEVICE_ID_SI_620		0x0620
+#define PCI_DEVICE_ID_SI_5107		0x5107
+#define PCI_DEVICE_ID_SI_5511		0x5511
+#define PCI_DEVICE_ID_SI_5513		0x5513
+#define PCI_DEVICE_ID_SI_5571		0x5571
+#define PCI_DEVICE_ID_SI_5591		0x5591
+#define PCI_DEVICE_ID_SI_5597		0x5597
+#define PCI_DEVICE_ID_SI_5600		0x5600
+#define PCI_DEVICE_ID_SI_6306		0x6306
+#define PCI_DEVICE_ID_SI_6326		0x6326
+#define PCI_DEVICE_ID_SI_7001		0x7001
+
+#define PCI_VENDOR_ID_HP		0x103c
+#define PCI_DEVICE_ID_HP_J2585A		0x1030
+#define PCI_DEVICE_ID_HP_J2585B		0x1031
+
+#define PCI_VENDOR_ID_PCTECH		0x1042
+#define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
+#define PCI_DEVICE_ID_PCTECH_RZ1001	0x1001
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_0	0x3000
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_1	0x3010
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020
+
+#define PCI_VENDOR_ID_DPT               0x1044   
+#define PCI_DEVICE_ID_DPT               0xa400  
+
+#define PCI_VENDOR_ID_OPTI		0x1045
+#define PCI_DEVICE_ID_OPTI_92C178	0xc178
+#define PCI_DEVICE_ID_OPTI_82C557	0xc557
+#define PCI_DEVICE_ID_OPTI_82C558	0xc558
+#define PCI_DEVICE_ID_OPTI_82C621	0xc621
+#define PCI_DEVICE_ID_OPTI_82C700	0xc700
+#define PCI_DEVICE_ID_OPTI_82C701	0xc701
+#define PCI_DEVICE_ID_OPTI_82C814	0xc814
+#define PCI_DEVICE_ID_OPTI_82C822	0xc822
+#define PCI_DEVICE_ID_OPTI_82C861	0xc861
+#define PCI_DEVICE_ID_OPTI_82C825	0xd568
+
+#define PCI_VENDOR_ID_SGS		0x104a
+#define PCI_DEVICE_ID_SGS_2000		0x0008
+#define PCI_DEVICE_ID_SGS_1764		0x0009
+
+#define PCI_VENDOR_ID_BUSLOGIC		      0x104B
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER    0x1040
+#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT     0x8130
+
+#define PCI_VENDOR_ID_TI		0x104c
+#define PCI_DEVICE_ID_TI_TVP4010	0x3d04
+#define PCI_DEVICE_ID_TI_TVP4020	0x3d07
+#define PCI_DEVICE_ID_TI_PCI1130	0xac12
+#define PCI_DEVICE_ID_TI_PCI1031	0xac13
+#define PCI_DEVICE_ID_TI_PCI1131	0xac15
+#define PCI_DEVICE_ID_TI_PCI1250	0xac16
+#define PCI_DEVICE_ID_TI_PCI1220	0xac17
+
+#define PCI_VENDOR_ID_OAK		0x104e
+#define PCI_DEVICE_ID_OAK_OTI107	0x0107
+
+/* Winbond have two vendor IDs! See 0x10ad as well */
+#define PCI_VENDOR_ID_WINBOND2		0x1050
+#define PCI_DEVICE_ID_WINBOND2_89C940	0x0940
+#define PCI_DEVICE_ID_WINBOND2_89C940F	0x5a5a
+
+#define PCI_VENDOR_ID_MOTOROLA		0x1057
+#define PCI_VENDOR_ID_MOTOROLA_OOPS	0x1507
+#define PCI_DEVICE_ID_MOTOROLA_MPC105	0x0001
+#define PCI_DEVICE_ID_MOTOROLA_MPC106	0x0002
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
+#define PCI_DEVICE_ID_MOTOROLA_FALCON	0x4802
+#define PCI_DEVICE_ID_MOTOROLA_CPX8216	0x4806
+
+#define PCI_VENDOR_ID_PROMISE		0x105a
+#define PCI_DEVICE_ID_PROMISE_20246	0x4d33
+#define PCI_DEVICE_ID_PROMISE_20262	0x4d38
+#define PCI_DEVICE_ID_PROMISE_5300	0x5300
+
+#define PCI_VENDOR_ID_N9		0x105d
+#define PCI_DEVICE_ID_N9_I128		0x2309
+#define PCI_DEVICE_ID_N9_I128_2		0x2339
+#define PCI_DEVICE_ID_N9_I128_T2R	0x493d
+
+#define PCI_VENDOR_ID_UMC		0x1060
+#define PCI_DEVICE_ID_UMC_UM8673F	0x0101
+#define PCI_DEVICE_ID_UMC_UM8891A	0x0891
+#define PCI_DEVICE_ID_UMC_UM8886BF	0x673a
+#define PCI_DEVICE_ID_UMC_UM8886A	0x886a
+#define PCI_DEVICE_ID_UMC_UM8881F	0x8881
+#define PCI_DEVICE_ID_UMC_UM8886F	0x8886
+#define PCI_DEVICE_ID_UMC_UM9017F	0x9017
+#define PCI_DEVICE_ID_UMC_UM8886N	0xe886
+#define PCI_DEVICE_ID_UMC_UM8891N	0xe891
+
+#define PCI_VENDOR_ID_X			0x1061
+#define PCI_DEVICE_ID_X_AGX016		0x0001
+
+#define PCI_VENDOR_ID_MYLEX		0x1069
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V2	0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V3	0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V4	0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V5	0x0020
+
+#define PCI_VENDOR_ID_MYLEX		0x1069
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V2	0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V3	0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V4	0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V5	0x0020
+
+#define PCI_VENDOR_ID_MYLEX		0x1069
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V2	0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V3	0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V4	0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V5	0x0020
+
+#define PCI_VENDOR_ID_PICOP		0x1066
+#define PCI_DEVICE_ID_PICOP_PT86C52X	0x0001
+#define PCI_DEVICE_ID_PICOP_PT80C524	0x8002
+
+#define PCI_VENDOR_ID_APPLE		0x106b
+#define PCI_DEVICE_ID_APPLE_BANDIT	0x0001
+#define PCI_DEVICE_ID_APPLE_GC		0x0002
+#define PCI_DEVICE_ID_APPLE_HYDRA	0x000e
+
+#define PCI_VENDOR_ID_NEXGEN		0x1074
+#define PCI_DEVICE_ID_NEXGEN_82C501	0x4e78
+
+#define PCI_VENDOR_ID_QLOGIC		0x1077
+#define PCI_DEVICE_ID_QLOGIC_ISP1020	0x1020
+#define PCI_DEVICE_ID_QLOGIC_ISP1022	0x1022
+#define PCI_DEVICE_ID_QLOGIC_ISP2100	0x2100
+#define PCI_DEVICE_ID_QLOGIC_ISP2200	0x2200
+
+#define PCI_VENDOR_ID_CYRIX		0x1078
+#define PCI_DEVICE_ID_CYRIX_5510	0x0000
+#define PCI_DEVICE_ID_CYRIX_PCI_MASTER	0x0001
+#define PCI_DEVICE_ID_CYRIX_5520	0x0002
+#define PCI_DEVICE_ID_CYRIX_5530_LEGACY	0x0100
+#define PCI_DEVICE_ID_CYRIX_5530_SMI	0x0101
+#define PCI_DEVICE_ID_CYRIX_5530_IDE	0x0102
+#define PCI_DEVICE_ID_CYRIX_5530_AUDIO	0x0103
+#define PCI_DEVICE_ID_CYRIX_5530_VIDEO	0x0104
+
+#define PCI_VENDOR_ID_LEADTEK		0x107d
+#define PCI_DEVICE_ID_LEADTEK_805	0x0000
+
+#define PCI_VENDOR_ID_CONTAQ		0x1080
+#define PCI_DEVICE_ID_CONTAQ_82C599	0x0600
+#define PCI_DEVICE_ID_CONTAQ_82C693	0xc693
+
+#define PCI_VENDOR_ID_FOREX		0x1083
+
+#define PCI_VENDOR_ID_OLICOM		0x108d
+#define PCI_DEVICE_ID_OLICOM_OC3136	0x0001
+#define PCI_DEVICE_ID_OLICOM_OC2315	0x0011
+#define PCI_DEVICE_ID_OLICOM_OC2325	0x0012
+#define PCI_DEVICE_ID_OLICOM_OC2183	0x0013
+#define PCI_DEVICE_ID_OLICOM_OC2326	0x0014
+#define PCI_DEVICE_ID_OLICOM_OC6151	0x0021
+
+#define PCI_VENDOR_ID_SUN		0x108e
+#define PCI_DEVICE_ID_SUN_EBUS		0x1000
+#define PCI_DEVICE_ID_SUN_HAPPYMEAL	0x1001
+#define PCI_DEVICE_ID_SUN_SIMBA		0x5000
+#define PCI_DEVICE_ID_SUN_PBM		0x8000
+#define PCI_DEVICE_ID_SUN_SABRE		0xa000
+
+#define PCI_VENDOR_ID_CMD		0x1095
+#define PCI_DEVICE_ID_CMD_640		0x0640
+#define PCI_DEVICE_ID_CMD_643		0x0643
+#define PCI_DEVICE_ID_CMD_646		0x0646
+#define PCI_DEVICE_ID_CMD_647		0x0647
+#define PCI_DEVICE_ID_CMD_670		0x0670
+
+#define PCI_VENDOR_ID_VISION		0x1098
+#define PCI_DEVICE_ID_VISION_QD8500	0x0001
+#define PCI_DEVICE_ID_VISION_QD8580	0x0002
+
+#define PCI_VENDOR_ID_BROOKTREE		0x109e
+#define PCI_DEVICE_ID_BROOKTREE_848	0x0350
+#define PCI_DEVICE_ID_BROOKTREE_849A	0x0351
+#define PCI_DEVICE_ID_BROOKTREE_878_1   0x036e
+#define PCI_DEVICE_ID_BROOKTREE_878     0x0878
+#define PCI_DEVICE_ID_BROOKTREE_8474	0x8474
+
+#define PCI_VENDOR_ID_SIERRA		0x10a8
+#define PCI_DEVICE_ID_SIERRA_STB	0x0000
+
+#define PCI_VENDOR_ID_SGI		0x10a9
+#define PCI_DEVICE_ID_SGI_IOC3		0x0003
+
+#define PCI_VENDOR_ID_ACC		0x10aa
+#define PCI_DEVICE_ID_ACC_2056		0x0000
+
+#define PCI_VENDOR_ID_WINBOND		0x10ad
+#define PCI_DEVICE_ID_WINBOND_83769	0x0001
+#define PCI_DEVICE_ID_WINBOND_82C105	0x0105
+#define PCI_DEVICE_ID_WINBOND_83C553	0x0565
+
+#define PCI_VENDOR_ID_DATABOOK		0x10b3
+#define PCI_DEVICE_ID_DATABOOK_87144	0xb106
+
+#define PCI_VENDOR_ID_PLX		0x10b5
+#define PCI_DEVICE_ID_PLX_SPCOM200	0x1103
+#define PCI_DEVICE_ID_PLX_9050		0x9050
+#define PCI_DEVICE_ID_PLX_9060		0x9060
+#define PCI_DEVICE_ID_PLX_9060ES	0x906E
+#define PCI_DEVICE_ID_PLX_9060SD	0x906D
+#define PCI_DEVICE_ID_PLX_9080		0x9080
+#define PCI_DEVICE_ID_PLX_GTEK_SERIAL2	0xa001
+
+#define PCI_VENDOR_ID_MADGE		0x10b6
+#define PCI_DEVICE_ID_MADGE_MK2		0x0002
+#define PCI_DEVICE_ID_MADGE_C155S	0x1001
+
+#define PCI_VENDOR_ID_3COM		0x10b7
+#define PCI_DEVICE_ID_3COM_3C985	0x0001
+#define PCI_DEVICE_ID_3COM_3C339	0x3390
+#define PCI_DEVICE_ID_3COM_3C590	0x5900
+#define PCI_DEVICE_ID_3COM_3C595TX	0x5950
+#define PCI_DEVICE_ID_3COM_3C595T4	0x5951
+#define PCI_DEVICE_ID_3COM_3C595MII	0x5952
+#define PCI_DEVICE_ID_3COM_3C900TPO	0x9000
+#define PCI_DEVICE_ID_3COM_3C900COMBO	0x9001
+#define PCI_DEVICE_ID_3COM_3C905TX	0x9050
+#define PCI_DEVICE_ID_3COM_3C905T4	0x9051
+#define PCI_DEVICE_ID_3COM_3C905B_TX	0x9055
+
+#define PCI_VENDOR_ID_SMC		0x10b8
+#define PCI_DEVICE_ID_SMC_EPIC100	0x0005
+
+#define PCI_VENDOR_ID_AL		0x10b9
+#define PCI_DEVICE_ID_AL_M1445		0x1445
+#define PCI_DEVICE_ID_AL_M1449		0x1449
+#define PCI_DEVICE_ID_AL_M1451		0x1451
+#define PCI_DEVICE_ID_AL_M1461		0x1461
+#define PCI_DEVICE_ID_AL_M1489		0x1489
+#define PCI_DEVICE_ID_AL_M1511		0x1511
+#define PCI_DEVICE_ID_AL_M1513		0x1513
+#define PCI_DEVICE_ID_AL_M1521		0x1521
+#define PCI_DEVICE_ID_AL_M1523		0x1523
+#define PCI_DEVICE_ID_AL_M1531		0x1531
+#define PCI_DEVICE_ID_AL_M1533		0x1533
+#define PCI_DEVICE_ID_AL_M1541		0x1541
+#define PCI_DEVICE_ID_AL_M1543		0x1543
+#define PCI_DEVICE_ID_AL_M3307		0x3307
+#define PCI_DEVICE_ID_AL_M4803		0x5215
+#define PCI_DEVICE_ID_AL_M5219		0x5219
+#define PCI_DEVICE_ID_AL_M5229		0x5229
+#define PCI_DEVICE_ID_AL_M5237		0x5237
+#define PCI_DEVICE_ID_AL_M5243		0x5243
+#define PCI_DEVICE_ID_AL_M7101		0x7101
+
+#define PCI_VENDOR_ID_MITSUBISHI	0x10ba
+
+#define PCI_VENDOR_ID_SURECOM		0x10bd
+#define PCI_DEVICE_ID_SURECOM_NE34	0x0e34
+
+#define PCI_VENDOR_ID_NEOMAGIC          0x10c8
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2070 0x0001
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128V 0x0002
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZV 0x0003
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2160 0x0004
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICMEDIA_256AV       0x0005
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZVPLUS   0x0083
+
+#define PCI_VENDOR_ID_ASP		0x10cd
+#define PCI_DEVICE_ID_ASP_ABP940	0x1200
+#define PCI_DEVICE_ID_ASP_ABP940U	0x1300
+#define PCI_DEVICE_ID_ASP_ABP940UW	0x2300
+
+#define PCI_VENDOR_ID_MACRONIX		0x10d9
+#define PCI_DEVICE_ID_MACRONIX_MX98713	0x0512
+#define PCI_DEVICE_ID_MACRONIX_MX987x5	0x0531
+
+#define PCI_VENDOR_ID_CERN		0x10dc
+#define PCI_DEVICE_ID_CERN_SPSB_PMC	0x0001
+#define PCI_DEVICE_ID_CERN_SPSB_PCI	0x0002
+#define PCI_DEVICE_ID_CERN_HIPPI_DST	0x0021
+#define PCI_DEVICE_ID_CERN_HIPPI_SRC	0x0022
+
+#define PCI_VENDOR_ID_NVIDIA		0x10de
+#define PCI_DEVICE_ID_NVIDIA_TNT	0x0020
+#define PCI_DEVICE_ID_NVIDIA_TNT2	0x0028
+#define PCI_DEVICE_ID_NVIDIA_UTNT2	0x0029
+#define PCI_DEVICE_ID_NVIDIA_VTNT2	0x002C
+#define PCI_DEVICE_ID_NVIDIA_UVTNT2	0x002D
+#define PCI_DEVICE_ID_NVIDIA_ITNT2	0x00A0
+
+#define PCI_VENDOR_ID_IMS		0x10e0
+#define PCI_DEVICE_ID_IMS_8849		0x8849
+
+#define PCI_VENDOR_ID_TEKRAM2		0x10e1
+#define PCI_DEVICE_ID_TEKRAM2_690c	0x690c
+
+#define PCI_VENDOR_ID_TUNDRA		0x10e3
+#define PCI_DEVICE_ID_TUNDRA_CA91C042	0x0000
+
+#define PCI_VENDOR_ID_AMCC		0x10e8
+#define PCI_DEVICE_ID_AMCC_MYRINET	0x8043
+#define PCI_DEVICE_ID_AMCC_PARASTATION	0x8062
+#define PCI_DEVICE_ID_AMCC_S5933	0x807d
+#define PCI_DEVICE_ID_AMCC_S5933_HEPC3	0x809c
+
+#define PCI_VENDOR_ID_INTERG		0x10ea
+#define PCI_DEVICE_ID_INTERG_1680	0x1680
+#define PCI_DEVICE_ID_INTERG_1682	0x1682
+#define PCI_DEVICE_ID_INTERG_2000	0x2000
+
+#define PCI_VENDOR_ID_REALTEK		0x10ec
+#define PCI_DEVICE_ID_REALTEK_8029	0x8029
+#define PCI_DEVICE_ID_REALTEK_8129	0x8129
+#define PCI_DEVICE_ID_REALTEK_8139	0x8139
+
+#define PCI_VENDOR_ID_TRUEVISION	0x10fa
+#define PCI_DEVICE_ID_TRUEVISION_T1000	0x000c
+
+#define PCI_VENDOR_ID_INIT		0x1101
+#define PCI_DEVICE_ID_INIT_320P		0x9100
+#define PCI_DEVICE_ID_INIT_360P		0x9500
+
+#define PCI_VENDOR_ID_TTI		0x1103
+#define PCI_DEVICE_ID_TTI_HPT343	0x0003
+#define PCI_DEVICE_ID_TTI_HPT366	0x0004
+
+#define PCI_VENDOR_ID_VIA		0x1106
+#define PCI_DEVICE_ID_VIA_8501_0	0x0501
+#define PCI_DEVICE_ID_VIA_82C505	0x0505
+#define PCI_DEVICE_ID_VIA_82C561	0x0561
+#define PCI_DEVICE_ID_VIA_82C586_1	0x0571
+#define PCI_DEVICE_ID_VIA_82C576	0x0576
+#define PCI_DEVICE_ID_VIA_82C585	0x0585
+#define PCI_DEVICE_ID_VIA_82C586_0	0x0586
+#define PCI_DEVICE_ID_VIA_82C595	0x0595
+#define PCI_DEVICE_ID_VIA_82C596	0x0596
+#define PCI_DEVICE_ID_VIA_82C597_0	0x0597
+#define PCI_DEVICE_ID_VIA_82C598_0	0x0598
+#define PCI_DEVICE_ID_VIA_82C680	0x0680
+#define PCI_DEVICE_ID_VIA_82C686	0x0686
+#define PCI_DEVICE_ID_VIA_82C691	0x0691
+#define PCI_DEVICE_ID_VIA_82C693	0x0693
+#define PCI_DEVICE_ID_VIA_82C926	0x0926
+#define PCI_DEVICE_ID_VIA_82C416	0x1571
+#define PCI_DEVICE_ID_VIA_82C595_97	0x1595
+#define PCI_DEVICE_ID_VIA_82C586_2	0x3038
+#define PCI_DEVICE_ID_VIA_82C586_3	0x3040
+#define PCI_DEVICE_ID_VIA_82C686_4	0x3057
+#define PCI_DEVICE_ID_VIA_82C686_5	0x3058
+#define PCI_DEVICE_ID_VIA_82C686_6	0x3068
+#define PCI_DEVICE_ID_VIA_86C100A	0x6100
+#define PCI_DEVICE_ID_VIA_8501_1	0x8501
+#define PCI_DEVICE_ID_VIA_82C597_1	0x8597
+#define PCI_DEVICE_ID_VIA_82C598_1	0x8598
+
+#define PCI_VENDOR_ID_SMC2             0x1113
+#define PCI_DEVICE_ID_SMC2_1211TX      0x1211
+
+#define PCI_VENDOR_ID_VORTEX		0x1119
+#define PCI_DEVICE_ID_VORTEX_GDT60x0	0x0000
+#define PCI_DEVICE_ID_VORTEX_GDT6000B	0x0001
+#define PCI_DEVICE_ID_VORTEX_GDT6x10	0x0002
+#define PCI_DEVICE_ID_VORTEX_GDT6x20	0x0003
+#define PCI_DEVICE_ID_VORTEX_GDT6530	0x0004
+#define PCI_DEVICE_ID_VORTEX_GDT6550	0x0005
+#define PCI_DEVICE_ID_VORTEX_GDT6x17	0x0006
+#define PCI_DEVICE_ID_VORTEX_GDT6x27	0x0007
+#define PCI_DEVICE_ID_VORTEX_GDT6537	0x0008
+#define PCI_DEVICE_ID_VORTEX_GDT6557	0x0009
+#define PCI_DEVICE_ID_VORTEX_GDT6x15	0x000a
+#define PCI_DEVICE_ID_VORTEX_GDT6x25	0x000b
+#define PCI_DEVICE_ID_VORTEX_GDT6535	0x000c
+#define PCI_DEVICE_ID_VORTEX_GDT6555	0x000d
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP	0x0100
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP	0x0101
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP	0x0102
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP	0x0103
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP	0x0104
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP	0x0105
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP1	0x0110
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP1	0x0111
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP1	0x0112
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP1	0x0113
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP1	0x0114
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP1	0x0115
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP2	0x0120
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP2	0x0121
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP2	0x0122
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP2	0x0123
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP2	0x0124
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP2	0x0125
+
+#define PCI_VENDOR_ID_EF		0x111a
+#define PCI_DEVICE_ID_EF_ATM_FPGA	0x0000
+#define PCI_DEVICE_ID_EF_ATM_ASIC	0x0002
+
+#define PCI_VENDOR_ID_FORE		0x1127
+#define PCI_DEVICE_ID_FORE_PCA200PC	0x0210
+#define PCI_DEVICE_ID_FORE_PCA200E	0x0300
+
+#define PCI_VENDOR_ID_IMAGINGTECH	0x112f
+#define PCI_DEVICE_ID_IMAGINGTECH_ICPCI	0x0000
+
+#define PCI_VENDOR_ID_PHILIPS		0x1131
+#define PCI_DEVICE_ID_PHILIPS_SAA7145	0x7145
+#define PCI_DEVICE_ID_PHILIPS_SAA7146	0x7146
+
+#define PCI_VENDOR_ID_CYCLONE		0x113c
+#define PCI_DEVICE_ID_CYCLONE_SDK	0x0001
+
+#define PCI_VENDOR_ID_ALLIANCE		0x1142
+#define PCI_DEVICE_ID_ALLIANCE_PROMOTIO	0x3210
+#define PCI_DEVICE_ID_ALLIANCE_PROVIDEO	0x6422
+#define PCI_DEVICE_ID_ALLIANCE_AT24	0x6424
+#define PCI_DEVICE_ID_ALLIANCE_AT3D	0x643d
+
+#define PCI_VENDOR_ID_SK		0x1148
+#define PCI_DEVICE_ID_SK_FP		0x4000
+#define PCI_DEVICE_ID_SK_TR		0x4200
+#define PCI_DEVICE_ID_SK_GE		0x4300
+
+#define PCI_VENDOR_ID_VMIC		0x114a
+#define PCI_DEVICE_ID_VMIC_VME		0x7587
+
+#define PCI_VENDOR_ID_DIGI		0x114f
+#define PCI_DEVICE_ID_DIGI_EPC		0x0002
+#define PCI_DEVICE_ID_DIGI_RIGHTSWITCH	0x0003
+#define PCI_DEVICE_ID_DIGI_XEM		0x0004
+#define PCI_DEVICE_ID_DIGI_XR		0x0005
+#define PCI_DEVICE_ID_DIGI_CX		0x0006
+#define PCI_DEVICE_ID_DIGI_XRJ		0x0009
+#define PCI_DEVICE_ID_DIGI_EPCJ		0x000a
+#define PCI_DEVICE_ID_DIGI_XR_920	0x0027
+
+#define PCI_VENDOR_ID_MUTECH		0x1159
+#define PCI_DEVICE_ID_MUTECH_MV1000	0x0001
+
+#define PCI_VENDOR_ID_RENDITION		0x1163
+#define PCI_DEVICE_ID_RENDITION_VERITE	0x0001
+#define PCI_DEVICE_ID_RENDITION_VERITE2100 0x2000
+
+#define PCI_VENDOR_ID_TOSHIBA		0x1179
+#define PCI_DEVICE_ID_TOSHIBA_601	0x0601
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95	0x060a
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC97	0x060f
+
+#define PCI_VENDOR_ID_RICOH		0x1180
+#define PCI_DEVICE_ID_RICOH_RL5C465	0x0465
+#define PCI_DEVICE_ID_RICOH_RL5C466	0x0466
+#define PCI_DEVICE_ID_RICOH_RL5C475	0x0475
+#define PCI_DEVICE_ID_RICOH_RL5C478	0x0478
+
+#define PCI_VENDOR_ID_ARTOP		0x1191
+#define PCI_DEVICE_ID_ARTOP_ATP8400	0x0004
+#define PCI_DEVICE_ID_ARTOP_ATP850UF	0x0005
+
+#define PCI_VENDOR_ID_ZEITNET		0x1193
+#define PCI_DEVICE_ID_ZEITNET_1221	0x0001
+#define PCI_DEVICE_ID_ZEITNET_1225	0x0002
+
+#define PCI_VENDOR_ID_OMEGA		0x119b
+#define PCI_DEVICE_ID_OMEGA_82C092G	0x1221
+
+#define PCI_SUBVENDOR_ID_KEYSPAN	0x11a9
+#define PCI_SUBDEVICE_ID_KEYSPAN_SX2	0x5334
+
+#define PCI_VENDOR_ID_GALILEO		0x11ab
+#define PCI_DEVICE_ID_GALILEO_GT64011	0x4146
+
+#define PCI_VENDOR_ID_LITEON		0x11ad
+#define PCI_DEVICE_ID_LITEON_LNE100TX	0x0002
+
+#define PCI_VENDOR_ID_V3		0x11b0
+#define PCI_DEVICE_ID_V3_V960		0x0001
+#define PCI_DEVICE_ID_V3_V350		0x0001
+#define PCI_DEVICE_ID_V3_V960V2		0x0002
+#define PCI_DEVICE_ID_V3_V350V2		0x0002
+
+#define PCI_VENDOR_ID_NP		0x11bc
+#define PCI_DEVICE_ID_NP_PCI_FDDI	0x0001
+
+#define PCI_VENDOR_ID_ATT		0x11c1
+#define PCI_DEVICE_ID_ATT_L56XMF	0x0440
+
+#define PCI_VENDOR_ID_SPECIALIX		0x11cb
+#define PCI_DEVICE_ID_SPECIALIX_IO8	0x2000
+#define PCI_DEVICE_ID_SPECIALIX_XIO	0x4000
+#define PCI_DEVICE_ID_SPECIALIX_RIO	0x8000
+
+#define PCI_VENDOR_ID_AURAVISION	0x11d1
+#define PCI_DEVICE_ID_AURAVISION_VXP524	0x01f7
+
+#define PCI_VENDOR_ID_IKON		0x11d5
+#define PCI_DEVICE_ID_IKON_10115	0x0115
+#define PCI_DEVICE_ID_IKON_10117	0x0117
+
+#define PCI_VENDOR_ID_ZORAN		0x11de
+#define PCI_DEVICE_ID_ZORAN_36057	0x6057
+#define PCI_DEVICE_ID_ZORAN_36120	0x6120
+
+#define PCI_VENDOR_ID_KINETIC		0x11f4
+#define PCI_DEVICE_ID_KINETIC_2915	0x2915
+
+#define PCI_VENDOR_ID_COMPEX		0x11f6
+#define PCI_DEVICE_ID_COMPEX_ENET100VG4	0x0112
+#define PCI_DEVICE_ID_COMPEX_RL2000	0x1401
+
+#define PCI_VENDOR_ID_RP               0x11fe
+#define PCI_DEVICE_ID_RP32INTF         0x0001
+#define PCI_DEVICE_ID_RP8INTF          0x0002
+#define PCI_DEVICE_ID_RP16INTF         0x0003
+#define PCI_DEVICE_ID_RP4QUAD	       0x0004
+#define PCI_DEVICE_ID_RP8OCTA          0x0005
+#define PCI_DEVICE_ID_RP8J	       0x0006
+#define PCI_DEVICE_ID_RPP4	       0x000A
+#define PCI_DEVICE_ID_RPP8	       0x000B
+#define PCI_DEVICE_ID_RP8M	       0x000C
+
+#define PCI_VENDOR_ID_CYCLADES		0x120e
+#define PCI_DEVICE_ID_CYCLOM_Y_Lo	0x0100
+#define PCI_DEVICE_ID_CYCLOM_Y_Hi	0x0101
+#define PCI_DEVICE_ID_CYCLOM_4Y_Lo	0x0102
+#define PCI_DEVICE_ID_CYCLOM_4Y_Hi	0x0103
+#define PCI_DEVICE_ID_CYCLOM_8Y_Lo	0x0104
+#define PCI_DEVICE_ID_CYCLOM_8Y_Hi	0x0105
+#define PCI_DEVICE_ID_CYCLOM_Z_Lo	0x0200
+#define PCI_DEVICE_ID_CYCLOM_Z_Hi	0x0201
+
+#define PCI_VENDOR_ID_ESSENTIAL		0x120f
+#define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER	0x0001
+
+#define PCI_VENDOR_ID_O2		0x1217
+#define PCI_DEVICE_ID_O2_6729		0x6729
+#define PCI_DEVICE_ID_O2_6730		0x673a
+#define PCI_DEVICE_ID_O2_6832		0x6832
+#define PCI_DEVICE_ID_O2_6836		0x6836
+
+#define PCI_VENDOR_ID_3DFX		0x121a
+#define PCI_DEVICE_ID_3DFX_VOODOO	0x0001
+#define PCI_DEVICE_ID_3DFX_VOODOO2	0x0002
+#define PCI_DEVICE_ID_3DFX_BANSHEE      0x0003
+#define PCI_DEVICE_ID_3DFX_VOODOO3	0x0005
+
+#define PCI_VENDOR_ID_SIGMADES		0x1236
+#define PCI_DEVICE_ID_SIGMADES_6425	0x6401
+
+#define PCI_VENDOR_ID_CCUBE		0x123f
+
+#define PCI_VENDOR_ID_AVM		0x1244
+#define PCI_DEVICE_ID_AVM_A1		0x0a00
+
+#define PCI_VENDOR_ID_DIPIX		0x1246
+
+#define PCI_VENDOR_ID_STALLION		0x124d
+#define PCI_DEVICE_ID_STALLION_ECHPCI832 0x0000
+#define PCI_DEVICE_ID_STALLION_ECHPCI864 0x0002
+#define PCI_DEVICE_ID_STALLION_EIOPCI	0x0003
+
+#define PCI_VENDOR_ID_OPTIBASE		0x1255
+#define PCI_DEVICE_ID_OPTIBASE_FORGE	0x1110
+#define PCI_DEVICE_ID_OPTIBASE_FUSION	0x1210
+#define PCI_DEVICE_ID_OPTIBASE_VPLEX	0x2110
+#define PCI_DEVICE_ID_OPTIBASE_VPLEXCC	0x2120
+#define PCI_DEVICE_ID_OPTIBASE_VQUEST	0x2130
+
+#define PCI_VENDOR_ID_ESS		0x125d
+#define PCI_DEVICE_ID_ESS_AUDIOPCI	0x1969
+
+#define PCI_VENDOR_ID_SATSAGEM		0x1267
+#define PCI_DEVICE_ID_SATSAGEM_PCR2101	0x5352
+#define PCI_DEVICE_ID_SATSAGEM_TELSATTURBO 0x5a4b
+
+#define PCI_VENDOR_ID_HUGHES		0x1273
+#define PCI_DEVICE_ID_HUGHES_DIRECPC	0x0002
+
+#define PCI_VENDOR_ID_ENSONIQ		0x1274
+#define PCI_DEVICE_ID_ENSONIQ_AUDIOPCI	0x5000
+#define PCI_DEVICE_ID_ENSONIQ_ES1371    0x1371
+
+#define PCI_VENDOR_ID_ALTEON		0x12ae
+#define PCI_DEVICE_ID_ALTEON_ACENIC	0x0001
+
+#define PCI_SUBVENDOR_ID_CONNECT_TECH			0x12c4
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232		0x0001
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232		0x0002
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232		0x0003
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485		0x0004
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4	0x0005
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485		0x0006
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2	0x0007
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485		0x0008
+
+#define PCI_VENDOR_ID_PICTUREL		0x12c5
+#define PCI_DEVICE_ID_PICTUREL_PCIVST	0x0081
+
+#define PCI_VENDOR_ID_NVIDIA_SGS	0x12d2
+#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018
+
+#define PCI_VENDOR_ID_CBOARDS		0x1307
+#define PCI_DEVICE_ID_CBOARDS_DAS1602_16 0x0001
+
+#define PCI_VENDOR_ID_SIIG		0x131f
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_550	0x1010
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_650	0x1011
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_850	0x1012
+#define PCI_DEVICE_ID_SIIG_1P_10x	0x1020
+#define PCI_DEVICE_ID_SIIG_2P_10x	0x1021
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_550	0x1034
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_650	0x1035
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_850	0x1036
+#define PCI_DEVICE_ID_SIIG_1P_20x	0x2020
+#define PCI_DEVICE_ID_SIIG_2P_20x	0x2021
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_550	0x2040
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_650	0x2041
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_850	0x2042
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_550	0x2010
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_650	0x2011
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_850	0x2012
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_550	0x2060
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_650	0x2061
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_850	0x2062
+
+#define PCI_VENDOR_ID_SEALEVEL		0x135e
+#define PCI_DEVICE_ID_SEALEVEL_U530	0x7101
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM2	0x7201
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM422	0x7402
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM232	0x7202
+#define PCI_DEVICE_ID_SEALEVEL_COMM4	0x7401
+#define PCI_DEVICE_ID_SEALEVEL_COMM8	0x7801
+
+#define PCI_VENDOR_ID_NETGEAR		0x1385
+#define PCI_DEVICE_ID_NETGEAR_GA620	0x620a
+
+#define PCI_VENDOR_ID_LAVA		0x1407
+#define PCI_DEVICE_ID_LAVA_PARALLEL	0x8000
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A	0x8002 /* The Lava Dual Parallel is */
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B	0x8003 /* two PCI devices on a card */
+
+#define PCI_VENDOR_ID_PANACOM		0x14d4
+#define PCI_DEVICE_ID_PANACOM_QUADMODEM	0x0400
+#define PCI_DEVICE_ID_PANACOM_DUALMODEM	0x0402
+
+#define PCI_VENDOR_ID_SYMPHONY		0x1c1c
+#define PCI_DEVICE_ID_SYMPHONY_101	0x0001
+
+#define PCI_VENDOR_ID_TEKRAM		0x1de1
+#define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29
+
+#define PCI_VENDOR_ID_3DLABS		0x3d3d
+#define PCI_DEVICE_ID_3DLABS_300SX	0x0001
+#define PCI_DEVICE_ID_3DLABS_500TX	0x0002
+#define PCI_DEVICE_ID_3DLABS_DELTA	0x0003
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA	0x0004
+#define PCI_DEVICE_ID_3DLABS_MX		0x0006
+
+#define PCI_VENDOR_ID_AVANCE		0x4005
+#define PCI_DEVICE_ID_AVANCE_ALG2064	0x2064
+#define PCI_DEVICE_ID_AVANCE_2302	0x2302
+
+#define PCI_VENDOR_ID_NETVIN		0x4a14
+#define PCI_DEVICE_ID_NETVIN_NV5000SC	0x5000
+
+#define PCI_VENDOR_ID_S3		0x5333
+#define PCI_DEVICE_ID_S3_PLATO_PXS	0x0551
+#define PCI_DEVICE_ID_S3_ViRGE		0x5631
+#define PCI_DEVICE_ID_S3_TRIO		0x8811
+#define PCI_DEVICE_ID_S3_AURORA64VP	0x8812
+#define PCI_DEVICE_ID_S3_TRIO64UVP	0x8814
+#define PCI_DEVICE_ID_S3_ViRGE_VX	0x883d
+#define PCI_DEVICE_ID_S3_868		0x8880
+#define PCI_DEVICE_ID_S3_928		0x88b0
+#define PCI_DEVICE_ID_S3_864_1		0x88c0
+#define PCI_DEVICE_ID_S3_864_2		0x88c1
+#define PCI_DEVICE_ID_S3_964_1		0x88d0
+#define PCI_DEVICE_ID_S3_964_2		0x88d1
+#define PCI_DEVICE_ID_S3_968		0x88f0
+#define PCI_DEVICE_ID_S3_TRIO64V2	0x8901
+#define PCI_DEVICE_ID_S3_PLATO_PXG	0x8902
+#define PCI_DEVICE_ID_S3_ViRGE_DXGX	0x8a01
+#define PCI_DEVICE_ID_S3_ViRGE_GX2	0x8a10
+#define PCI_DEVICE_ID_S3_ViRGE_MX	0x8c01
+#define PCI_DEVICE_ID_S3_ViRGE_MXP	0x8c02
+#define PCI_DEVICE_ID_S3_ViRGE_MXPMV	0x8c03
+#define PCI_DEVICE_ID_S3_SONICVIBES	0xca00
+
+#define PCI_VENDOR_ID_DCI       0x6666
+#define PCI_DEVICE_ID_DCI_PCCOM4    0x0001
+
+#define PCI_VENDOR_ID_GENROCO		0x5555
+#define PCI_DEVICE_ID_GENROCO_HFP832	0x0003
+
+#define PCI_VENDOR_ID_INTEL		0x8086
+#define PCI_DEVICE_ID_INTEL_21145	0x0039
+#define PCI_DEVICE_ID_INTEL_82375	0x0482
+#define PCI_DEVICE_ID_INTEL_82424	0x0483
+#define PCI_DEVICE_ID_INTEL_82378	0x0484
+#define PCI_DEVICE_ID_INTEL_82430	0x0486
+#define PCI_DEVICE_ID_INTEL_82434	0x04a3
+#define PCI_DEVICE_ID_INTEL_I960	0x0960
+#define PCI_DEVICE_ID_INTEL_82559ER	0x1209
+#define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
+#define PCI_DEVICE_ID_INTEL_82092AA_1	0x1222
+#define PCI_DEVICE_ID_INTEL_7116	0x1223
+#define PCI_DEVICE_ID_INTEL_82596	0x1226
+#define PCI_DEVICE_ID_INTEL_82865	0x1227
+#define PCI_DEVICE_ID_INTEL_82557	0x1229
+#define PCI_DEVICE_ID_INTEL_82437	0x122d
+#define PCI_DEVICE_ID_INTEL_82371FB_0	0x122e
+#define PCI_DEVICE_ID_INTEL_82371FB_1	0x1230
+#define PCI_DEVICE_ID_INTEL_82371MX	0x1234
+#define PCI_DEVICE_ID_INTEL_82437MX	0x1235
+#define PCI_DEVICE_ID_INTEL_82441	0x1237
+#define PCI_DEVICE_ID_INTEL_82380FB	0x124b
+#define PCI_DEVICE_ID_INTEL_82439	0x1250
+#define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2	0x7020
+#define PCI_DEVICE_ID_INTEL_82437VX	0x7030
+#define PCI_DEVICE_ID_INTEL_82439TX	0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0	0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB	0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2	0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3	0x7113
+#define PCI_VENDOR_ID_COMPUTONE		0x8e0e
+#define PCI_DEVICE_ID_COMPUTONE_IP2EX	0x0291
+
+#define PCI_DEVICE_ID_INTEL_82443LX_0	0x7180
+#define PCI_DEVICE_ID_INTEL_82443LX_1	0x7181
+#define PCI_DEVICE_ID_INTEL_82443BX_0	0x7190
+#define PCI_DEVICE_ID_INTEL_82443BX_1	0x7191
+#define PCI_DEVICE_ID_INTEL_82443BX_2	0x7192
+#define PCI_DEVICE_ID_INTEL_P6		0x84c4
+#define PCI_DEVICE_ID_INTEL_82450GX	0x84c5
+#define PCI_DEVICE_ID_INTEL_82451NX	0x84ca
+
+#define PCI_VENDOR_ID_KTI		0x8e2e
+#define PCI_DEVICE_ID_KTI_ET32P2	0x3000
+
+#define PCI_VENDOR_ID_ADAPTEC		0x9004
+#define PCI_DEVICE_ID_ADAPTEC_7810	0x1078
+#define PCI_DEVICE_ID_ADAPTEC_7821	0x2178
+#define PCI_DEVICE_ID_ADAPTEC_38602	0x3860
+#define PCI_DEVICE_ID_ADAPTEC_7850	0x5078
+#define PCI_DEVICE_ID_ADAPTEC_7855	0x5578
+#define PCI_DEVICE_ID_ADAPTEC_5800	0x5800
+#define PCI_DEVICE_ID_ADAPTEC_3860	0x6038
+#define PCI_DEVICE_ID_ADAPTEC_1480A	0x6075
+#define PCI_DEVICE_ID_ADAPTEC_7860	0x6078
+#define PCI_DEVICE_ID_ADAPTEC_7861	0x6178
+#define PCI_DEVICE_ID_ADAPTEC_7870	0x7078
+#define PCI_DEVICE_ID_ADAPTEC_7871	0x7178
+#define PCI_DEVICE_ID_ADAPTEC_7872	0x7278
+#define PCI_DEVICE_ID_ADAPTEC_7873	0x7378
+#define PCI_DEVICE_ID_ADAPTEC_7874	0x7478
+#define PCI_DEVICE_ID_ADAPTEC_7895	0x7895
+#define PCI_DEVICE_ID_ADAPTEC_7880	0x8078
+#define PCI_DEVICE_ID_ADAPTEC_7881	0x8178
+#define PCI_DEVICE_ID_ADAPTEC_7882	0x8278
+#define PCI_DEVICE_ID_ADAPTEC_7883	0x8378
+#define PCI_DEVICE_ID_ADAPTEC_7884	0x8478
+#define PCI_DEVICE_ID_ADAPTEC_7885	0x8578
+#define PCI_DEVICE_ID_ADAPTEC_7886	0x8678
+#define PCI_DEVICE_ID_ADAPTEC_7887	0x8778
+#define PCI_DEVICE_ID_ADAPTEC_7888	0x8878
+#define PCI_DEVICE_ID_ADAPTEC_1030	0x8b78
+
+#define PCI_VENDOR_ID_ADAPTEC2		0x9005
+#define PCI_DEVICE_ID_ADAPTEC2_2940U2	0x0010
+#define PCI_DEVICE_ID_ADAPTEC2_2930U2	0x0011
+#define PCI_DEVICE_ID_ADAPTEC2_7890B	0x0013
+#define PCI_DEVICE_ID_ADAPTEC2_7890	0x001f
+#define PCI_DEVICE_ID_ADAPTEC2_3940U2	0x0050
+#define PCI_DEVICE_ID_ADAPTEC2_3950U2D	0x0051
+#define PCI_DEVICE_ID_ADAPTEC2_7896	0x005f
+#define PCI_DEVICE_ID_ADAPTEC2_7892A	0x0080
+#define PCI_DEVICE_ID_ADAPTEC2_7892B	0x0081
+#define PCI_DEVICE_ID_ADAPTEC2_7892D	0x0083
+#define PCI_DEVICE_ID_ADAPTEC2_7892P	0x008f
+#define PCI_DEVICE_ID_ADAPTEC2_7899A	0x00c0
+#define PCI_DEVICE_ID_ADAPTEC2_7899B	0x00c1
+#define PCI_DEVICE_ID_ADAPTEC2_7899D	0x00c3
+#define PCI_DEVICE_ID_ADAPTEC2_7899P	0x00cf
+
+#define PCI_VENDOR_ID_ATRONICS		0x907f
+#define PCI_DEVICE_ID_ATRONICS_2015	0x2015
+
+#define PCI_VENDOR_ID_HOLTEK		0x9412
+#define PCI_DEVICE_ID_HOLTEK_6565	0x6565
+
+#define PCI_VENDOR_ID_EXSYS		0xd84d
+#define PCI_DEVICE_ID_EXSYS_4014		0x4014
+
+#define PCI_VENDOR_ID_TIGERJET		0xe159
+#define PCI_DEVICE_ID_TIGERJET_300	0x0001
+
+#define PCI_VENDOR_ID_ARK		0xedd8
+#define PCI_DEVICE_ID_ARK_STING		0xa091
+#define PCI_DEVICE_ID_ARK_STINGARK	0xa099
+#define PCI_DEVICE_ID_ARK_2000MT	0xa0a1
+
+#define PCI_VENDOR_ID_INTERPHASE		0x107e
+#define PCI_DEVICE_ID_INTERPHASE_5526	0x0004
+#define PCI_DEVICE_ID_INTERPHASE_55x6	0x0005
+
+#define PCI_VENDOR_ID_INTERPHASE		0x107e
+#define PCI_DEVICE_ID_INTERPHASE_5526	0x0004
+#define PCI_DEVICE_ID_INTERPHASE_55x6	0x0005
+
+#define PCI_VENDOR_ID_INTERPHASE		0x107e
+#define PCI_DEVICE_ID_INTERPHASE_5526	0x0004
+#define PCI_DEVICE_ID_INTERPHASE_55x6	0x0005
+
diff -u --recursive --new-file v2.3.19/linux/include/linux/prctl.h linux/include/linux/prctl.h
--- v2.3.19/linux/include/linux/prctl.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/prctl.h	Thu Oct  7 10:17:09 1999
@@ -6,5 +6,8 @@
 #define PR_SET_PDEATHSIG  1  /* Second arg is a signal */
 #define PR_GET_PDEATHSIG  2  /* Second arg is a ptr to return the signal */
 
+/* Get/set current->dumpable */
+#define PR_GET_DUMPABLE   3
+#define PR_SET_DUMPABLE   4
 
 #endif /* _LINUX_PRCTL_H */
diff -u --recursive --new-file v2.3.19/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.19/linux/include/linux/proc_fs.h	Fri Sep 10 23:57:37 1999
+++ linux/include/linux/proc_fs.h	Fri Oct  8 10:25:54 1999
@@ -199,6 +199,7 @@
 	PROC_SCSI_MVME147,
 	PROC_SCSI_MVME16x,
 	PROC_SCSI_BVME6000,
+	PROC_SCSI_SIM710,
 	PROC_SCSI_A3000,
 	PROC_SCSI_A2091,
 	PROC_SCSI_GVP11,
diff -u --recursive --new-file v2.3.19/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.19/linux/include/linux/sched.h	Fri Sep 10 23:57:37 1999
+++ linux/include/linux/sched.h	Fri Oct  8 10:25:28 1999
@@ -142,6 +142,8 @@
 extern void show_state(void);
 extern void cpu_init (void);
 extern void trap_init(void);
+extern void update_one_process( struct task_struct *p,
+	unsigned long ticks, unsigned long user, unsigned long system, int cpu);
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
diff -u --recursive --new-file v2.3.19/linux/include/linux/smp.h linux/include/linux/smp.h
--- v2.3.19/linux/include/linux/smp.h	Wed Aug 18 16:43:30 1999
+++ linux/include/linux/smp.h	Fri Oct  8 10:25:19 1999
@@ -80,7 +80,7 @@
 #define smp_threads_ready			1
 #define kernel_lock()
 #define cpu_logical_map(cpu)			0
-#define smp_call_function(func,info,retry,wait)
+#define smp_call_function(func,info,retry,wait)	0
 
 #endif
 #endif
diff -u --recursive --new-file v2.3.19/linux/include/linux/sunrpc/xprt.h linux/include/linux/sunrpc/xprt.h
--- v2.3.19/linux/include/linux/sunrpc/xprt.h	Wed Aug 18 16:45:06 1999
+++ linux/include/linux/sunrpc/xprt.h	Fri Oct  8 10:25:30 1999
@@ -124,8 +124,10 @@
 struct rpc_xprt {
 	struct rpc_xprt *	link;		/* list of all clients */
 	struct rpc_xprt *	rx_pending;	/* receive pending list */
+	struct rpc_xprt *	tx_pending;	/* transmit pending list */
 	
-	int 			rx_pending_flag;/* are we on the pending list ? */
+	int 			rx_pending_flag;/* are we on the rcv pending list ? */
+	int 			tx_pending_flag;/* are we on the xmit pending list ? */
 
 	struct file *		file;		/* VFS layer */
 	struct socket *		sock;		/* BSD socket layer */
diff -u --recursive --new-file v2.3.19/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.3.19/linux/include/scsi/sg.h	Mon Jun  7 16:20:36 1999
+++ linux/include/scsi/sg.h	Thu Oct  7 10:17:09 1999
@@ -12,10 +12,16 @@
 *       Copyright (C) 1998, 1999 Douglas Gilbert
 
 
-    Version: 2.1.34 (990603)
-    This version for later 2.1.x and 2.2.x series kernels
-    D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
-
+    Version: 2.3.35 (990708)
+    This version for 2.3 series kernels. It only differs from sg version
+    2.1.35 used in the 2.2 series kernels by changes to wait_queue. This
+    in an internal kernel interface and should not effect users.
+        D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
+
+    Changes since 2.1.34 (990603)
+        - add queuing info into struct sg_scsi_id
+        - block negative timeout values
+        - add back write() wait on previous read() when no cmd queuing
     Changes since 2.1.33 (990521)
         - implement SG_SET_RESERVED_SIZE and associated memory re-org.
         - add SG_NEXT_CMD_LEN to override SCSI command lengths
@@ -144,9 +150,10 @@
     int scsi_id;        /* scsi id of target device */
     int lun;
     int scsi_type;      /* TYPE_... defined in scsi/scsi.h */
+    short h_cmd_per_lun;/* host (adapter) maximum commands per lun */
+    short d_queue_depth;/* device (or adapter) maximum queue length */
     int unused1;        /* probably find a good use, set 0 for now */
     int unused2;        /* ditto */
-    int unused3;  
 } Sg_scsi_id;
 
 /* IOCTLs: ( _GET_s yield result via 'int *' 3rd argument unless 
@@ -204,6 +211,10 @@
 #define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */
 #define SG_NEXT_CMD_LEN 0x2283  /* override SCSI command length with given
                    number on the next write() on this file descriptor */
+
+/* Returns -EBUSY if occupied else takes as input: 0 -> do nothing,
+   1 -> device reset or  2 -> bus reset (may not be activated yet) */
+#define SG_SCSI_RESET 0x2284
 
 
 #define SG_SCATTER_SZ (8 * 4096)  /* PAGE_SIZE not available to user */
diff -u --recursive --new-file v2.3.19/linux/init/main.c linux/init/main.c
--- v2.3.19/linux/init/main.c	Mon Oct  4 15:49:30 1999
+++ linux/init/main.c	Thu Oct  7 10:17:09 1999
@@ -439,8 +439,6 @@
 
 #endif
 
-extern void initialize_secondary(void);
-
 /*
  *	Activate the first processor.
  */
@@ -448,14 +446,6 @@
 asmlinkage void __init start_kernel(void)
 {
 	char * command_line;
-
-#ifdef __SMP__
-	static int boot_cpu = 1;
-	/* "current" has been set up, we need to load it now */
-	if (!boot_cpu)
-		initialize_secondary();
-	boot_cpu = 0;
-#endif
 
 /*
  * Interrupts are still disabled. Do necessary setups, then
diff -u --recursive --new-file v2.3.19/linux/ipc/msg.c linux/ipc/msg.c
--- v2.3.19/linux/ipc/msg.c	Tue Aug 31 17:29:15 1999
+++ linux/ipc/msg.c	Thu Oct  7 10:17:09 1999
@@ -9,19 +9,80 @@
  * Copyright (C) 1998 Alan Cox & Andi Kleen
  *
  * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
+ *
+ * mostly rewritten, threaded and wake-one semantics added
+ * (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
  */
 
 #include <linux/config.h>
 #include <linux/malloc.h>
 #include <linux/msg.h>
-#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/list.h>
 
 #include <asm/uaccess.h>
 
-extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
+#define USHRT_MAX	0xffff
+/* one ms_receiver structure for each sleeping receiver */
+struct msg_receiver {
+	struct list_head r_list;
+	struct task_struct* r_tsk;
+
+	int r_mode;
+	long r_msgtype;
+	long r_maxsize;
+
+	struct msg_msg* volatile r_msg;
+};
+
+/* one msg_msg structure for each message */
+struct msg_msg {
+	struct list_head m_list; 
+	long  m_type;          
+	int m_ts;           /* message text size */
+	/* the actual message follows immediately */
+};
+
+
+/* one msq_queue structure for each present queue on the system */
+struct msg_queue {
+	struct ipc_perm q_perm;
+	__kernel_time_t q_stime;	/* last msgsnd time */
+	__kernel_time_t q_rtime;	/* last msgrcv time */
+	__kernel_time_t q_ctime;	/* last change time */
+	unsigned int  q_cbytes;		/* current number of bytes on queue */
+	unsigned int  q_qnum;		/* number of messages in queue */
+	unsigned int  q_qbytes;		/* max number of bytes on queue */
+	__kernel_ipc_pid_t q_lspid;	/* pid of last msgsnd */
+	__kernel_ipc_pid_t q_lrpid;	/* last receive pid */
+
+	struct list_head q_messages;
+	struct list_head q_receivers;
+	wait_queue_head_t q_rwait;
+};
+
+/* one msq_array structure for each possible queue on the system */
+struct msg_array {
+	spinlock_t lock;
+	struct msg_queue* q;
+};
+
+#define SEARCH_ANY		1
+#define SEARCH_EQUAL		2
+#define SEARCH_NOTEQUAL		3
+#define SEARCH_LESSEQUAL	4
+
+static DECLARE_MUTEX(msg_lock);
+static struct msg_array msg_que[MSGMNI];
+
+static unsigned short msg_seq = 0;
+static int msg_used_queues = 0;
+static int msg_max_id = -1;
+
+static atomic_t msg_bytes = ATOMIC_INIT(0);
+static atomic_t msg_hdrs = ATOMIC_INIT(0);
 
 static void freeque (int id);
 static int newque (key_t key, int msgflg);
@@ -30,13 +91,8 @@
 static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
 #endif
 
-static struct msqid_ds_kern *msgque[MSGMNI];
-static int msgbytes = 0;
-static int msghdrs = 0;
-static unsigned short msg_seq = 0;
-static int used_queues = 0;
-static int max_msqid = 0;
-static DECLARE_WAIT_QUEUE_HEAD(msg_lock);
+/* implemented in ipc/util.c, thread-safe */
+extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
 
 void __init msg_init (void)
 {
@@ -45,279 +101,137 @@
 	struct proc_dir_entry *ent;
 #endif
 
-	for (id = 0; id < MSGMNI; id++) 
-		msgque[id] = (struct msqid_ds_kern *) IPC_UNUSED;
-	msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
-	init_waitqueue_head(&msg_lock);
+	for (id = 0; id < MSGMNI; id++) {
+		msg_que[id].lock = SPIN_LOCK_UNLOCKED;
+		msg_que[id].q = NULL;
+	}
 #ifdef CONFIG_PROC_FS
 	ent = create_proc_entry("sysvipc/msg", 0, 0);
 	ent->read_proc = sysvipc_msg_read_proc;
 #endif
-	return;
 }
 
-static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
+static int findkey (key_t key)
 {
 	int id;
-	struct msqid_ds_kern *msq;
-	struct ipc_perm *ipcp;
-	struct msg *msgh;
-	long mtype;
+	struct msg_queue *msq;
 	
-	if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
-		return -EINVAL;
-	if (get_user(mtype, &msgp->mtype))
-		return -EFAULT; 
-	if (mtype < 1)
-		return -EINVAL;
-	id = (unsigned int) msqid % MSGMNI;
-	msq = msgque [id];
-	if (msq == IPC_UNUSED || msq == IPC_NOID)
-		return -EINVAL;
-	ipcp = &msq->msg_perm; 
-
- slept:
-	if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) 
-		return -EIDRM;
-
-	if (ipcperms(ipcp, S_IWUGO)) 
-		return -EACCES;
-	
-	if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { 
-		if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { 
-			/* still no space in queue */
-			if (msgflg & IPC_NOWAIT)
-				return -EAGAIN;
-			if (signal_pending(current))
-				return -EINTR;
-			interruptible_sleep_on (&msq->wwait);
-			goto slept;
-		}
-	}
-	
-	/* allocate message header and text space*/ 
-	msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_KERNEL);
-	if (!msgh)
-		return -ENOMEM;
-	msgh->msg_spot = (char *) (msgh + 1);
-
-	if (copy_from_user(msgh->msg_spot, msgp->mtext, msgsz))
-	{
-		kfree(msgh);
-		return -EFAULT;
+	for (id = 0; id <= msg_max_id; id++) {
+		msq = msg_que[id].q;
+		if(msq == NULL)
+			continue;
+		if (key == msq->q_perm.key)
+			return id;
 	}
-	
-	if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
-		|| msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
-		kfree(msgh);
-		return -EIDRM;
-	}
-
-	msgh->msg_next = NULL;
-	msgh->msg_ts = msgsz;
-	msgh->msg_type = mtype;
-	msgh->msg_stime = CURRENT_TIME;
-
-	if (!msq->msg_first)
-		msq->msg_first = msq->msg_last = msgh;
-	else {
-		msq->msg_last->msg_next = msgh;
-		msq->msg_last = msgh;
-	}
-	msq->msg_cbytes += msgsz;
-	msgbytes  += msgsz;
-	msghdrs++;
-	msq->msg_qnum++;
-	msq->msg_lspid = current->pid;
-	msq->msg_stime = CURRENT_TIME;
-	wake_up (&msq->rwait);
-	return 0;
+	return -1;
 }
 
-static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
+static int newque (key_t key, int msgflg)
 {
-	struct msqid_ds_kern *msq;
-	struct ipc_perm *ipcp;
-	struct msg *tmsg, *leastp = NULL;
-	struct msg *nmsg = NULL;
 	int id;
+	struct msg_queue *msq;
+	struct ipc_perm *ipcp;
 
-	if (msqid < 0 || (long) msgsz < 0)
-		return -EINVAL;
+	for (id = 0; id < MSGMNI; id++) {
+		if (msg_que[id].q == NULL)
+			break;
+	}
+	if(id == MSGMNI)
+		return -ENOSPC;
 
-	id = (unsigned int) msqid % MSGMNI;
-	msq = msgque [id];
-	if (msq == IPC_NOID || msq == IPC_UNUSED)
-		return -EINVAL;
-	ipcp = &msq->msg_perm; 
+	msq  = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL);
+	if (!msq) 
+		return -ENOMEM;
 
-	/* 
-	 *  find message of correct type.
-	 *  msgtyp = 0 => get first.
-	 *  msgtyp > 0 => get first message of matching type.
-	 *  msgtyp < 0 => get message with least type must be < abs(msgtype).  
+	ipcp = &msq->q_perm;
+	ipcp->mode = (msgflg & S_IRWXUGO);
+	ipcp->key = key;
+	ipcp->cuid = ipcp->uid = current->euid;
+	ipcp->gid = ipcp->cgid = current->egid;
+
+	/* ipcp->seq*MSGMNI must be a positive integer.
+	 * this limits MSGMNI to 32768
 	 */
-	while (!nmsg) {
-		if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
-			return -EIDRM;
-		}
-		if (ipcperms (ipcp, S_IRUGO)) {
-			return -EACCES;
-		}
-
-		if (msgtyp == 0) 
-			nmsg = msq->msg_first;
-		else if (msgtyp > 0) {
-			if (msgflg & MSG_EXCEPT) { 
-				for (tmsg = msq->msg_first; tmsg; 
-				     tmsg = tmsg->msg_next)
-					if (tmsg->msg_type != msgtyp)
-						break;
-				nmsg = tmsg;
-			} else {
-				for (tmsg = msq->msg_first; tmsg; 
-				     tmsg = tmsg->msg_next)
-					if (tmsg->msg_type == msgtyp)
-						break;
-				nmsg = tmsg;
-			}
-		} else {
-			for (leastp = tmsg = msq->msg_first; tmsg; 
-			     tmsg = tmsg->msg_next) 
-				if (tmsg->msg_type < leastp->msg_type) 
-					leastp = tmsg;
-			if (leastp && leastp->msg_type <= - msgtyp)
-				nmsg = leastp;
-		}
-		
-		if (nmsg) { /* done finding a message */
-			if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) {
-				return -E2BIG;
-			}
-			msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
-			if (nmsg ==  msq->msg_first)
-				msq->msg_first = nmsg->msg_next;
-			else {
-				for (tmsg = msq->msg_first; tmsg; 
-				     tmsg = tmsg->msg_next)
-					if (tmsg->msg_next == nmsg) 
-						break;
-				tmsg->msg_next = nmsg->msg_next;
-				if (nmsg == msq->msg_last)
-					msq->msg_last = tmsg;
-			}
-			if (!(--msq->msg_qnum))
-				msq->msg_last = msq->msg_first = NULL;
-			
-			msq->msg_rtime = CURRENT_TIME;
-			msq->msg_lrpid = current->pid;
-			msgbytes -= nmsg->msg_ts; 
-			msghdrs--; 
-			msq->msg_cbytes -= nmsg->msg_ts;
-			wake_up (&msq->wwait);
-			if (put_user (nmsg->msg_type, &msgp->mtype) ||
-			    copy_to_user (msgp->mtext, nmsg->msg_spot, msgsz))
-				msgsz = -EFAULT; 
-			kfree(nmsg);
-			return msgsz;
-		} else {  /* did not find a message */
-			if (msgflg & IPC_NOWAIT) {
-				return -ENOMSG;
-			}
-			if (signal_pending(current)) {
-				return -EINTR; 
-			}
-			interruptible_sleep_on (&msq->rwait);
-		}
-	} /* end while */
-	return -1;
-}
+	ipcp->seq = msg_seq++;
 
-asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
-{
-	int ret;
+	msq->q_stime = msq->q_rtime = 0;
+	msq->q_ctime = CURRENT_TIME;
+	msq->q_cbytes = msq->q_qnum = 0;
+	msq->q_qbytes = MSGMNB;
+	msq->q_lspid = msq->q_lrpid = 0;
+	INIT_LIST_HEAD(&msq->q_messages);
+	INIT_LIST_HEAD(&msq->q_receivers);
+	init_waitqueue_head(&msq->q_rwait);
+
+	if (id > msg_max_id)
+		msg_max_id = id;
+	spin_lock(&msg_que[id].lock);
+	msg_que[id].q = msq;
+	spin_unlock(&msg_que[id].lock);
+	msg_used_queues++;
 
-	lock_kernel();
-	ret = real_msgsnd(msqid, msgp, msgsz, msgflg);
-	unlock_kernel();
-	return ret;
+	return (int)msq->q_perm.seq * MSGMNI + id;
 }
 
-asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
-			    long msgtyp, int msgflg)
+static void expunge_all(struct msg_queue* msq, int res)
 {
-	int ret;
+	struct list_head *tmp;
 
-	lock_kernel();
-	ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg);
-	unlock_kernel();
-	return ret;
+	tmp = msq->q_receivers.next;
+	while (tmp != &msq->q_receivers) {
+		struct msg_receiver* msr;
+		
+		msr = list_entry(tmp,struct msg_receiver,r_list);
+		tmp = tmp->next;
+		msr->r_msg = ERR_PTR(res);
+		wake_up_process(msr->r_tsk);
+	}
 }
 
-static int findkey (key_t key)
+static void freeque (int id)
 {
-	int id;
-	struct msqid_ds_kern *msq;
-	
-	for (id = 0; id <= max_msqid; id++) {
-		while ((msq = msgque[id]) == IPC_NOID) 
-			interruptible_sleep_on (&msg_lock);
-		if (msq == IPC_UNUSED)
-			continue;
-		if (key == msq->msg_perm.key)
-			return id;
+	struct msg_queue *msq;
+	struct list_head *tmp;
+
+	msq=msg_que[id].q;
+	msg_que[id].q = NULL;
+	if (id == msg_max_id) {
+		while ((msg_que[msg_max_id].q == NULL)) {
+			if(msg_max_id--== 0)
+				break;
+		}
 	}
-	return -1;
-}
+	msg_used_queues--;
 
-static int newque (key_t key, int msgflg)
-{
-	int id;
-	struct msqid_ds_kern *msq;
-	struct ipc_perm *ipcp;
+	expunge_all(msq,-EIDRM);
 
-	for (id = 0; id < MSGMNI; id++) 
-		if (msgque[id] == IPC_UNUSED) {
-			msgque[id] = (struct msqid_ds_kern *) IPC_NOID;
-			goto found;
-		}
-	return -ENOSPC;
-
-found:
-	msq = (struct msqid_ds_kern *) kmalloc (sizeof (*msq), GFP_KERNEL);
-	if (!msq) {
-		msgque[id] = (struct msqid_ds_kern *) IPC_UNUSED;
-		wake_up (&msg_lock);
-		return -ENOMEM;
+	while(waitqueue_active(&msq->q_rwait)) {
+		wake_up(&msq->q_rwait);
+		spin_unlock(&msg_que[id].lock);
+		current->policy |= SCHED_YIELD;
+		schedule();
+		spin_lock(&msg_que[id].lock);
 	}
-	ipcp = &msq->msg_perm;
-	ipcp->mode = (msgflg & S_IRWXUGO);
-	ipcp->key = key;
-	ipcp->cuid = ipcp->uid = current->euid;
-	ipcp->gid = ipcp->cgid = current->egid;
-	msq->msg_perm.seq = msg_seq;
-	msq->msg_first = msq->msg_last = NULL;
-	init_waitqueue_head(&msq->wwait);
-	init_waitqueue_head(&msq->rwait);
-	msq->msg_cbytes = msq->msg_qnum = 0;
-	msq->msg_lspid = msq->msg_lrpid = 0;
-	msq->msg_stime = msq->msg_rtime = 0;
-	msq->msg_qbytes = MSGMNB;
-	msq->msg_ctime = CURRENT_TIME;
-	if (id > max_msqid)
-		max_msqid = id;
-	msgque[id] = msq;
-	used_queues++;
-	wake_up (&msg_lock);
-	return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
+	spin_unlock(&msg_que[id].lock);
+		
+	tmp = msq->q_messages.next;
+	while(tmp != &msq->q_messages) {
+		struct msg_msg* msg = list_entry(tmp,struct msg_msg,m_list);
+		tmp = tmp->next;
+		atomic_dec(&msg_hdrs);
+		kfree(msg);
+	}
+	atomic_sub(msq->q_cbytes, &msg_bytes);
+	kfree(msq);
 }
 
+
 asmlinkage long sys_msgget (key_t key, int msgflg)
 {
 	int id, ret = -EPERM;
-	struct msqid_ds_kern *msq;
+	struct msg_queue *msq;
 	
-	lock_kernel();
+	down(&msg_lock);
 	if (key == IPC_PRIVATE) 
 		ret = newque(key, msgflg);
 	else if ((id = findkey (key)) == -1) { /* key not used */
@@ -328,61 +242,38 @@
 	} else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
 		ret = -EEXIST;
 	} else {
-		msq = msgque[id];
-		if (msq == IPC_UNUSED || msq == IPC_NOID)
-			ret = -EIDRM;
-		else if (ipcperms(&msq->msg_perm, msgflg))
+		msq = msg_que[id].q;
+		if (ipcperms(&msq->q_perm, msgflg))
 			ret = -EACCES;
 		else
-			ret = (unsigned int) msq->msg_perm.seq * MSGMNI + id;
+			ret = (unsigned int) msq->q_perm.seq * MSGMNI + id;
 	}
-	unlock_kernel();
+	up(&msg_lock);
 	return ret;
-} 
-
-static void freeque (int id)
-{
-	struct msqid_ds_kern *msq = msgque[id];
-	struct msg *msgp, *msgh;
-
-	msq->msg_perm.seq++;
-	msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI); /* increment, but avoid overflow */
-	msgbytes -= msq->msg_cbytes;
-	if (id == max_msqid)
-		while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
-	msgque[id] = (struct msqid_ds_kern *) IPC_UNUSED;
-	used_queues--;
-	while (waitqueue_active(&msq->rwait) || waitqueue_active(&msq->wwait)) {
-		wake_up (&msq->rwait); 
-		wake_up (&msq->wwait);
-		schedule(); 
-	}
-	for (msgp = msq->msg_first; msgp; msgp = msgh ) {
-		msgh = msgp->msg_next;
-		msghdrs--;
-		kfree(msgp);
-	}
-	kfree(msq);
 }
 
 asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
 {
-	int id, err = -EINVAL;
-	struct msqid_ds_kern *msq;
+	int id, err;
+	struct msg_queue *msq;
 	struct msqid_ds tbuf;
 	struct ipc_perm *ipcp;
 	
-	lock_kernel();
 	if (msqid < 0 || cmd < 0)
-		goto out;
-	err = -EFAULT;
+		return -EINVAL;
+	id = msqid % MSGMNI;
 	switch (cmd) {
 	case IPC_INFO: 
 	case MSG_INFO: 
-		if (!buf)
-			goto out;
 	{ 
 		struct msginfo msginfo;
+		if (!buf)
+			return -EFAULT;
+		/* We must not return kernel stack data.
+		 * due to variable alignment, it's not enough
+		 * to set all member fields.
+		 */
+		memset(&msginfo,0,sizeof(msginfo));	
 		msginfo.msgmni = MSGMNI;
 		msginfo.msgmax = MSGMAX;
 		msginfo.msgmnb = MSGMNB;
@@ -392,120 +283,416 @@
 		msginfo.msgssz = MSGSSZ;
 		msginfo.msgseg = MSGSEG;
 		if (cmd == MSG_INFO) {
-			msginfo.msgpool = used_queues;
-			msginfo.msgmap = msghdrs;
-			msginfo.msgtql = msgbytes;
+			msginfo.msgpool = msg_used_queues;
+			msginfo.msgmap = atomic_read(&msg_hdrs);
+			msginfo.msgtql = atomic_read(&msg_bytes);
 		}
 
-		err = -EFAULT; 
 		if (copy_to_user (buf, &msginfo, sizeof(struct msginfo)))
-			goto out; 
-		err = max_msqid;
-		goto out;
+			return -EFAULT;
+		return (msg_max_id < 0) ? 0: msg_max_id;
 	}
 	case MSG_STAT:
+	case IPC_STAT:
+	{
+		int success_return;
 		if (!buf)
-			goto out;
+			return -EFAULT;
+		if(cmd == MSG_STAT && msqid > MSGMNI)
+			return -EINVAL;
+
+		spin_lock(&msg_que[id].lock);
+		msq = msg_que[id].q;
 		err = -EINVAL;
-		if (msqid > max_msqid)
-			goto out;
-		msq = msgque[msqid];
-		if (msq == IPC_UNUSED || msq == IPC_NOID)
-			goto out;
+		if (msq == NULL)
+			goto out_unlock;
+		if(cmd == MSG_STAT) {
+			success_return = (unsigned int) msq->q_perm.seq * MSGMNI + msqid;
+		} else {
+			err = -EIDRM;
+			if (msq->q_perm.seq != (unsigned int) msqid / MSGMNI)
+				goto out_unlock;
+			success_return = 0;
+		}
 		err = -EACCES;
-		if (ipcperms (&msq->msg_perm, S_IRUGO))
-			goto out;
-		id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
-		tbuf.msg_perm   = msq->msg_perm;
-		tbuf.msg_stime  = msq->msg_stime;
-		tbuf.msg_rtime  = msq->msg_rtime;
-		tbuf.msg_ctime  = msq->msg_ctime;
-		tbuf.msg_cbytes = msq->msg_cbytes;
-		tbuf.msg_lcbytes = msq->msg_cbytes;
-		tbuf.msg_qnum   = msq->msg_qnum;
-		tbuf.msg_lqbytes = msq->msg_qbytes;
-		tbuf.msg_qbytes = msq->msg_qbytes;
-		tbuf.msg_lspid  = msq->msg_lspid;
-		tbuf.msg_lrpid  = msq->msg_lrpid;
-		err = -EFAULT;
+		if (ipcperms (&msq->q_perm, S_IRUGO))
+			goto out_unlock;
+
+		memset(&tbuf,0,sizeof(tbuf));
+		tbuf.msg_perm   = msq->q_perm;
+		/* tbuf.msg_{first,last}: not reported.*/
+		tbuf.msg_stime  = msq->q_stime;
+		tbuf.msg_rtime  = msq->q_rtime;
+		tbuf.msg_ctime  = msq->q_ctime;
+		if(msq->q_cbytes > USHRT_MAX)
+			tbuf.msg_cbytes = USHRT_MAX;
+		 else
+			tbuf.msg_cbytes = msq->q_cbytes;
+		tbuf.msg_lcbytes = msq->q_cbytes;
+		
+		if(msq->q_qnum > USHRT_MAX)
+			tbuf.msg_qnum = USHRT_MAX;
+		 else
+			tbuf.msg_qnum   = msq->q_qnum;
+
+		if(msq->q_qbytes > USHRT_MAX)
+			tbuf.msg_qbytes = USHRT_MAX;
+		 else
+			tbuf.msg_qbytes = msq->q_qbytes;
+		tbuf.msg_lqbytes = msq->q_qbytes;
+
+		tbuf.msg_lspid  = msq->q_lspid;
+		tbuf.msg_lrpid  = msq->q_lrpid;
+		spin_unlock(&msg_que[id].lock);
 		if (copy_to_user (buf, &tbuf, sizeof(*buf)))
-			goto out; 
-		err = id;
-		goto out;
+			return -EFAULT;
+		return success_return;
+	}
 	case IPC_SET:
 		if (!buf)
-			goto out;
-		err = -EFAULT; 
-		if (!copy_from_user (&tbuf, buf, sizeof (*buf)))
-			err = 0; 
+			return -EFAULT;
+		if (copy_from_user (&tbuf, buf, sizeof (*buf)))
+			return -EFAULT;
 		break;
-	case IPC_STAT:
-		if (!buf)
-			goto out;
+	case IPC_RMID:
 		break;
+	default:
+		return  -EINVAL;
 	}
 
-	id = (unsigned int) msqid % MSGMNI;
-	msq = msgque [id];
+	down(&msg_lock);
+	spin_lock(&msg_que[id].lock);
+	msq = msg_que[id].q;
 	err = -EINVAL;
-	if (msq == IPC_UNUSED || msq == IPC_NOID)
-		goto out;
+	if (msq == NULL)
+		goto out_unlock_up;
 	err = -EIDRM;
-	if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
-		goto out;
-	ipcp = &msq->msg_perm;
+	if (msq->q_perm.seq != (unsigned int) msqid / MSGMNI)
+		goto out_unlock_up;
+	ipcp = &msq->q_perm;
 
 	switch (cmd) {
-	case IPC_STAT:
-		err = -EACCES;
-		if (ipcperms (ipcp, S_IRUGO))
-			goto out;
-		tbuf.msg_perm   = msq->msg_perm;
-		tbuf.msg_stime  = msq->msg_stime;
-		tbuf.msg_rtime  = msq->msg_rtime;
-		tbuf.msg_ctime  = msq->msg_ctime;
-		tbuf.msg_lcbytes = msq->msg_cbytes;
-		tbuf.msg_cbytes = msq->msg_cbytes;
-		tbuf.msg_qnum   = msq->msg_qnum;
-		tbuf.msg_lqbytes = msq->msg_qbytes;
-		tbuf.msg_qbytes = msq->msg_qbytes;
-		tbuf.msg_lspid  = msq->msg_lspid;
-		tbuf.msg_lrpid  = msq->msg_lrpid;
-		err = -EFAULT;
-		if (!copy_to_user (buf, &tbuf, sizeof (*buf)))
-			err = 0;
-		goto out;
 	case IPC_SET:
+	{
+		int newqbytes;
 		err = -EPERM;
 		if (current->euid != ipcp->cuid && 
 		    current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
 		    /* We _could_ check for CAP_CHOWN above, but we don't */
-			goto out;
-		if (tbuf.msg_qbytes > MSGMNB && !capable(CAP_SYS_RESOURCE))
-			goto out;
-		msq->msg_qbytes = tbuf.msg_qbytes;
+			goto out_unlock_up;
+
+		if(tbuf.msg_qbytes == 0)
+			newqbytes = tbuf.msg_lqbytes;
+		 else
+		 	newqbytes = tbuf.msg_qbytes;
+		if (newqbytes > MSGMNB && !capable(CAP_SYS_RESOURCE))
+			goto out_unlock_up;
+		msq->q_qbytes = newqbytes;
+
 		ipcp->uid = tbuf.msg_perm.uid;
 		ipcp->gid =  tbuf.msg_perm.gid;
 		ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
 			(S_IRWXUGO & tbuf.msg_perm.mode);
-		msq->msg_ctime = CURRENT_TIME;
-		err = 0;
-		goto out;
+		msq->q_ctime = CURRENT_TIME;
+		/* sleeping receivers might be excluded by
+		 * stricter permissions.
+		 */
+		expunge_all(msq,-EAGAIN);
+		/* sleeping senders might be able to send
+		 * due to a larger queue size.
+		 */
+		wake_up(&msq->q_rwait);
+		spin_unlock(&msg_que[id].lock);
+		break;
+	}
 	case IPC_RMID:
 		err = -EPERM;
 		if (current->euid != ipcp->cuid && 
 		    current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
-			goto out;
-
+			goto out_unlock;
 		freeque (id); 
-		err = 0;
-		goto out;
-	default:
-		err = -EINVAL;
-		goto out;
+		break;
 	}
-out:
-	unlock_kernel();
+	err = 0;
+out_up:
+	up(&msg_lock);
+	return err;
+out_unlock_up:
+	spin_unlock(&msg_que[id].lock);
+	goto out_up;
+out_unlock:
+	spin_unlock(&msg_que[id].lock);
+	return err;
+}
+
+static int testmsg(struct msg_msg* msg,long type,int mode)
+{
+	switch(mode)
+	{
+		case SEARCH_ANY:
+			return 1;
+		case SEARCH_LESSEQUAL:
+			if(msg->m_type <=type)
+				return 1;
+			break;
+		case SEARCH_EQUAL:
+			if(msg->m_type == type)
+				return 1;
+			break;
+		case SEARCH_NOTEQUAL:
+			if(msg->m_type != type)
+				return 1;
+			break;
+	}
+	return 0;
+}
+
+int inline pipelined_send(struct msg_queue* msq, struct msg_msg* msg)
+{
+	struct list_head* tmp;
+
+	tmp = msq->q_receivers.next;
+	while (tmp != &msq->q_receivers) {
+		struct msg_receiver* msr;
+		msr = list_entry(tmp,struct msg_receiver,r_list);
+		tmp = tmp->next;
+		if(testmsg(msg,msr->r_msgtype,msr->r_mode)) {
+			list_del(&msr->r_list);
+			if(msr->r_maxsize < msg->m_ts) {
+				msr->r_msg = ERR_PTR(-E2BIG);
+				wake_up_process(msr->r_tsk);
+			} else {
+				msr->r_msg = msg;
+				msq->q_lspid = msr->r_tsk->pid;
+				msq->q_rtime = CURRENT_TIME;
+				wake_up_process(msr->r_tsk);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
+{
+	int id;
+	struct msg_queue *msq;
+	struct msg_msg *msg;
+	long mtype;
+	int err;
+	
+	if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
+		return -EINVAL;
+	if (get_user(mtype, &msgp->mtype))
+		return -EFAULT; 
+	if (mtype < 1)
+		return -EINVAL;
+
+	msg = (struct msg_msg *) kmalloc (sizeof(*msg) + msgsz, GFP_KERNEL);
+	if(msg==NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(msg+1, msgp->mtext, msgsz)) {
+		kfree(msg);
+		return -EFAULT;
+	}	
+	msg->m_type = mtype;
+	msg->m_ts = msgsz;
+
+	id = (unsigned int) msqid % MSGMNI;
+	spin_lock(&msg_que[id].lock);
+	err= -EINVAL;
+retry:
+	msq = msg_que[id].q;
+	if (msq == NULL)
+		goto out_free;
+
+	err= -EIDRM;
+	if (msq->q_perm.seq != (unsigned int) msqid / MSGMNI) 
+		goto out_free;
+
+	err=-EACCES;
+	if (ipcperms(&msq->q_perm, S_IWUGO)) 
+		goto out_free;
+
+	if(msgsz + msq->q_cbytes > msq->q_qbytes) {
+		DECLARE_WAITQUEUE(wait,current);
+
+		if(msgflg&IPC_NOWAIT) {
+			err=-EAGAIN;
+			goto out_free;
+		}
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(&msq->q_rwait,&wait);
+		spin_unlock(&msg_que[id].lock);
+		schedule();
+		current->state= TASK_RUNNING;
+		
+		remove_wait_queue(&msq->q_rwait,&wait);
+		if (signal_pending(current)) {
+			kfree(msg);
+			return -EINTR;
+		}
+
+		spin_lock(&msg_que[id].lock);
+		err = -EIDRM;
+		goto retry;
+	}
+
+	if(!pipelined_send(msq,msg)) {
+		/* noone is waiting for this message, enqueue it */
+		list_add_tail(&msg->m_list,&msq->q_messages);
+		msq->q_cbytes += msgsz;
+		msq->q_qnum++;
+		atomic_add(msgsz,&msg_bytes);
+		atomic_inc(&msg_hdrs);
+	}
+	
+	err = 0;
+	msg = NULL;
+	msq->q_lspid = current->pid;
+	msq->q_stime = CURRENT_TIME;
+
+out_free:
+	if(msg!=NULL)
+		kfree(msg);
+	spin_unlock(&msg_que[id].lock);
+	return err;
+}
+
+int inline convert_mode(long* msgtyp, int msgflg)
+{
+	/* 
+	 *  find message of correct type.
+	 *  msgtyp = 0 => get first.
+	 *  msgtyp > 0 => get first message of matching type.
+	 *  msgtyp < 0 => get message with least type must be < abs(msgtype).  
+	 */
+	if(*msgtyp==0)
+		return SEARCH_ANY;
+	if(*msgtyp<0) {
+		*msgtyp=-(*msgtyp);
+		return SEARCH_LESSEQUAL;
+	}
+	if(msgflg & MSG_EXCEPT)
+		return SEARCH_NOTEQUAL;
+	return SEARCH_EQUAL;
+}
+
+asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
+			    long msgtyp, int msgflg)
+{
+	struct msg_queue *msq;
+	struct msg_receiver msr_d;
+	struct list_head* tmp;
+	struct msg_msg* msg, *found_msg;
+	int id;
+	int err;
+	int mode;
+
+	if (msqid < 0 || (long) msgsz < 0)
+		return -EINVAL;
+	mode = convert_mode(&msgtyp,msgflg);
+
+	id = (unsigned int) msqid % MSGMNI;
+	spin_lock(&msg_que[id].lock);
+retry:
+	msq = msg_que[id].q;
+	err=-EINVAL;
+	if (msq == NULL)
+		goto out_unlock;
+	err=-EACCES;
+	if (ipcperms (&msq->q_perm, S_IRUGO))
+		goto out_unlock;
+
+	tmp = msq->q_messages.next;
+	found_msg=NULL;
+	while (tmp != &msq->q_messages) {
+		msg = list_entry(tmp,struct msg_msg,m_list);
+		if(testmsg(msg,msgtyp,mode)) {
+			found_msg = msg;
+			if(mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
+				found_msg=msg;
+				msgtyp=msg->m_type-1;
+			} else {
+				found_msg=msg;
+				break;
+			}
+		}
+		tmp = tmp->next;
+	}
+	if(found_msg) {
+		msg=found_msg;
+		if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
+			err=-E2BIG;
+			goto out_unlock;
+		}
+		list_del(&msg->m_list);
+		msq->q_qnum--;
+		msq->q_rtime = CURRENT_TIME;
+		msq->q_lrpid = current->pid;
+		msq->q_cbytes -= msg->m_ts;
+		atomic_sub(msg->m_ts,&msg_bytes);
+		atomic_dec(&msg_hdrs);
+		if(waitqueue_active(&msq->q_rwait))
+			wake_up(&msq->q_rwait);
+out_success_unlock:
+		spin_unlock(&msg_que[id].lock);
+out_success:
+		msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz;
+		if (put_user (msg->m_type, &msgp->mtype) ||
+			    copy_to_user (msgp->mtext, msg+1, msgsz))
+		{
+			    msgsz = -EFAULT;
+		}
+		kfree(msg);
+		return msgsz;
+	} else
+	{
+		/* no message waiting. Prepare for pipelined
+		 * receive.
+		 */
+		if (msgflg & IPC_NOWAIT) {
+			err=-ENOMSG;
+			goto out_unlock;
+		}
+		list_add_tail(&msr_d.r_list,&msq->q_receivers);
+		msr_d.r_tsk = current;
+		msr_d.r_msgtype = msgtyp;
+		msr_d.r_mode = mode;
+		if(msgflg & MSG_NOERROR)
+			msr_d.r_maxsize = MSGMAX;
+		 else
+		 	msr_d.r_maxsize = msgsz;
+		msr_d.r_msg = ERR_PTR(-EAGAIN);
+		current->state = TASK_INTERRUPTIBLE;
+		spin_unlock(&msg_que[id].lock);
+		schedule();
+		current->state = TASK_RUNNING;
+
+		msg = (struct msg_msg*) msr_d.r_msg;
+		if(!IS_ERR(msg)) 
+			goto out_success;
+
+		spin_lock(&msg_que[id].lock);
+		msg = (struct msg_msg*)msr_d.r_msg;
+		if(!IS_ERR(msg)) {
+			/* our message arived while we waited for
+			 * the spinlock. Process it.
+			 */
+			goto out_success_unlock;
+		}
+		err = PTR_ERR(msg);
+		if(err == -EAGAIN) {
+			list_del(&msr_d.r_list);
+			if (signal_pending(current))
+				err=-EINTR;
+			 else
+				goto retry;
+		}
+	}
+out_unlock:
+	spin_unlock(&msg_que[id].lock);
 	return err;
 }
 
@@ -516,25 +703,28 @@
 	off_t begin = 0;
 	int i, len = 0;
 
+	down(&msg_lock);
 	len += sprintf(buffer, "       key      msqid perms cbytes  qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n");
 
-	for(i = 0; i < MSGMNI; i++)
-		if(msgque[i] != IPC_UNUSED) {
+	for(i = 0; i <= msg_max_id; i++) {
+		spin_lock(&msg_que[i].lock);
+		if(msg_que[i].q != NULL) {
 			len += sprintf(buffer + len, "%10d %10d  %4o  %5u %5u %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
-				msgque[i]->msg_perm.key,
-				msgque[i]->msg_perm.seq * MSGMNI + i,
-				msgque[i]->msg_perm.mode,
-				msgque[i]->msg_cbytes,
-				msgque[i]->msg_qnum,
-				msgque[i]->msg_lspid,
-				msgque[i]->msg_lrpid,
-				msgque[i]->msg_perm.uid,
-				msgque[i]->msg_perm.gid,
-				msgque[i]->msg_perm.cuid,
-				msgque[i]->msg_perm.cgid,
-				msgque[i]->msg_stime,
-				msgque[i]->msg_rtime,
-				msgque[i]->msg_ctime);
+				msg_que[i].q->q_perm.key,
+				msg_que[i].q->q_perm.seq * MSGMNI + i,
+				msg_que[i].q->q_perm.mode,
+				msg_que[i].q->q_cbytes,
+				msg_que[i].q->q_qnum,
+				msg_que[i].q->q_lspid,
+				msg_que[i].q->q_lrpid,
+				msg_que[i].q->q_perm.uid,
+				msg_que[i].q->q_perm.gid,
+				msg_que[i].q->q_perm.cuid,
+				msg_que[i].q->q_perm.cgid,
+				msg_que[i].q->q_stime,
+				msg_que[i].q->q_rtime,
+				msg_que[i].q->q_ctime);
+			spin_unlock(&msg_que[i].lock);
 
 			pos += len;
 			if(pos < offset) {
@@ -543,9 +733,13 @@
 			}
 			if(pos > offset + length)
 				goto done;
+		} else {
+			spin_unlock(&msg_que[i].lock);
 		}
+	}
 	*eof = 1;
 done:
+	up(&msg_lock);
 	*start = buffer + (offset - begin);
 	len -= (offset - begin);
 	if(len > length)
@@ -555,3 +749,4 @@
 	return len;
 }
 #endif
+
diff -u --recursive --new-file v2.3.19/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.19/linux/ipc/shm.c	Tue Sep  7 12:14:07 1999
+++ linux/ipc/shm.c	Fri Oct  8 10:07:23 1999
@@ -7,6 +7,7 @@
  *
  * /proc/sysvipc/shm support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
  * BIGMEM support, Andrea Arcangeli <andrea@suse.de>
+ * SMP thread shm, Jean-Luc Boyard <jean-luc.boyard@siemens.fr>
  */
 
 #include <linux/config.h>
@@ -41,11 +42,13 @@
 static int shm_rss = 0; /* number of shared memory pages that are in memory */
 static int shm_swp = 0; /* number of shared memory pages that are in swap */
 static int max_shmid = 0; /* every used id is <= max_shmid */
-static DECLARE_WAIT_QUEUE_HEAD(shm_lock); /* calling findkey() may need to wait */
+static DECLARE_WAIT_QUEUE_HEAD(shm_wait); /* calling findkey() may need to wait */
 static struct shmid_kernel *shm_segs[SHMMNI];
 
 static unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */
 
+spinlock_t shm_lock = SPIN_LOCK_UNLOCKED;
+
 /* some statistics */
 static ulong swap_attempts = 0;
 static ulong swap_successes = 0;
@@ -61,7 +64,7 @@
 	for (id = 0; id < SHMMNI; id++)
 		shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
 	shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;
-	init_waitqueue_head(&shm_lock);
+	init_waitqueue_head(&shm_wait);
 #ifdef CONFIG_PROC_FS
 	ent = create_proc_entry("sysvipc/shm", 0, 0);
 	ent->read_proc = sysvipc_shm_read_proc;
@@ -75,8 +78,21 @@
 	struct shmid_kernel *shp;
 
 	for (id = 0; id <= max_shmid; id++) {
-		while ((shp = shm_segs[id]) == IPC_NOID)
-			sleep_on (&shm_lock);
+		if ((shp = shm_segs[id]) == IPC_NOID) {
+			DECLARE_WAITQUEUE(wait, current);
+
+			add_wait_queue(&shm_wait, &wait);
+			for(;;) {
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				if ((shp = shm_segs[id]) != IPC_NOID)
+					break;
+				spin_unlock(&shm_lock);
+				schedule();
+				spin_lock(&shm_lock);
+			}
+			__set_current_state(TASK_RUNNING);
+			remove_wait_queue(&shm_wait, &wait);
+		}
 		if (shp == IPC_UNUSED)
 			continue;
 		if (key == shp->u.shm_perm.key)
@@ -106,28 +122,30 @@
 	return -ENOSPC;
 
 found:
+	spin_unlock(&shm_lock);
 	shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_KERNEL);
 	if (!shp) {
+		spin_lock(&shm_lock);
 		shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
-		wake_up (&shm_lock);
+		wake_up (&shm_wait);
 		return -ENOMEM;
 	}
-
+	lock_kernel();
 	shp->shm_pages = (ulong *) vmalloc (numpages*sizeof(ulong));
+	unlock_kernel();
 	if (!shp->shm_pages) {
-		shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
-		wake_up (&shm_lock);
 		kfree(shp);
+		spin_lock(&shm_lock);
+		shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
+		wake_up (&shm_wait);
 		return -ENOMEM;
 	}
 
 	for (i = 0; i < numpages; shp->shm_pages[i++] = 0);
-	shm_tot += numpages;
 	shp->u.shm_perm.key = key;
 	shp->u.shm_perm.mode = (shmflg & S_IRWXUGO);
 	shp->u.shm_perm.cuid = shp->u.shm_perm.uid = current->euid;
 	shp->u.shm_perm.cgid = shp->u.shm_perm.gid = current->egid;
-	shp->u.shm_perm.seq = shm_seq;
 	shp->u.shm_segsz = size;
 	shp->u.shm_cpid = current->pid;
 	shp->attaches = NULL;
@@ -136,11 +154,16 @@
 	shp->u.shm_ctime = CURRENT_TIME;
 	shp->shm_npages = numpages;
 
+	spin_lock(&shm_lock);
+
+	shm_tot += numpages;
+	shp->u.shm_perm.seq = shm_seq;
+
 	if (id > max_shmid)
 		max_shmid = id;
 	shm_segs[id] = shp;
 	used_segs++;
-	wake_up (&shm_lock);
+	wake_up (&shm_wait);
 	return (unsigned int) shp->u.shm_perm.seq * SHMMNI + id;
 }
 
@@ -152,7 +175,7 @@
 	int err, id = 0;
 
 	down(&current->mm->mmap_sem);
-	lock_kernel();
+	spin_lock(&shm_lock);
 	if (size < 0 || size > shmmax) {
 		err = -EINVAL;
 	} else if (key == IPC_PRIVATE) {
@@ -175,7 +198,7 @@
 		else
 			err = (int) shp->u.shm_perm.seq * SHMMNI + id;
 	}
-	unlock_kernel();
+	spin_unlock(&shm_lock);
 	up(&current->mm->mmap_sem);
 	return err;
 }
@@ -188,6 +211,7 @@
 {
 	struct shmid_kernel *shp;
 	int i, numpages;
+	int rss, swp;
 
 	shp = shm_segs[id];
 	if (shp == IPC_NOID || shp == IPC_UNUSED) {
@@ -204,23 +228,31 @@
 		printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id);
 		return;
 	}
+	spin_unlock(&shm_lock);
 	numpages = shp->shm_npages;
-	for (i = 0; i < numpages ; i++) {
+	for (i = 0, rss = 0, swp = 0; i < numpages ; i++) {
 		pte_t pte;
 		pte = __pte(shp->shm_pages[i]);
 		if (pte_none(pte))
 			continue;
 		if (pte_present(pte)) {
 			free_page (pte_page(pte));
-			shm_rss--;
+			rss++;
 		} else {
+			lock_kernel();
 			swap_free(pte_val(pte));
-			shm_swp--;
+			unlock_kernel();
+			swp++;
 		}
 	}
+	lock_kernel();
 	vfree(shp->shm_pages);
-	shm_tot -= numpages;
+	unlock_kernel();
 	kfree(shp);
+	spin_lock(&shm_lock);
+	shm_rss -= rss;
+	shm_swp -= swp;
+	shm_tot -= numpages;
 	return;
 }
 
@@ -231,14 +263,14 @@
 	struct ipc_perm *ipcp;
 	int id, err = -EINVAL;
 
-	lock_kernel();
 	if (cmd < 0 || shmid < 0)
-		goto out;
+		goto out_unlocked;
 	if (cmd == IPC_SET) {
 		err = -EFAULT;
 		if(copy_from_user (&tbuf, buf, sizeof (*buf)))
-			goto out;
+			goto out_unlocked;
 	}
+	spin_lock(&shm_lock);
 
 	switch (cmd) { /* replace with proc interface ? */
 	case IPC_INFO:
@@ -252,8 +284,10 @@
 		shminfo.shmmin = SHMMIN;
 		shminfo.shmall = SHMALL;
 		shminfo.shmseg = SHMSEG;
+		spin_unlock(&shm_lock);
 		if(copy_to_user (buf, &shminfo, sizeof(struct shminfo)))
-			goto out;
+			goto out_unlocked;
+		spin_lock(&shm_lock);
 		err = max_shmid;
 		goto out;
 	}
@@ -267,8 +301,10 @@
 		shm_info.shm_swp = shm_swp;
 		shm_info.swap_attempts = swap_attempts;
 		shm_info.swap_successes = swap_successes;
+		spin_unlock(&shm_lock);
 		if(copy_to_user (buf, &shm_info, sizeof(shm_info)))
-			goto out;
+			goto out_unlocked;
+		spin_lock(&shm_lock);
 		err = max_shmid;
 		goto out;
 	}
@@ -283,8 +319,10 @@
 			goto out;
 		id = (unsigned int) shp->u.shm_perm.seq * SHMMNI + shmid;
 		err = -EFAULT;
+		spin_unlock(&shm_lock);
 		if(copy_to_user (buf, &shp->u, sizeof(*buf)))
-			goto out;
+			goto out_unlocked;
+		spin_lock(&shm_lock);
 		err = id;
 		goto out;
 	}
@@ -325,8 +363,10 @@
 		if (ipcperms (ipcp, S_IRUGO))
 			goto out;
 		err = -EFAULT;
+		spin_unlock(&shm_lock);
 		if(copy_to_user (buf, &shp->u, sizeof(shp->u)))
-			goto out;
+			goto out_unlocked;
+		spin_lock(&shm_lock);
 		break;
 	case IPC_SET:
 		if (current->euid == shp->u.shm_perm.uid ||
@@ -358,7 +398,8 @@
 	}
 	err = 0;
 out:
-	unlock_kernel();
+	spin_unlock(&shm_lock);
+out_unlocked:
 	return err;
 }
 
@@ -440,7 +481,7 @@
 	unsigned long len;
 
 	down(&current->mm->mmap_sem);
-	lock_kernel();
+	spin_lock(&shm_lock);
 	if (shmid < 0) {
 		/* printk("shmat() -> EINVAL because shmid = %d < 0\n",shmid); */
 		goto out;
@@ -501,8 +542,10 @@
 	if (shp->u.shm_perm.seq != (unsigned int) shmid / SHMMNI)
 		goto out;
 
+	spin_unlock(&shm_lock);
 	err = -ENOMEM;
 	shmd = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	spin_lock(&shm_lock);
 	if (!shmd)
 		goto out;
 	if ((shp != shm_segs[id]) || (shp->u.shm_perm.seq != (unsigned int) shmid / SHMMNI)) {
@@ -524,12 +567,11 @@
 	shmd->vm_ops = &shm_vm_ops;
 
 	shp->u.shm_nattch++;            /* prevent destruction */
-	if ((err = shm_map (shmd))) {
-		if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST)
-			killseg(id);
-		kmem_cache_free(vm_area_cachep, shmd);
-		goto out;
-	}
+	spin_unlock(&shm_lock);
+	err = shm_map (shmd);
+	spin_lock(&shm_lock);
+	if (err)
+		goto failed_shm_map;
 
 	insert_attach(shp,shmd);  /* insert shmd into shp->attaches */
 
@@ -539,8 +581,16 @@
 	*raddr = addr;
 	err = 0;
 out:
-	unlock_kernel();
+	spin_unlock(&shm_lock);
+	up(&current->mm->mmap_sem);
+	return err;
+
+failed_shm_map:
+	if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST)
+		killseg(id);
+	spin_unlock(&shm_lock);
 	up(&current->mm->mmap_sem);
+	kmem_cache_free(vm_area_cachep, shmd);
 	return err;
 }
 
@@ -549,13 +599,13 @@
 {
 	struct shmid_kernel *shp;
 
-	lock_kernel();
+	spin_lock(&shm_lock);
 	shp = *(struct shmid_kernel **) shmd->vm_private_data;
 	insert_attach(shp,shmd);  /* insert shmd into shp->attaches */
 	shp->u.shm_nattch++;
 	shp->u.shm_atime = CURRENT_TIME;
 	shp->u.shm_lpid = current->pid;
-	unlock_kernel();
+	spin_unlock(&shm_lock);
 }
 
 /*
@@ -568,7 +618,7 @@
 {
 	struct shmid_kernel *shp;
 
-	lock_kernel();
+	spin_lock(&shm_lock);
 	/* remove from the list of attaches of the shm segment */
 	shp = *(struct shmid_kernel **) shmd->vm_private_data;
 	remove_attach(shp,shmd);  /* remove from shp->attaches */
@@ -578,7 +628,7 @@
 		unsigned int id = (struct shmid_kernel **)shmd->vm_private_data - shm_segs;
 		killseg (id);
 	}
-	unlock_kernel();
+	spin_unlock(&shm_lock);
 }
 
 /*
@@ -590,14 +640,12 @@
 	struct vm_area_struct *shmd, *shmdnext;
 
 	down(&current->mm->mmap_sem);
-	lock_kernel();
 	for (shmd = current->mm->mmap; shmd; shmd = shmdnext) {
 		shmdnext = shmd->vm_next;
 		if (shmd->vm_ops == &shm_vm_ops
 		    && shmd->vm_start - shmd->vm_offset == (ulong) shmaddr)
 			do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
 	}
-	unlock_kernel();
 	up(&current->mm->mmap_sem);
 	return 0;
 }
@@ -640,36 +688,43 @@
 	}
 #endif
 
-	lock_kernel();
+	spin_lock(&shm_lock);
  again:
 	pte = __pte(shp->shm_pages[idx]);
 	if (!pte_present(pte)) {
 		if (pte_none(pte)) {
+			spin_unlock(&shm_lock);
 			page = __get_free_page(GFP_BIGUSER);
 			if (!page)
 				goto oom;
 			clear_bigpage(page);
+			spin_lock(&shm_lock);
 			if (pte_val(pte) != shp->shm_pages[idx])
 				goto changed;
 		} else {
 			unsigned long entry = pte_val(pte);
 
+			spin_unlock(&shm_lock);
 			page_map = lookup_swap_cache(entry);
 			if (!page_map) {
+				lock_kernel();
 				swapin_readahead(entry);
 				page_map = read_swap_cache(entry);
+				unlock_kernel();
+				if (!page_map)
+					goto oom;
 			}
-			pte = __pte(shp->shm_pages[idx]);
-			page = page_address(page_map);
-			if (pte_present(pte))
-				goto present;
-			if (!page_map)
-				goto oom;
 			delete_from_swap_cache(page_map);
 			page_map = replace_with_bigmem(page_map);
 			page = page_address(page_map);
+			lock_kernel();
 			swap_free(entry);
+			unlock_kernel();
+			spin_lock(&shm_lock);
 			shm_swp--;
+			pte = __pte(shp->shm_pages[idx]);
+			if (pte_present(pte))
+				goto present;
 		}
 		shm_rss++;
 		pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
@@ -679,7 +734,7 @@
 
 done:	/* pte_val(pte) == shp->shm_pages[idx] */
 	get_page(mem_map + MAP_NR(pte_page(pte)));
-	unlock_kernel();
+	spin_unlock(&shm_lock);
 	current->min_flt++;
 	return pte_page(pte);
 
@@ -687,11 +742,9 @@
 	free_page(page);
 	goto again;
 present:
-	if (page_map)
-		free_page_and_swap_cache(page);
+	free_page(page);
 	goto done;
 oom:
-	unlock_kernel();
 	return -1;
 }
 
@@ -710,17 +763,20 @@
 	int loop = 0;
 	int counter;
 	struct page * page_map;
-	int ret = 0;
 	
-	lock_kernel();
 	counter = shm_rss >> prio;
-	if (!counter || !(swap_nr = get_swap_page()))
-		goto out_unlock;
+	lock_kernel();
+	if (!counter || !(swap_nr = get_swap_page())) {
+		unlock_kernel();
+		return 0;
+	}
+	unlock_kernel();
 
+	spin_lock(&shm_lock);
  check_id:
 	shp = shm_segs[swap_id];
 	if (shp == IPC_UNUSED || shp == IPC_NOID || shp->u.shm_perm.mode & SHM_LOCKED ) {
-		next_id:
+ next_id:
 		swap_idx = 0;
 		if (++swap_id > max_shmid) {
 			swap_id = 0;
@@ -748,27 +804,30 @@
 	swap_attempts++;
 
 	if (--counter < 0) { /* failed */
-		failed:
+ failed:
+		spin_unlock(&shm_lock);
+		lock_kernel();
 		swap_free (swap_nr);
-		goto out_unlock;
+		unlock_kernel();
+		return 0;
 	}
 	if (page_count(mem_map + MAP_NR(pte_page(page))) != 1)
 		goto check_table;
 	if (!(page_map = prepare_bigmem_swapout(page_map)))
 		goto check_table;
 	shp->shm_pages[idx] = swap_nr;
+	swap_successes++;
+	shm_swp++;
+	shm_rss--;
+	spin_unlock(&shm_lock);
+	lock_kernel();
 	swap_duplicate(swap_nr);
 	add_to_swap_cache(page_map, swap_nr);
 	rw_swap_page(WRITE, page_map, 0);
+	unlock_kernel();
 
 	__free_page(page_map);
-	swap_successes++;
-	shm_swp++;
-	shm_rss--;
-	ret = 1;
- out_unlock:
-	unlock_kernel();
-	return ret;
+	return 1;
 }
 
 /*
@@ -784,8 +843,12 @@
 	get_page(mem_map + MAP_NR(page));
 	shm_rss++;
 
-	swap_free(entry);
 	shm_swp--;
+	spin_unlock(&shm_lock);
+
+	lock_kernel();
+	swap_free(entry);
+	unlock_kernel();
 }
 
 /*
@@ -795,6 +858,7 @@
 {
 	int i, n;
 
+	spin_lock(&shm_lock);
 	for (i = 0; i < SHMMNI; i++)
 		if (shm_segs[i] != IPC_UNUSED && shm_segs[i] != IPC_NOID)
 			for (n = 0; n < shm_segs[i]->shm_npages; n++)
@@ -804,6 +868,7 @@
 						       page, entry);
 					return;
 				}
+	spin_unlock(&shm_lock);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -815,6 +880,7 @@
 
     	len += sprintf(buffer, "       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime\n");
 
+	spin_lock(&shm_lock);
     	for(i = 0; i < SHMMNI; i++)
 		if(shm_segs[i] != IPC_UNUSED) {
 	    		len += sprintf(buffer + len, "%10d %10d  %4o %10d %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu\n",
@@ -849,6 +915,7 @@
 		len = length;
 	if(len < 0)
 		len = 0;
+	spin_unlock(&shm_lock);
 	return len;
 }
 #endif
diff -u --recursive --new-file v2.3.19/linux/kernel/sys.c linux/kernel/sys.c
--- v2.3.19/linux/kernel/sys.c	Tue Sep  7 12:14:07 1999
+++ linux/kernel/sys.c	Thu Oct  7 10:17:09 1999
@@ -997,6 +997,17 @@
 		case PR_GET_PDEATHSIG:
 			error = put_user(current->pdeath_signal, (int *)arg2);
 			break;
+		case PR_GET_DUMPABLE:
+			if (current->dumpable)
+				error = 1;
+			break;
+		case PR_SET_DUMPABLE:
+			if (arg2 != 0 && arg2 != 1) {
+				error = -EINVAL;
+				break;
+			}
+			current->dumpable = arg2;
+			break;
 		default:
 			error = -EINVAL;
 			break;
diff -u --recursive --new-file v2.3.19/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.3.19/linux/kernel/sysctl.c	Tue Aug 31 17:29:15 1999
+++ linux/kernel/sysctl.c	Thu Oct  7 12:47:37 1999
@@ -256,8 +256,6 @@
 	 0444, NULL, &proc_dointvec},
 	{FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
 	 0444, NULL, &proc_dointvec},
-	{FS_MAXINODE, "inode-max", &max_inodes, sizeof(int),
-	 0644, NULL, &proc_dointvec},
 	{FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
 	 0444, NULL, &proc_dointvec},
 	{FS_MAXFILE, "file-max", &max_files, sizeof(int),
diff -u --recursive --new-file v2.3.19/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.19/linux/mm/filemap.c	Tue Sep  7 12:14:07 1999
+++ linux/mm/filemap.c	Thu Oct  7 10:17:09 1999
@@ -127,7 +127,7 @@
 			goto repeat;
 		}
 		if (page_count(page) != 2)
-			printk("hm, busy page invalidated? (not necesserily a bug)\n");
+			printk("hm, busy page invalidated? (not necessarily a bug)\n");
 		lru_cache_del(page);
 
 		remove_page_from_inode_queue(page);
diff -u --recursive --new-file v2.3.19/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.3.19/linux/mm/vmscan.c	Tue Aug 31 17:29:15 1999
+++ linux/mm/vmscan.c	Thu Oct  7 12:47:37 1999
@@ -424,6 +424,14 @@
 				goto done;
 		}
 
+		/* don't be too light against the d/i cache since
+		   shrink_mmap() almost never fail when there's
+		   really plenty of memory free. */
+		count -= shrink_dcache_memory(priority, gfp_mask);
+		count -= shrink_icache_memory(priority, gfp_mask);
+		if (count <= 0)
+			goto done;
+
 		/* Try to get rid of some shared memory pages.. */
 		if (gfp_mask & __GFP_IO) {
 			while (shm_swap(priority, gfp_mask)) {
@@ -437,8 +445,6 @@
 			if (!--count)
 				goto done;
 		}
-
-		shrink_dcache_memory(priority, gfp_mask);
 	} while (--priority >= 0);
 done:
 
diff -u --recursive --new-file v2.3.19/linux/net/802/fc.c linux/net/802/fc.c
--- v2.3.19/linux/net/802/fc.c	Thu Aug 26 13:05:42 1999
+++ linux/net/802/fc.c	Thu Oct  7 10:17:09 1999
@@ -88,7 +88,10 @@
 		printk("fc_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(fcllc->ethertype));
 		return 0;
 	}
-
+#ifdef CONFIG_INET
 	return arp_find(fch->daddr, skb);
+#else
+	return 0;
+#endif
 }
 	
diff -u --recursive --new-file v2.3.19/linux/net/core/netfilter.c linux/net/core/netfilter.c
--- v2.3.19/linux/net/core/netfilter.c	Fri Sep 10 23:57:38 1999
+++ linux/net/core/netfilter.c	Thu Oct  7 10:51:42 1999
@@ -310,9 +310,6 @@
 	struct list_head *i;
 	int ret;
 
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
 	if (down_interruptible(&nf_sockopt_mutex) != 0)
 		return -EINTR;
 
diff -u --recursive --new-file v2.3.19/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- v2.3.19/linux/net/sunrpc/xprt.c	Sat Jul  3 10:45:04 1999
+++ linux/net/sunrpc/xprt.c	Thu Oct  7 10:17:09 1999
@@ -789,11 +789,29 @@
 	return result;
 }
 
+static __inline__ void tcp_output_record(struct rpc_xprt *xprt)
+{
+	if(xprt->snd_sent && xprt->snd_task)
+		dprintk("RPC: write space\n");
+	if(xprt->write_space == 0)
+	{
+		xprt->write_space = 1;
+		if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
+		{
+			if(xprt->snd_sent)
+				dprintk("RPC: Write wakeup snd_sent =%d\n",
+					xprt->snd_sent);
+			rpc_wake_up_task(xprt->snd_task);			
+		}
+	}
+}
+
 /*
  *	TCP task queue stuff
  */
  
-static struct rpc_xprt *rpc_xprt_pending = NULL;	/* Chain by rx_pending of rpc_xprt's */
+static struct rpc_xprt *rpc_rx_xprt_pending = NULL;	/* Chain by rx_pending of rpc_xprt's */
+static struct rpc_xprt *rpc_tx_xprt_pending = NULL;	/* Chain by tx_pending of rpc_xprt's */
 
 /*
  *	This is protected from tcp_data_ready and the stack as its run
@@ -811,11 +829,11 @@
 	 *	Empty each pending socket
 	 */
 	 
-	while((xprt=rpc_xprt_pending)!=NULL)
+	while((xprt=rpc_rx_xprt_pending)!=NULL)
 	{
 		int safe_retry=0;
 		
-		rpc_xprt_pending=xprt->rx_pending;
+		rpc_rx_xprt_pending=xprt->rx_pending;
 		xprt->rx_pending_flag=0;
 		
 		dprintk("rpciod_tcp_dispatcher: Processing %p\n", xprt);
@@ -840,6 +858,13 @@
 					result);
 		}
 	}
+
+	while((xprt=rpc_tx_xprt_pending)!=NULL)
+	{
+		rpc_tx_xprt_pending = xprt->tx_pending;
+		xprt->tx_pending_flag = 0;
+		tcp_output_record(xprt);
+	}
 }
 
 
@@ -877,12 +902,12 @@
 	{
 		int start_queue=0;
 
-		dprintk("RPC:     xprt queue %p\n", rpc_xprt_pending);
-		if(rpc_xprt_pending==NULL)
+		dprintk("RPC:     xprt queue %p\n", rpc_rx_xprt_pending);
+		if(rpc_rx_xprt_pending==NULL)
 			start_queue=1;
 		xprt->rx_pending_flag=1;
-		xprt->rx_pending=rpc_xprt_pending;
-		rpc_xprt_pending=xprt;
+		xprt->rx_pending=rpc_rx_xprt_pending;
+		rpc_rx_xprt_pending=xprt;
 		if (start_queue)
 		  {
 		    tcp_rpciod_queue();
@@ -924,18 +949,16 @@
 
 	if (!(xprt = xprt_from_sock(sk)))
 		return;
-	if(xprt->snd_sent && xprt->snd_task)
-		dprintk("RPC: write space\n");
-	if(xprt->write_space == 0)
-	{
-		xprt->write_space = 1;
-		if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
-		{
-			if(xprt->snd_sent)
-				dprintk("RPC: Write wakeup snd_sent =%d\n",
-					xprt->snd_sent);
-			rpc_wake_up_task(xprt->snd_task);			
-		}
+	if (!xprt->tx_pending_flag) {
+		int start_queue = 0;
+
+		if (rpc_tx_xprt_pending == NULL)
+			start_queue = 1;
+		xprt->tx_pending_flag = 1;
+		xprt->tx_pending = rpc_tx_xprt_pending;
+		rpc_tx_xprt_pending = xprt;
+		if (start_queue)
+			tcp_rpciod_queue();
 	}
 }
 
